Passed
Pull Request — master (#196)
by Christoffer
02:26
created

Lexer::lexNumber()   C

Complexity

Conditions 10
Paths 26

Size

Total Lines 53
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
rs 6.5333
c 0
b 0
f 0
cc 10
eloc 31
nc 26
nop 4

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Digia\GraphQL\Language;
4
5
use Digia\GraphQL\Error\LanguageException;
6
use Digia\GraphQL\Error\SyntaxErrorException;
7
8
class Lexer implements LexerInterface
9
{
10
    /**
11
     * TODO: Document this
12
     *
13
     * @var Source|null
14
     */
15
    protected $source;
16
17
    /**
18
     * TODO: Document this
19
     *
20
     * @var string|null
21
     */
22
    protected $body;
23
24
    /**
25
     * TODO: Document this
26
     *
27
     * @var int
28
     */
29
    protected $bodyLength;
30
31
    /**
32
     * @var array
33
     */
34
    protected $options = [];
35
36
    /**
37
     * The previously focused non-ignored token.
38
     *
39
     * @var Token
40
     */
41
    protected $lastToken;
42
43
    /**
44
     * The currently focused non-ignored token.
45
     *
46
     * @var Token
47
     */
48
    protected $token;
49
50
    /**
51
     * TODO: Document this
52
     *
53
     * @var int
54
     */
55
    protected $pos;
56
57
    /**
58
     * The (1-indexed) line containing the current token.
59
     *
60
     * @var int
61
     */
62
    protected $line;
63
64
    /**
65
     * The character offset at which the current line begins.
66
     *
67
     * @var int
68
     */
69
    protected $lineStart;
70
71
    /**
72
     * Lexer constructor.
73
     *
74
     * @param TokenReaderInterface $reader
75
     */
76
    public function __construct()
77
    {
78
        $startOfFileToken = new Token(TokenKindEnum::SOF);
79
80
        $this->lastToken = $startOfFileToken;
81
        $this->token     = $startOfFileToken;
82
        $this->line      = 1;
83
        $this->lineStart = 0;
84
    }
85
86
    /**
87
     * @inheritdoc
88
     * @throws SyntaxErrorException
89
     */
90
    public function advance(): Token
91
    {
92
        $this->lastToken = $this->token;
93
        return $this->token = $this->lookahead();
94
    }
95
96
    /**
97
     * @inheritdoc
98
     * @throws SyntaxErrorException
99
     */
100
    public function lookahead(): Token
101
    {
102
        $token = $this->token;
103
104
        if (TokenKindEnum::EOF !== $token->getKind()) {
105
            do {
106
                $next = $this->readToken($token);
107
                $token->setNext($next);
108
                $token = $next;
109
            } while (TokenKindEnum::COMMENT === $token->getKind());
110
        }
111
112
        return $token;
113
    }
114
115
    /**
116
     * @inheritdoc
117
     */
118
    public function getOption(string $name, $default = null)
119
    {
120
        return $this->options[$name] ?? $default;
121
    }
122
123
    /**
124
     * @inheritdoc
125
     * @throws LanguageException
126
     */
127
    public function getBody(): string
128
    {
129
        return $this->getSource()->getBody();
130
    }
131
132
    /**
133
     * @inheritdoc
134
     */
135
    public function getTokenKind(): string
136
    {
137
        return $this->token->getKind();
138
    }
139
140
    /**
141
     * @inheritdoc
142
     */
143
    public function getTokenValue(): ?string
144
    {
145
        return $this->token->getValue();
146
    }
147
148
    /**
149
     * @inheritdoc
150
     */
151
    public function getToken(): Token
152
    {
153
        return $this->token;
154
    }
155
156
    /**
157
     * @inheritdoc
158
     * @throws LanguageException
159
     */
160
    public function getSource(): Source
161
    {
162
        if ($this->source instanceof Source) {
163
            return $this->source;
164
        }
165
166
        throw new LanguageException('No source has been set.');
167
    }
168
169
    /**
170
     * @inheritdoc
171
     */
172
    public function getLastToken(): Token
173
    {
174
        return $this->lastToken;
175
    }
176
177
    /**
178
     * @inheritdoc
179
     */
180
    public function setSource(Source $source)
181
    {
182
        $this->body       = $source->getBody();
183
        $this->bodyLength = \strlen($this->body);
184
        $this->source     = $source;
185
        return $this;
186
    }
187
188
    /**
189
     * @inheritdoc
190
     */
191
    public function setOptions(array $options)
192
    {
193
        $this->options = $options;
194
        return $this;
195
    }
196
197
    /**
198
     * @param Token $prev
199
     * @return Token
200
     * @throws SyntaxErrorException
201
     */
202
    protected function readToken(Token $prev): Token
203
    {
204
        $this->pos = $prev->getEnd();
205
206
        $this->skipWhitespace();
207
208
        $line = $this->line;
209
        $col  = 1 + $this->pos - $this->lineStart;
210
211
        if ($this->pos >= $this->bodyLength) {
212
            return $this->createEndOfFileToken($line, $col, $prev);
213
        }
214
215
        $code = charCodeAt($this->body, $this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

215
        $code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, $this->pos);
Loading history...
216
217
        // Punctuation: [!$&:=@|()[]{}]{1}
218
        if (33 === $code || 36 === $code || 38 === $code || 58 === $code || 61 === $code || 64 === $code || 124 === $code ||
219
            40 === $code || 41 === $code || 91 === $code || 93 === $code || 123 === $code || 125 === $code) {
220
            return $this->lexPunctuation($code, $line, $col, $prev);
221
        }
222
223
        // Comment: #[\u0009\u0020-\uFFFF]*
224
        if (35 === $code) {
225
            return $this->lexComment($line, $col, $prev);
226
        }
227
228
        // Int:   -?(0|[1-9][0-9]*)
229
        // Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
230
        if ($code === 45 || isNumber($code)) {
231
            return $this->lexNumber($code, $line, $col, $prev);
232
        }
233
234
        // Name: [_A-Za-z][_0-9A-Za-z]*
235
        if (isAlphaNumeric($code)) {
236
            return $this->lexName($line, $col, $prev);
237
        }
238
239
        // Spread: ...
240
        if ($this->bodyLength >= 3 && isSpread($this->body, $code, $this->pos)) {
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $body of Digia\GraphQL\Language\isSpread() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

240
        if ($this->bodyLength >= 3 && isSpread(/** @scrutinizer ignore-type */ $this->body, $code, $this->pos)) {
Loading history...
241
            return $this->lexSpread($line, $col, $prev);
242
        }
243
244
        // String: "([^"\\\u000A\u000D]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*"
245
        if (isString($this->body, $code, $this->pos)) {
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $body of Digia\GraphQL\Language\isString() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

245
        if (isString(/** @scrutinizer ignore-type */ $this->body, $code, $this->pos)) {
Loading history...
246
            return $this->lexString($line, $col, $prev);
247
        }
248
249
        // Block String: """("?"?(\\"""|\\(?!=""")|[^"\\]))*"""
250
        if ($this->bodyLength >= 3 && isTripleQuote($this->body, $code, $this->pos)) {
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $body of Digia\GraphQL\Language\isTripleQuote() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

250
        if ($this->bodyLength >= 3 && isTripleQuote(/** @scrutinizer ignore-type */ $this->body, $code, $this->pos)) {
Loading history...
251
            return $this->lexBlockString($line, $col, $prev);
252
        }
253
254
        throw $this->createSyntaxErrorException();
255
    }
256
257
    /**
258
     * Creates an End Of File (EOF) token.
259
     *
260
     * @param int   $line
261
     * @param int   $col
262
     * @param Token $prev
263
     * @return Token
264
     */
265
    protected function createEndOfFileToken(int $line, int $col, Token $prev): Token
266
    {
267
        return new Token(TokenKindEnum::EOF, $this->bodyLength, $this->bodyLength, $line, $col, $prev);
268
    }
269
270
    /**
271
     * Reads a punctuation token from the source file.
272
     *
273
     * @param int   $code
274
     * @param int   $line
275
     * @param int   $col
276
     * @param Token $prev
277
     * @return Token
278
     * @throws SyntaxErrorException
279
     */
280
    protected function lexPunctuation(int $code, int $line, int $col, Token $prev): ?Token
281
    {
282
        switch ($code) {
283
            case 33: // !
284
                return new Token(TokenKindEnum::BANG, $this->pos, $this->pos + 1, $line, $col, $prev);
285
            case 36: // $
286
                return new Token(TokenKindEnum::DOLLAR, $this->pos, $this->pos + 1, $line, $col, $prev);
287
            case 38: // &
288
                return new Token(TokenKindEnum::AMP, $this->pos, $this->pos + 1, $line, $col, $prev);
289
            case 58: // :
290
                return new Token(TokenKindEnum::COLON, $this->pos, $this->pos + 1, $line, $col, $prev);
291
            case 61: // =
292
                return new Token(TokenKindEnum::EQUALS, $this->pos, $this->pos + 1, $line, $col, $prev);
293
            case 64: // @
294
                return new Token(TokenKindEnum::AT, $this->pos, $this->pos + 1, $line, $col, $prev);
295
            case 124: // |
296
                return new Token(TokenKindEnum::PIPE, $this->pos, $this->pos + 1, $line, $col, $prev);
297
            case 40: // (
298
                return new Token(TokenKindEnum::PAREN_L, $this->pos, $this->pos + 1, $line, $col, $prev);
299
            case 41: // )
300
                return new Token(TokenKindEnum::PAREN_R, $this->pos, $this->pos + 1, $line, $col, $prev);
301
            case 91: // [
302
                return new Token(TokenKindEnum::BRACKET_L, $this->pos, $this->pos + 1, $line, $col, $prev);
303
            case 93: // ]
304
                return new Token(TokenKindEnum::BRACKET_R, $this->pos, $this->pos + 1, $line, $col, $prev);
305
            case 123: // {
306
                return new Token(TokenKindEnum::BRACE_L, $this->pos, $this->pos + 1, $line, $col, $prev);
307
            case 125: // }
308
                return new Token(TokenKindEnum::BRACE_R, $this->pos, $this->pos + 1, $line, $col, $prev);
309
            default:
310
                throw $this->createSyntaxErrorException();
311
        }
312
    }
313
314
    /**
315
     * Reads a name token from the source file.
316
     *
317
     * @param int   $line
318
     * @param int   $col
319
     * @param Token $prev
320
     * @return Token
321
     */
322
    protected function lexName(int $line, int $col, Token $prev): Token
323
    {
324
        $start     = $this->pos;
325
        $this->pos = $start + 1;
326
327
        while ($this->pos !== $this->bodyLength &&
328
            ($code = charCodeAt($this->body, $this->pos)) !== null &&
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

328
            ($code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, $this->pos)) !== null &&
Loading history...
329
            isAlphaNumeric($code)) {
330
            ++$this->pos;
331
        }
332
333
        $value = sliceString($this->body, $start, $this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\sliceString() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

333
        $value = sliceString(/** @scrutinizer ignore-type */ $this->body, $start, $this->pos);
Loading history...
334
335
        return new Token(TokenKindEnum::NAME, $start, $this->pos, $line, $col, $prev, $value);
336
    }
337
338
    /**
339
     * Reads a number (int/float) token from the source file.
340
     *
341
     * @param int   $code
342
     * @param int   $line
343
     * @param int   $col
344
     * @param Token $prev
345
     * @return Token
346
     * @throws SyntaxErrorException
347
     */
348
    protected function lexNumber(int $code, int $line, int $col, Token $prev): Token
349
    {
350
        $start   = $this->pos;
351
        $isFloat = false;
352
353
        if (45 === $code) {
354
            // -
355
            $code = charCodeAt($this->body, ++$this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

355
            $code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, ++$this->pos);
Loading history...
356
        }
357
358
        if (48 === $code) {
359
            // 0
360
            $code = charCodeAt($this->body, ++$this->pos);
361
362
            if (isNumber($code)) {
363
                throw $this->createSyntaxErrorException(
364
                    \sprintf('Invalid number, unexpected digit after 0: %s.', printCharCode($code))
365
                );
366
            }
367
        } else {
368
            $this->skipDigits($code);
369
            $code = charCodeAt($this->body, $this->pos);
370
        }
371
372
        if (46 === $code) {
373
            // .
374
            $isFloat = true;
375
            $code    = charCodeAt($this->body, ++$this->pos);
376
            $this->skipDigits($code);
377
            $code = charCodeAt($this->body, $this->pos);
378
        }
379
380
        if (69 === $code || 101 === $code) {
381
            // e or E
382
            $isFloat = true;
383
            $code    = charCodeAt($this->body, ++$this->pos);
384
385
            if (43 === $code || 45 === $code) {
386
                // + or -
387
                $code = charCodeAt($this->body, ++$this->pos);
388
            }
389
390
            $this->skipDigits($code);
391
        }
392
393
        return new Token(
394
            $isFloat ? TokenKindEnum::FLOAT : TokenKindEnum::INT,
395
            $start,
396
            $this->pos,
397
            $line,
398
            $col,
399
            $prev,
400
            sliceString($this->body, $start, $this->pos)
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\sliceString() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

400
            sliceString(/** @scrutinizer ignore-type */ $this->body, $start, $this->pos)
Loading history...
401
        );
402
    }
403
404
    /**
405
     * Reads digits from the source file.
406
     *
407
     * @param int $code
408
     * @throws SyntaxErrorException
409
     */
410
    protected function skipDigits(int $code): void
411
    {
412
        if (isNumber($code)) {
413
            do {
414
                $code = charCodeAt($this->body, ++$this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

414
                $code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, ++$this->pos);
Loading history...
415
            } while (isNumber($code));
416
417
            return;
418
        }
419
420
        throw $this->createSyntaxErrorException(
421
            \sprintf('Invalid number, expected digit but got: %s.', printCharCode($code))
422
        );
423
    }
424
425
    /**
426
     * Reads a comment token from the source file.
427
     *
428
     * @param int   $line
429
     * @param int   $col
430
     * @param Token $prev
431
     * @return Token
432
     */
433
    protected function lexComment(int $line, int $col, Token $prev): Token
434
    {
435
        $start = $this->pos;
436
437
        do {
438
            $code = charCodeAt($this->body, ++$this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

438
            $code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, ++$this->pos);
Loading history...
439
        } while ($code !== null && ($code > 0x001f || $code === 0x0009)); // SourceCharacter but not LineTerminator
440
441
        return new Token(
442
            TokenKindEnum::COMMENT,
443
            $start,
444
            $this->pos,
445
            $line,
446
            $col,
447
            $prev,
448
            sliceString($this->body, $start + 1, $this->pos)
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\sliceString() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

448
            sliceString(/** @scrutinizer ignore-type */ $this->body, $start + 1, $this->pos)
Loading history...
449
        );
450
    }
451
452
    /**
453
     * Reads a spread token from the source.
454
     *
455
     * @param int   $line
456
     * @param int   $col
457
     * @param Token $prev
458
     * @return Token
459
     */
460
    protected function lexSpread(int $line, int $col, Token $prev): Token
461
    {
462
        return new Token(TokenKindEnum::SPREAD, $this->pos, $this->pos + 3, $line, $col, $prev);
463
    }
464
465
    /**
466
     * @param int   $line
467
     * @param int   $col
468
     * @param Token $prev
469
     * @return Token
470
     * @throws SyntaxErrorException
471
     */
472
    protected function lexString(int $line, int $col, Token $prev): Token
473
    {
474
        $start      = $this->pos;
475
        $chunkStart = ++$this->pos;
476
        $value      = '';
477
478
        while ($this->pos < $this->bodyLength &&
479
            ($code = charCodeAt($this->body, $this->pos)) !== null && !isLineTerminator($code)) {
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

479
            ($code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, $this->pos)) !== null && !isLineTerminator($code)) {
Loading history...
480
            // Closing Quote (")
481
            if (34 === $code) {
482
                $value .= sliceString($this->body, $chunkStart, $this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\sliceString() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

482
                $value .= sliceString(/** @scrutinizer ignore-type */ $this->body, $chunkStart, $this->pos);
Loading history...
483
                return new Token(TokenKindEnum::STRING, $start, $this->pos + 1, $line, $col, $prev, $value);
484
            }
485
486
            if (isSourceCharacter($code)) {
487
                throw $this->createSyntaxErrorException(
488
                    \sprintf('Invalid character within String: %s.', printCharCode($code))
489
                );
490
            }
491
492
            ++$this->pos;
493
494
            if (92 === $code) {
495
                // \
496
                $value .= sliceString($this->body, $chunkStart, $this->pos - 1);
497
498
                $code = charCodeAt($this->body, $this->pos);
499
500
                switch ($code) {
501
                    case 34: // "
502
                        $value .= '"';
503
                        break;
504
                    case 47: // /
505
                        $value .= '/';
506
                        break;
507
                    case 92: // \
508
                        $value .= '\\';
509
                        break;
510
                    case 98: // b
511
                        $value .= '\b';
512
                        break;
513
                    case 102: // f
514
                        $value .= '\f';
515
                        break;
516
                    case 110: // n
517
                        $value .= '\n';
518
                        break;
519
                    case 114: // r
520
                        $value .= '\r';
521
                        break;
522
                    case 116: // t
523
                        $value .= '\t';
524
                        break;
525
                    case 117: // u
526
                        $unicodeString = sliceString($this->body, $this->pos + 1, $this->pos + 5);
527
528
                        if (!\preg_match('/[0-9A-Fa-f]{4}/', $unicodeString)) {
529
                            throw $this->createSyntaxErrorException(
530
                                \sprintf('Invalid character escape sequence: \\u%s.', $unicodeString)
531
                            );
532
                        }
533
534
                        $value     .= '\\u' . $unicodeString;
535
                        $this->pos += 4;
536
537
                        break;
538
                    default:
539
                        throw $this->createSyntaxErrorException(
540
                            \sprintf('Invalid character escape sequence: \\%s.', \chr($code))
541
                        );
542
                }
543
544
                ++$this->pos;
545
546
                $chunkStart = $this->pos;
547
            }
548
        }
549
550
        throw $this->createSyntaxErrorException('Unterminated string.');
551
    }
552
553
    /**
554
     * @param int   $line
555
     * @param int   $col
556
     * @param Token $prev
557
     * @return Token
558
     * @throws SyntaxErrorException
559
     */
560
    protected function lexBlockString(int $line, int $col, Token $prev): Token
561
    {
562
        $start      = $this->pos;
563
        $this->pos  = $start + 3;
564
        $chunkStart = $this->pos;
565
        $rawValue   = '';
566
567
        while ($this->pos < $this->bodyLength && ($code = charCodeAt($this->body, $this->pos)) !== null) {
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

567
        while ($this->pos < $this->bodyLength && ($code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, $this->pos)) !== null) {
Loading history...
568
            // Closing Triple-Quote (""")
569
            if (isTripleQuote($this->body, $code, $this->pos)) {
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $body of Digia\GraphQL\Language\isTripleQuote() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

569
            if (isTripleQuote(/** @scrutinizer ignore-type */ $this->body, $code, $this->pos)) {
Loading history...
570
                $rawValue .= sliceString($this->body, $chunkStart, $this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\sliceString() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

570
                $rawValue .= sliceString(/** @scrutinizer ignore-type */ $this->body, $chunkStart, $this->pos);
Loading history...
571
                return new Token(
572
                    TokenKindEnum::BLOCK_STRING,
573
                    $start,
574
                    $this->pos + 3,
575
                    $line,
576
                    $col,
577
                    $prev,
578
                    blockStringValue($rawValue)
579
                );
580
            }
581
582
            if (isSourceCharacter($code) && !isLineTerminator($code)) {
583
                throw $this->createSyntaxErrorException(
584
                    \sprintf('Invalid character within String: %s.', printCharCode($code))
585
                );
586
            }
587
588
            if (isEscapedTripleQuote($this->body, $code, $this->pos)) {
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $body of Digia\GraphQL\Language\isEscapedTripleQuote() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

588
            if (isEscapedTripleQuote(/** @scrutinizer ignore-type */ $this->body, $code, $this->pos)) {
Loading history...
589
                $rawValue   .= sliceString($this->body, $chunkStart, $this->pos) . '"""';
590
                $this->pos  += 4;
591
                $chunkStart = $this->pos;
592
            } else {
593
                ++$this->pos;
594
            }
595
        }
596
597
        throw $this->createSyntaxErrorException('Unterminated string.');
598
    }
599
600
    /**
601
     * Creates a `SyntaxErrorException` for the current position in the source.
602
     *
603
     * @param null|string $description
604
     * @return SyntaxErrorException
605
     */
606
    protected function createSyntaxErrorException(?string $description = null): SyntaxErrorException
607
    {
608
        $code = charCodeAt($this->body, $this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

608
        $code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, $this->pos);
Loading history...
609
        return new SyntaxErrorException(
610
            $this->source,
0 ignored issues
show
Bug introduced by
It seems like $this->source can also be of type null; however, parameter $source of Digia\GraphQL\Error\Synt...xception::__construct() does only seem to accept Digia\GraphQL\Language\Source, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

610
            /** @scrutinizer ignore-type */ $this->source,
Loading history...
611
            $this->pos,
612
            $description ?? $this->unexpectedCharacterMessage($code)
613
        );
614
    }
615
616
    /**
617
     * Report a message that an unexpected character was encountered.
618
     *
619
     * @param int $code
620
     * @return string
621
     */
622
    protected function unexpectedCharacterMessage(int $code): string
623
    {
624
        if (isSourceCharacter($code) && !isLineTerminator($code)) {
625
            return \sprintf('Cannot contain the invalid character %s.', printCharCode($code));
626
        }
627
628
        if ($code === 39) {
629
            // '
630
            return 'Unexpected single quote character (\'), did you mean to use a double quote (")?';
631
        }
632
633
        return \sprintf('Cannot parse the unexpected character %s.', printCharCode($code));
634
    }
635
636
    /**
637
     *
638
     */
639
    protected function skipWhitespace(): void
640
    {
641
        while ($this->pos < $this->bodyLength) {
642
            $code = charCodeAt($this->body, $this->pos);
0 ignored issues
show
Bug introduced by
It seems like $this->body can also be of type null; however, parameter $string of Digia\GraphQL\Language\charCodeAt() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

642
            $code = charCodeAt(/** @scrutinizer ignore-type */ $this->body, $this->pos);
Loading history...
643
644
            if ($code === 9 || $code === 32 || $code === 44 || $code === 0xfeff) {
645
                // tab | space | comma | BOM
646
                ++$this->pos;
647
            } elseif ($code === 10) {
648
                // new line (\n)
649
                ++$this->pos;
650
                ++$this->line;
651
                $this->lineStart = $this->pos;
652
            } elseif ($code === 13) {
653
                // carriage return (\r)
654
                if (charCodeAt($this->body, $this->pos + 1) === 10) {
655
                    // carriage return and new line (\r\n)
656
                    $this->pos += 2;
657
                } else {
658
                    ++$this->pos;
659
                }
660
                ++$this->line;
661
                $this->lineStart = $this->pos;
662
            } else {
663
                break;
664
            }
665
        }
666
    }
667
}
668