Passed
Pull Request — master (#806)
by Maxim
19:17
created

BracesGrammar::parse()   B

Complexity

Conditions 11
Paths 6

Size

Total Lines 53
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 11.0036

Importance

Changes 0
Metric Value
cc 11
eloc 32
nc 6
nop 2
dl 0
loc 53
ccs 31
cts 32
cp 0.9688
crap 11.0036
rs 7.3166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Stempler\Lexer\Grammar\Dynamic;
6
7
use Spiral\Stempler\Lexer\Buffer;
8
use Spiral\Stempler\Lexer\Byte;
9
use Spiral\Stempler\Lexer\Grammar\DynamicGrammar;
10
use Spiral\Stempler\Lexer\Grammar\Traits\TokenTrait;
11
use Spiral\Stempler\Lexer\Token;
12
13
/**
14
 * Control open and close brace grammar.
15
 */
16
final class BracesGrammar
17
{
18
    use TokenTrait;
0 ignored issues
show
introduced by
The trait Spiral\Stempler\Lexer\Grammar\Traits\TokenTrait requires some properties which are not provided by Spiral\Stempler\Lexer\Gr...r\Dynamic\BracesGrammar: $char, $content, $type
Loading history...
19
20
    private bool $active = true;
21
    private ?string $startSequence = null;
22
    private ?string $endSequence = null;
23
    private array $body = [];
24
25 170
    public function __construct(
26
        string $startSequence,
27
        string $endSequence,
28
        private readonly int $startToken,
29
        private readonly int $endToken
30
    ) {
31 170
        $this->setStartSequence($startSequence);
32 170
        $this->setEndSequence($endSequence);
33
    }
34
35
    /**
36
     * Disable braces grammar.
37
     */
38
    public function disable(): void
39
    {
40
        $this->active = false;
41
    }
42
43
    /**
44
     * Enable braces grammar.
45
     */
46
    public function enable(): void
47
    {
48
        $this->active = true;
49
    }
50
51 170
    public function setStartSequence(string $startSequence): void
52
    {
53 170
        $this->startSequence = $startSequence;
54
    }
55
56 170
    public function setEndSequence(string $endSequence): void
57
    {
58 170
        $this->endSequence = $endSequence;
59
    }
60
61
    /**
62
     * Enable to disable grammar.
63
     */
64 3
    public function setActive(bool $active): void
65
    {
66 3
        $this->active = $active;
67
    }
68
69 53
    public function nextToken(Buffer $src): bool
70
    {
71 53
        return $this->active && $src->lookaheadByte(\strlen((string) $this->startSequence)) === $this->startSequence;
72
    }
73
74
    /**
75
     * Check if braces starts here.
76
     */
77 135
    public function starts(Buffer $src, Byte $n): bool
78
    {
79 135
        if (!$this->active) {
80 2
            return false;
81
        }
82
83 135
        return $this->startSequence === ($n->char . $src->lookaheadByte(\strlen((string) $this->startSequence) - 1));
84
    }
85
86
    /**
87
     * Parse braces content and return generated tokens or null in case of error.
88
     */
89 39
    public function parse(Buffer $src, Byte $n): ?array
90
    {
91 39
        $this->tokens = [
92 39
            new Token(
93 39
                $this->startToken,
94 39
                $n->offset,
95 39
                $n->char . $this->nextBytes($src, \strlen((string) $this->startSequence) - 1)
96
            ),
97
        ];
98
99 39
        while ($n = $src->next()) {
100 39
            if (!$n instanceof Byte) {
101
                // no other grammars are allowed
102
                break;
103
            }
104
105 39
            switch ($n->char) {
106 39
                case '"':
107 39
                case "'":
108 21
                    $this->body[] = $n;
109 21
                    while ($nn = $src->next()) {
110 21
                        $this->body[] = $nn;
111 21
                        if ($nn instanceof Byte && $nn->char === $n->char) {
112 21
                            break;
113
                        }
114
                    }
115 21
                    break;
116
117 39
                case $this->endSequence[0]:
118 39
                    if (!$this->ends($src, $n)) {
119
                        // still part of body
120 1
                        $this->body[] = $n;
121 1
                        break;
122
                    }
123
124 38
                    $this->flushBody();
125 38
                    $this->tokens[] = new Token(
126 38
                        $this->endToken,
127 38
                        $n->offset,
128 38
                        $n->char . $this->nextBytes($src, \strlen((string) $this->endSequence) - 1)
129
                    );
130
131 38
                    break 2;
132
                default:
133 39
                    $this->body[] = $n;
134
            }
135
        }
136
137 39
        if (\count($this->tokens) !== 3) {
138 1
            return null;
139
        }
140
141 38
        return $this->tokens;
142
    }
143
144
    /**
145
     * Check if braces ends here.
146
     */
147 39
    private function ends(Buffer $src, Byte $n): bool
148
    {
149 39
        return $this->endSequence === ($n->char . $src->lookaheadByte(\strlen((string) $this->endSequence) - 1));
150
    }
151
152
    /**
153
     * Fetch next N bytes.
154
     *
155
     * @param positive-int $size
0 ignored issues
show
Documentation Bug introduced by
The doc comment positive-int at position 0 could not be parsed: Unknown type name 'positive-int' at position 0 in positive-int.
Loading history...
156
     *
157
     * TODO issue #767
158
     * @link https://github.com/spiral/framework/issues/767
159
     * @psalm-suppress UndefinedPropertyFetch
160
     */
161 39
    private function nextBytes(Buffer $src, int $size): string
162
    {
163 39
        $result = '';
164 39
        for ($i = 0; $i < $size; $i++) {
165 39
            $result .= $src->next()->char;
0 ignored issues
show
Bug introduced by
The property char does not seem to exist on Spiral\Stempler\Lexer\Token.
Loading history...
166
        }
167
168 39
        return $result;
169
    }
170
171
    /**
172
     * Pack name token.
173
     */
174 38
    private function flushBody(): void
175
    {
176 38
        if ($this->body === []) {
177
            return;
178
        }
179
180 38
        $this->tokens[] = $this->packToken($this->body, DynamicGrammar::TYPE_BODY);
181 38
        $this->body = [];
182
    }
183
}
184