Completed
Push — master ( 76acb2...4e56bc )
by Nico
02:11
created

Tokenizer::getMatchedToken()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 5
nc 3
nop 1
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * @license     http://opensource.org/licenses/mit-license.php MIT
7
 * @link        https://github.com/nicoSWD
8
 * @author      Nicolas Oelgart <[email protected]>
9
 */
10
namespace nicoSWD\Rule\Tokenizer;
11
12
use nicoSWD\Rule\Grammar\Grammar;
13
use nicoSWD\Rule\TokenStream\Token\TokenFactory;
14
use SplPriorityQueue;
15
use stdClass;
16
17
final class Tokenizer implements TokenizerInterface
18
{
19
    /** @var TokenFactory */
20
    private $tokenFactory;
21
    /** @var Grammar */
22
    private $grammar;
23
    /** @var stdClass[] */
24
    private $internalTokens = [];
25
    /** @var string */
26
    private $regex = '';
27
28 234
    public function __construct(Grammar $grammar, TokenFactory $tokenFactory)
29
    {
30 234
        $this->tokenFactory = $tokenFactory;
31 234
        $this->grammar = $grammar;
32
33 234
        foreach ($grammar->getDefinition() as list($class, $regex, $priority)) {
34 234
            $this->registerToken($class, $regex, $priority);
35
        }
36 234
    }
37
38 228
    public function tokenize(string $string): TokenStack
39
    {
40 228
        $stack = new TokenStack();
41 228
        $regex = $this->getRegex();
42 228
        $offset = 0;
43
44 228
        while (preg_match($regex, $string, $matches, 0, $offset)) {
45 226
            $token = $this->getMatchedToken($matches);
46 226
            $className = $this->tokenFactory->createFromTokenName($token);
47
48 226
            $stack->attach(new $className(
49 226
                $matches[$token],
50 226
                $offset,
51 226
                $stack
52
            ));
53
54 226
            $offset += strlen($matches[0]);
55
        }
56
57 228
        return $stack;
58
    }
59
60 134
    public function getGrammar(): Grammar
61
    {
62 134
        return $this->grammar;
63
    }
64
65 234
    private function registerToken(string $class, string $regex, int $priority)
66
    {
67 234
        $token = new stdClass();
68 234
        $token->class = $class;
69 234
        $token->regex = $regex;
70 234
        $token->priority = $priority;
71
72 234
        $this->internalTokens[$class] = $token;
73 234
    }
74
75 228
    private function getMatchedToken(array $matches): string
76
    {
77 228
        foreach ($matches as $key => $value) {
78 226
            if ($value !== '' && !is_int($key)) {
79 226
                return $key;
80
            }
81
        }
82
83 2
        return 'Unknown';
84
    }
85
86 228
    private function getRegex(): string
87
    {
88 228
        if (!$this->regex) {
89 170
            $regex = [];
90
91 170
            foreach ($this->getQueue() as $token) {
92 170
                $regex[] = "(?<$token->class>$token->regex)";
93
            }
94
95 170
            $this->regex = '~(' . implode('|', $regex) . ')~As';
96
        }
97
98 228
        return $this->regex;
99
    }
100
101 170
    private function getQueue(): SplPriorityQueue
102
    {
103 170
        $queue = new SplPriorityQueue();
104
105 170
        foreach ($this->internalTokens as $class) {
106 170
            $queue->insert($class, $class->priority);
107
        }
108
109 170
        return $queue;
110
    }
111
}
112