Passed
Branch feature/first-release (43e0cc)
by Andrea Marco
10:48
created

Lexer::getIterator()   F

Complexity

Conditions 17
Paths 362

Size

Total Lines 30
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 17

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 17
eloc 20
c 5
b 0
f 0
nc 362
nop 0
dl 0
loc 30
ccs 21
cts 21
cp 1
crap 17
rs 2.3583

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