Passed
Push — master ( b4d53f...9f8f80 )
by Aleksei
11:38
created

Buffer::replay()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 3
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Stempler\Lexer;
6
7
/**
8
 * Creates local buffers over byte/token stream. Able to replay some tokens.
9
 *
10
 * @implements \IteratorAggregate<array-key, Byte|Token|null>
11
 */
12
final class Buffer implements \IteratorAggregate
13
{
14
    /** @var Byte[]|Token[] */
15
    private array $buffer = [];
16
17
    /** @var Byte[]|Token[] */
18
    private array $replay = [];
19
20 255
    public function __construct(
21
        /** @internal */
22
        private readonly \Generator $generator,
23
        private int $offset = 0,
24
    ) {
25 255
    }
26
27
    /**
28
     * Delegate generation to the nested generator and collect
29
     * generated token/char stream.
30
     *
31
     * @return \Generator<array-key, Byte|Token|null>
32
     */
33 248
    public function getIterator(): \Traversable
34
    {
35 248
        while ($n = $this->next()) {
36 247
            yield $n;
37
        }
38
    }
39
40 139
    public function getOffset(): int
41
    {
42 139
        return $this->offset;
43
    }
44
45 255
    public function next(): Byte|Token|null
46
    {
47 255
        if ($this->replay !== []) {
48 233
            $n = \array_shift($this->replay);
49
        } else {
50 255
            $n = $this->generator->current();
51 255
            if ($n === null) {
52 254
                return null;
53
            }
54 255
            $this->generator->next();
55 255
            $this->buffer[] = $n;
56
        }
57
58 255
        if ($n !== null && $n->offset !== null) {
59 255
            $this->offset = $n->offset;
60
        }
61
62 255
        return $n;
63
    }
64
65
    /**
66
     * Get all the string content until first token.
67
     */
68 15
    public function nextBytes(): string
69
    {
70 15
        $result = '';
71 15
        while ($n = $this->next()) {
72 15
            if ($n instanceof Byte) {
73 15
                $result .= $n->char;
74
            } else {
75
                break;
76
            }
77
        }
78
79 15
        return $result;
80
    }
81
82
    /**
83
     * Get next generator value without advancing the position.
84
     */
85 1
    public function lookahead(): Byte|Token|null
86
    {
87 1
        if ($this->replay !== []) {
88 1
            return $this->replay[0];
89
        }
90
91 1
        $n = $this->next();
92 1
        if ($n !== null) {
93 1
            \array_unshift($this->replay, $n);
94
        }
95
96 1
        return $n;
97
    }
98
99
    /**
100
     * Get next byte(s) value if any.
101
     *
102
     * @param int $size Size of lookup string.
103
     */
104 231
    public function lookaheadByte(int $size = 1): string
105
    {
106 231
        $result = '';
107 231
        $replay = [];
108 231
        for ($i = 0; $i < $size; $i++) {
109 231
            $n = $this->next();
110 231
            if ($n !== null) {
111 231
                $replay[] = $n;
112
            }
113
114 231
            if (!$n instanceof Byte) {
115 126
                break;
116
            }
117
118 231
            $result .= $n->char;
119
        }
120
121 231
        foreach (\array_reverse($replay) as $n) {
122 231
            \array_unshift($this->replay, $n);
123
        }
124
125 231
        return $result;
126
    }
127
128
    /**
129
     * Replay all the byte and token stream after given offset.
130
     */
131 95
    public function replay(int $offset): void
132
    {
133 95
        foreach ($this->buffer as $n) {
134 95
            if ($n->offset > $offset) {
135 52
                $this->replay[] = $n;
136
            }
137
        }
138
    }
139
140 2
    public function cleanReplay(): void
141
    {
142 2
        $this->replay = [];
143
    }
144
}
145