TokenMatcherSpec::getOnError()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\UniLex\Lexer;
6
7
use ReflectionClass;
8
use ReflectionException;
9
use ReflectionMethod;
10
use Remorhaz\UniLex\Exception;
11
12
class TokenMatcherSpec
13
{
14
    private $targetClassName;
15
16
    private $templateClassName;
17
18
    private $templateClass;
19
20
    private $usedClassList;
21
22
    private $targetNamespaceName;
23
24
    private $targetShortName;
25
26
    private $fileCommentList = [];
27
28
    private $header = '';
29
30
    private $beforeMatch = '';
31
32
    private $onError = '';
33
34
    private $onTransition = '';
35
36
    private $onToken = '';
37
38
    private $tokenSpecList = [];
39
40
    public function __construct(string $targetClassName, string $templateClassName)
41
    {
42
        $this->targetClassName = $targetClassName;
43
        $this->templateClassName = $templateClassName;
44
    }
45
46
    /**
47
     * @return ReflectionClass
48
     * @throws ReflectionException
49
     */
50
    public function getTemplateClass(): ReflectionClass
51
    {
52
        if (!isset($this->templateClass)) {
53
            $this->templateClass = new ReflectionClass($this->templateClassName);
54
        }
55
56
        return $this->templateClass;
57
    }
58
59
    public function getTargetClassName(): string
60
    {
61
        return $this->targetClassName;
62
    }
63
64
    /**
65
     * @param string      $name
66
     * @param string|null $alias
67
     * @return TokenMatcherSpec
68
     * @throws ReflectionException
69
     */
70
    public function addUsedClass(string $name, string $alias = null): self
71
    {
72
        $this->initUsedClassList();
73
        if (in_array($name, $this->usedClassList)) {
74
            return $this;
75
        }
76
        $class = new ReflectionClass($name);
77
        if ($this->getTargetNamespaceName() == $class->getNamespaceName()) {
78
            return $this;
79
        }
80
        if (isset($alias)) {
81
            $this->usedClassList[$alias] = $name;
82
83
            return $this;
84
        }
85
        $this->usedClassList[] = $name;
86
87
        return $this;
88
    }
89
90
    /**
91
     * @return array
92
     * @throws ReflectionException
93
     */
94
    public function getUsedClassList(): array
95
    {
96
        $this->initUsedClassList();
97
        $usedClassList = $this->usedClassList;
98
        asort($usedClassList);
99
100
        return $usedClassList;
101
    }
102
103
    public function addFileComment(string ...$textLineList): self
104
    {
105
        foreach ($textLineList as $textLine) {
106
            $this->fileCommentList[] = $textLine;
107
        }
108
109
        return $this;
110
    }
111
112
    public function getFileComment(): string
113
    {
114
        return implode("\n", $this->fileCommentList);
115
    }
116
117
    public function getTargetNamespaceName(): string
118
    {
119
        if (!isset($this->targetNamespaceName)) {
120
            [0 => $namespaceName] = $this->splitTargetClassName();
121
            $this->targetNamespaceName = $namespaceName;
122
        }
123
124
        return $this->targetNamespaceName;
125
    }
126
127
    public function getTargetShortName(): string
128
    {
129
        if (!isset($this->targetShortName)) {
130
            [1 => $shortName] = $this->splitTargetClassName();
131
            $this->targetShortName = $shortName;
132
        }
133
134
        return $this->targetShortName;
135
    }
136
137
    /**
138
     * @return ReflectionMethod
139
     * @throws ReflectionException
140
     */
141
    public function getMatchMethod(): ReflectionMethod
142
    {
143
        return $this->getTemplateClass()->getMethod('match');
144
    }
145
146
    public function setHeader(string $code): self
147
    {
148
        $this->header = $code;
149
150
        return $this;
151
    }
152
153
    public function getHeader(): string
154
    {
155
        return $this->header;
156
    }
157
158
    public function setBeforeMatch(string $code): self
159
    {
160
        $this->beforeMatch = $code;
161
162
        return $this;
163
    }
164
165
    public function getBeforeMatch(): string
166
    {
167
        return $this->beforeMatch;
168
    }
169
170
    public function setOnError(string $code): self
171
    {
172
        $this->onError = $code;
173
174
        return $this;
175
    }
176
177
    public function getOnError(): string
178
    {
179
        return $this->onError;
180
    }
181
182
    public function setOnTransition(string $code): self
183
    {
184
        $this->onTransition = $code;
185
186
        return $this;
187
    }
188
189
    public function getOnTransition(): string
190
    {
191
        return $this->onTransition;
192
    }
193
194
    public function setOnToken(string $code): self
195
    {
196
        $this->onToken = $code;
197
198
        return $this;
199
    }
200
201
    public function getOnToken(): string
202
    {
203
        return $this->onToken;
204
    }
205
206
    /**
207
     * @param string    $context
208
     * @param TokenSpec ...$tokenSpecList
209
     * @return TokenMatcherSpec
210
     * @throws Exception
211
     */
212
    public function addTokenSpec(string $context, TokenSpec ...$tokenSpecList): self
213
    {
214
        foreach ($tokenSpecList as $tokenSpec) {
215
            $regExp = $tokenSpec->getRegExp();
216
            if (isset($this->tokenSpecList[$context][$regExp])) {
217
                throw new Exception("Token spec for pattern {$regExp} is already set");
218
            }
219
            $this->tokenSpecList[$context][$regExp] = $tokenSpec;
220
        }
221
222
        return $this;
223
    }
224
225
    /**
226
     * @param string $mode
227
     * @return TokenSpec[]
228
     */
229
    public function getTokenSpecList(string $mode): array
230
    {
231
        return $this->tokenSpecList[$mode] ?? [];
232
    }
233
234
    public function getTokenSpec(string $mode, string $regExp): TokenSpec
235
    {
236
        foreach ($this->getTokenSpecList($mode) ?? [] as $tokenSpec) {
237
            if ($tokenSpec->getRegExp() == $regExp) {
238
                return $tokenSpec;
239
            }
240
        }
241
242
        throw new Exception("Token spec not found: {$regExp}");
243
    }
244
245
    /**
246
     * @return string[]
247
     */
248
    public function getModeList(): array
249
    {
250
        return array_keys($this->tokenSpecList);
251
    }
252
253
    private function splitTargetClassName(): array
254
    {
255
        $nameSpaceSeparator = '\\';
256
        $classNameParts = explode($nameSpaceSeparator, $this->getTargetClassName());
257
        $className = array_pop($classNameParts);
258
        $namespaceName = implode($nameSpaceSeparator, $classNameParts);
259
260
        return [$namespaceName, $className];
261
    }
262
263
    /**
264
     * @throws ReflectionException
265
     */
266
    private function initUsedClassList(): void
267
    {
268
        if (isset($this->usedClassList)) {
269
            return;
270
        }
271
        $this->usedClassList = [];
272
        foreach ($this->getMatchMethod()->getParameters() as $parameter) {
273
            if ($parameter->hasType() && !$parameter->getType()->isBuiltin()) {
274
                $this->addUsedClass($parameter->getType()->getName());
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

274
                $this->addUsedClass($parameter->getType()->/** @scrutinizer ignore-call */ getName());
Loading history...
275
            }
276
        }
277
        $this->addUsedClass($this->getTemplateClass()->getName());
278
    }
279
}
280