Passed
Push — master ( d2779f...9acd42 )
by Edward
06:48
created

TokenReader::getIterator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 2
nc 2
nop 0
crap 6
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\Lexer\Runtime\Token;
6
7
use Iterator;
8
use IteratorAggregate;
9
use Remorhaz\Lexer\Runtime\IO\EmptyLexeme;
10
use Remorhaz\Lexer\Runtime\IO\LexemeInterface;
11
use Remorhaz\Lexer\Runtime\IO\PreviewBufferInterface;
12
13
use function array_merge;
14
15
final class TokenReader implements IteratorAggregate, TokenReaderInterface
16
{
17
18
    /**
19
     * @var PreviewBufferInterface
20
     */
21
    private $previewBuffer;
22
23
    /**
24
     * @var MatcherSelectorInterface
25
     */
26
    private $matcherSelector;
27
28
    /**
29
     * @var int
30
     */
31
    private $offset = 0;
32
33
    /**
34
     * @var bool
35
     */
36
    private $isFinished = false;
37
38
    public function __construct(PreviewBufferInterface $previewBuffer, MatcherSelectorInterface $tokenContext)
39
    {
40
        $this->previewBuffer = $previewBuffer;
41
        $this->matcherSelector = $tokenContext;
42
    }
43
44
    /**
45
     * @return bool
46
     * @psalm-pure
47
     */
48
    public function isFinished(): bool
49
    {
50
        return $this->isFinished;
51
    }
52
53
    /**
54
     * @return int
55
     * @psalm-pure
56
     */
57
    public function getOffset(): int
58
    {
59
        return $this->offset;
60
    }
61
62
    /**
63
     * @return TokenInterface
64
     */
65
    public function read(): TokenInterface
66
    {
67
        if ($this->isFinished) {
68
            throw new Exception\UnexpectedEndOfInputException(
69
                array_merge(
70
                    [$this->offset],
71
                    $this->previewBuffer->getEmptyLexeme()->getStartOffsets()
72
                )
73
            );
74
        }
75
76
        if ($this->previewBuffer->isFinished()) {
77
            $this->isFinished = true;
78
            $matcher = $this->matcherSelector->getMatcher();
79
80
            return $matcher->createFinishToken($this->offset, $this->previewBuffer);
81
        }
82
83
        do {
84
            $matcher = $this->matcherSelector->getMatcher();
85
            $matchResult = $matcher->match($this->offset, $this->previewBuffer, $this->matcherSelector);
86
        } while ($matchResult->shouldRepeat());
87
        $this->offset++;
88
89
        return $matchResult->getToken();
90
    }
91
92
    /**
93
     * @return LexemeInterface
94
     * @psalm-pure
95
     */
96
    public function getEmptyLexeme(): LexemeInterface
97
    {
98
        return new EmptyLexeme($this->offset, $this->previewBuffer->getEmptyLexeme());
99
    }
100
101
    /**
102
     * @return Iterator
103
     * @psalm-return Iterator<int,TokenInterface>
104
     */
105
    public function getIterator(): Iterator
106
    {
107
        while (!$this->isFinished()) {
108
            yield $this->getOffset() => $this->read();
109
        }
110
    }
111
}
112