Completed
Push — master ( 4cc554...e2bb59 )
by Nico
01:55
created

Tokenizer   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 92
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 95.65%

Importance

Changes 0
Metric Value
wmc 16
lcom 1
cbo 2
dl 0
loc 92
ccs 44
cts 46
cp 0.9565
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
A tokenize() 0 22 2
A registerToken() 0 10 1
A getMatchedToken() 0 10 4
A getRegex() 0 15 4
A getQueue() 0 10 2
A getPriority() 0 4 1
1
<?php
2
3
/**
4
 * @license     http://opensource.org/licenses/mit-license.php MIT
5
 * @link        https://github.com/nicoSWD
6
 * @author      Nicolas Oelgart <[email protected]>
7
 */
8
declare(strict_types=1);
9
10
namespace nicoSWD\Rules;
11
12
use SplPriorityQueue;
13
use stdClass;
14
15
final class Tokenizer implements TokenizerInterface
16
{
17
    private $internalTokens = [];
18
19
    private $regex = '';
20
21
    private $regexRequiresReassembly = false;
22
23 240
    public function __construct(Grammar $grammar)
24
    {
25 240
        foreach ($grammar->getDefinition() as list($class, $regex, $priority)) {
26 240
            $this->registerToken($class, $regex, $priority);
27
        }
28 240
    }
29
30 230
    public function tokenize(string $string): Stack
31
    {
32 230
        $stack = new Stack();
33 230
        $regex = $this->getRegex();
34 230
        $baseNameSpace = __NAMESPACE__ . '\\Tokens\\Token';
35 230
        $offset = 0;
36
37 230
        while (preg_match($regex, $string, $matches, 0, $offset)) {
38 228
            $token = $this->getMatchedToken($matches);
39 228
            $className = $baseNameSpace . $token;
40
41 228
            $stack->attach(new $className(
42 228
                $matches[$token],
43 228
                $offset,
44 228
                $stack
45
            ));
46
47 228
            $offset += strlen($matches[0]);
48
        }
49
50 230
        return $stack;
51
    }
52
53 240
    public function registerToken(string $class, string $regex, int $priority = null)
54
    {
55 240
        $token = new stdClass();
56 240
        $token->class = $class;
57 240
        $token->regex = $regex;
58 240
        $token->priority = $priority ?? $this->getPriority($class);
59
60 240
        $this->internalTokens[$class] = $token;
61 240
        $this->regexRequiresReassembly = true;
62 240
    }
63
64 230
    private function getMatchedToken(array $matches): string
65
    {
66 230
        foreach ($matches as $key => $value) {
67 228
            if ($value !== '' && !is_int($key)) {
68 228
                return $key;
69
            }
70
        }
71
72 2
        return 'Unknown';
73
    }
74
75 230
    private function getRegex(): string
76
    {
77 230
        if (!$this->regex || $this->regexRequiresReassembly) {
78 230
            $regex = [];
79
80 230
            foreach ($this->getQueue() as $token) {
81 230
                $regex[] = "(?<$token->class>$token->regex)";
82
            }
83
84 230
            $this->regex = sprintf('~(%s)~As', implode('|', $regex));
85 230
            $this->regexRequiresReassembly = false;
86
        }
87
88 230
        return $this->regex;
89
    }
90
91 230
    private function getQueue(): SplPriorityQueue
92
    {
93 230
        $queue = new SplPriorityQueue();
94
95 230
        foreach ($this->internalTokens as $class) {
96 230
            $queue->insert($class, $class->priority);
97
        }
98
99 230
        return $queue;
100
    }
101
102
    private function getPriority(string $class): int
103
    {
104
        return $this->internalTokens[$class]->priority ?? 10;
105
    }
106
}
107