CharBuffer   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 105
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 33
dl 0
loc 105
rs 10
c 0
b 0
f 0
wmc 18

10 Methods

Rating   Name   Duplication   Size   Complexity  
A finishToken() 0 3 1
A __construct() 0 4 1
A resetToken() 0 3 1
A getTokenAsString() 0 11 4
A getSymbol() 0 6 2
A prevSymbol() 0 9 3
A nextSymbol() 0 6 2
A getTokenAsArray() 0 7 2
A isEnd() 0 3 1
A getTokenPosition() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\UniLex\IO;
6
7
use Remorhaz\UniLex\Exception;
8
use Remorhaz\UniLex\Lexer\Token;
9
use Remorhaz\UniLex\Lexer\TokenPosition;
10
11
class CharBuffer implements CharBufferInterface, TokenExtractInterface
12
{
13
    private $data;
14
15
    private $length;
16
17
    private $startOffset = 0;
18
19
    private $previewOffset = 0;
20
21
    public function __construct(int ...$data)
22
    {
23
        $this->data = $data;
24
        $this->length = count($data);
25
    }
26
27
    public function isEnd(): bool
28
    {
29
        return $this->previewOffset == $this->length;
30
    }
31
32
    /**
33
     * @return int
34
     * @throws Exception
35
     */
36
    public function getSymbol(): int
37
    {
38
        if ($this->previewOffset == $this->length) {
39
            throw new Exception("No symbol to preview at index {$this->previewOffset}");
40
        }
41
        return $this->data[$this->previewOffset];
42
    }
43
44
    /**
45
     * @throws Exception
46
     */
47
    public function nextSymbol(): void
48
    {
49
        if ($this->previewOffset == $this->length) {
50
            throw new Exception("Unexpected end of buffer on preview at index {$this->previewOffset}");
51
        }
52
        $this->previewOffset++;
53
    }
54
55
    /**
56
     * @param int $repeat
57
     * @throws Exception
58
     */
59
    public function prevSymbol(int $repeat = 1): void
60
    {
61
        if ($repeat < 1) {
62
            throw new Exception("Non-positive unread repeat counter: {$repeat}");
63
        }
64
        if ($this->previewOffset - $repeat < $this->startOffset) {
65
            throw new Exception("Invalid unread repeat counter: {$repeat}");
66
        }
67
        $this->previewOffset -= $repeat;
68
    }
69
70
    public function resetToken(): void
71
    {
72
        $this->previewOffset = $this->startOffset;
73
    }
74
75
    /**
76
     * @param Token $token
77
     */
78
    public function finishToken(Token $token): void
79
    {
80
        $this->startOffset = $this->previewOffset;
81
    }
82
83
    public function getTokenAsArray(): array
84
    {
85
        $result = [];
86
        for ($i = $this->startOffset; $i < $this->previewOffset; $i++) {
87
            $result[] = $this->data[$i];
88
        }
89
        return $result;
90
    }
91
92
    /**
93
     * @return string
94
     * @throws Exception
95
     */
96
    public function getTokenAsString(): string
97
    {
98
        $result = '';
99
        foreach ($this->getTokenAsArray() as $index => $char) {
100
            if ($char < 0 || $char > 0xFF) {
101
                $offset = $this->startOffset + $index;
102
                throw new Exception("Only 8-bit symbols can be converted to string, {$char} found at index {$offset}");
103
            }
104
            $result .= chr($char);
105
        }
106
        return $result;
107
    }
108
109
    /**
110
     * @return TokenPosition
111
     * @throws Exception
112
     */
113
    public function getTokenPosition(): TokenPosition
114
    {
115
        return new TokenPosition($this->startOffset, $this->previewOffset);
116
    }
117
}
118