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

Parser::getIterator()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 7
eloc 13
c 6
b 0
f 0
nc 7
nop 0
dl 0
loc 25
ccs 14
cts 14
cp 1
crap 7
rs 8.8333
1
<?php
2
3
namespace Cerbero\JsonParser;
4
5
use Cerbero\JsonParser\Decoders\ConfigurableDecoder;
6
use Cerbero\JsonParser\Exceptions\SyntaxException;
7
use Cerbero\JsonParser\Sources\Source;
8
use IteratorAggregate;
9
use Traversable;
10
11
/**
12
 * The JSON parser.
13
 *
14
 * @implements IteratorAggregate<string|int, mixed>
15
 */
16
final class Parser implements IteratorAggregate
17
{
18
    /**
19
     * The JSON parsing state.
20
     *
21
     * @var State
22
     */
23
    private State $state;
24
25
    /**
26
     * The decoder handling potential errors.
27
     *
28
     * @var ConfigurableDecoder
29
     */
30
    private ConfigurableDecoder $decoder;
31
32
    /**
33
     * Instantiate the class.
34
     *
35
     * @param Lexer $lexer
36
     * @param Config $config
37
     */
38 134
    public function __construct(private Lexer $lexer, private Config $config)
39
    {
40 134
        $this->state = new State();
41 134
        $this->decoder = new ConfigurableDecoder($config);
42
    }
43
44
    /**
45
     * Instantiate the class statically
46
     *
47
     * @param Source $source
48
     * @return static
49
     */
50 134
    public static function for(Source $source): static
51
    {
52 134
        return new static(new Lexer($source), $source->config());
53
    }
54
55
    /**
56
     * Retrieve the JSON fragments
57
     *
58
     * @return Traversable<string|int, mixed>
59
     */
60 130
    public function getIterator(): Traversable
61
    {
62 130
        $this->state->setPointers(...$this->config->pointers);
63
64 130
        foreach ($this->lexer as $token) {
65 126
            if (!$token->matches($this->state->expectedToken)) {
66 1
                throw new SyntaxException($token, $this->lexer->position());
67
            }
68
69 126
            $this->state->mutateByToken($token);
70
71 126
            if (!$token->endsChunk() || $this->state->treeIsDeep()) {
72 126
                continue;
73
            }
74
75 124
            if ($this->state->hasBuffer()) {
76
                /** @var string|int $key */
77 92
                $key = $this->decoder->decode($this->state->key());
78 92
                $value = $this->decoder->decode($this->state->value());
79
80 91
                yield $key => $this->state->callPointer($value, $key);
81
            }
82
83 123
            if ($this->state->canStopParsing()) {
84 51
                break;
85
            }
86
        }
87
    }
88
89
    /**
90
     * Retrieve the parsing progress
91
     *
92
     * @return Progress
93
     */
94
    public function progress(): Progress
95
    {
96
        return $this->lexer->progress();
97
    }
98
}
99