Passed
Branch feature/first-release (4f172a)
by Andrea Marco
01:55
created

Lexer::getIterator()   C

Complexity

Conditions 12
Paths 50

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 12
eloc 18
c 2
b 0
f 0
nc 50
nop 0
dl 0
loc 28
ccs 19
cts 19
cp 1
crap 12
rs 6.9666

How to fix   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 Cerbero\JsonParser\Tokens;
4
5
use Cerbero\JsonParser\Exceptions\SyntaxException;
6
use Cerbero\JsonParser\Sources\Source;
7
use Cerbero\JsonParser\Tokens\Token;
8
use Cerbero\JsonParser\Tokens\Tokenizer;
9
use Cerbero\JsonParser\Tokens\Tokens;
10
use Cerbero\JsonParser\ValueObjects\Progress;
11
use IteratorAggregate;
12
use Traversable;
13
14
use function strlen;
15
16
/**
17
 * The JSON lexer.
18
 *
19
 * @implements IteratorAggregate<int, Token>
20
 */
21
final class Lexer implements IteratorAggregate
22
{
23
    /**
24
     * The parsing progress.
25
     *
26
     * @var Progress
27
     */
28
    private Progress $progress;
29
30
    /**
31
     * The current position.
32
     *
33
     * @var int
34
     */
35
    private int $position = 1;
36
37
    /**
38
     * Instantiate the class.
39
     *
40
     * @param Source $source
41
     */
42 342
    public function __construct(private Source $source)
43
    {
44 342
        $this->progress = new Progress();
45
    }
46
47
    /**
48
     * Retrieve the JSON fragments
49
     *
50
     * @return \Generator<int, Token>
51
     */
52 330
    public function getIterator(): Traversable
53
    {
54 330
        $buffer = '';
55 330
        $inString = $isEscaping = false;
56
57 330
        foreach ($this->source as $chunk) {
58 327
            for ($i = 0, $size = strlen($chunk); $i < $size; $i++, $this->position++) {
59 327
                $character = $chunk[$i];
60 327
                $inString = ($character == '"') != $inString || $isEscaping;
61 327
                $isEscaping = $character == '\\' && !$isEscaping;
62 327
                $shouldBuffer = $inString || !isset(Tokens::BOUNDARIES[$character]);
63
64 327
                if ($shouldBuffer && $buffer == '' && !isset(Tokens::TYPES[$character])) {
65 10
                    throw new SyntaxException($character);
66
                }
67
68 326
                if ($shouldBuffer) {
69 274
                    $buffer .= $character;
70 274
                    continue;
71
                }
72
73 326
                if ($buffer != '') {
74 274
                    yield Tokenizer::instance()->toToken($buffer);
75 270
                    $buffer = '';
76
                }
77
78 326
                if (isset(Tokens::DELIMITERS[$character])) {
79 326
                    yield Tokenizer::instance()->toToken($character);
80
                }
81
            }
82
        }
83
    }
84
85
    /**
86
     * Retrieve the current position
87
     *
88
     * @return int
89
     */
90 11
    public function position(): int
91
    {
92 11
        return $this->position;
93
    }
94
95
    /**
96
     * Retrieve the parsing progress
97
     *
98
     * @return Progress
99
     */
100
    public function progress(): Progress
101
    {
102
        return $this->progress->setCurrent($this->position)->setTotal($this->source->size());
103
    }
104
}
105