Passed
Branch feature/first-release (4212f2)
by Andrea Marco
10:46
created

Parser   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 73
Duplicated Lines 0 %

Test Coverage

Coverage 90%

Importance

Changes 10
Bugs 0 Features 0
Metric Value
eloc 19
c 10
b 0
f 0
dl 0
loc 73
ccs 18
cts 20
cp 0.9
rs 10
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A progress() 0 3 1
A for() 0 3 1
B getIterator() 0 25 7
A __construct() 0 3 1
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 decoder handling potential errors.
20
     *
21
     * @var ConfigurableDecoder
22
     */
23
    private ConfigurableDecoder $decoder;
24
25
    /**
26
     * Instantiate the class.
27
     *
28
     * @param Lexer $lexer
29
     * @param Config $config
30
     */
31 143
    public function __construct(private Lexer $lexer, private Config $config)
32
    {
33 143
        $this->decoder = new ConfigurableDecoder($config);
34
    }
35
36
    /**
37
     * Instantiate the class statically
38
     *
39
     * @param Source $source
40
     * @return self
41
     */
42 143
    public static function for(Source $source): self
43
    {
44 143
        return new self(new Lexer($source), $source->config());
45
    }
46
47
    /**
48
     * Retrieve the JSON fragments
49
     *
50
     * @return Traversable<string|int, mixed>
51
     */
52 131
    public function getIterator(): Traversable
53
    {
54 131
        $state = new State($this->config->pointers);
55
56 131
        foreach ($this->lexer as $token) {
57 127
            if (!$token->matches($state->expectedToken)) {
58 1
                throw new SyntaxException($token, $this->lexer->position());
59
            }
60
61 127
            $state->mutateByToken($token);
62
63 127
            if (!$token->endsChunk() || $state->tree()->isDeep()) {
64 127
                continue;
65
            }
66
67 125
            if ($state->hasBuffer()) {
68
                /** @var string|int $key */
69 93
                $key = $this->decoder->decode($state->key());
70 93
                $value = $this->decoder->decode($state->value());
71
72 92
                yield $key => $state->callPointer($value, $key);
73
            }
74
75 124
            if ($state->canStopParsing()) {
76 52
                break;
77
            }
78
        }
79
    }
80
81
    /**
82
     * Retrieve the parsing progress
83
     *
84
     * @return Progress
85
     */
86
    public function progress(): Progress
87
    {
88
        return $this->lexer->progress();
89
    }
90
}
91