AbstractTokenExtractor   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 77
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 19
c 1
b 0
f 0
dl 0
loc 77
ccs 20
cts 20
cp 1
rs 10
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A createToken() 0 9 3
A extract() 0 18 5
A createGroupBeginToken() 0 3 1
A getByteOffset() 0 3 1
1
<?php declare(strict_types = 1);
2
3
namespace Apicart\FQL\Tokenizer;
4
5
use Apicart\FQL\Token\Token\GroupBegin;
6
use Apicart\FQL\Value\Token;
7
use RuntimeException;
8
9
abstract class AbstractTokenExtractor
10
{
11
12
    /**
13
     * Return the token at the given $position of the $string.
14
     *
15
     * @throws RuntimeException On PCRE regex error
16
     */
17 507
    final public function extract(string $string, int $position): Token
18
    {
19 507
        $byteOffset = $this->getByteOffset($string, $position);
20 507
        foreach ($this->getExpressionTypeMap() as $expression => $type) {
21 507
            $success = preg_match($expression, $string, $matches, 0, $byteOffset);
22 507
            if ($success === false) {
23 1
                throw new RuntimeException('PCRE regex error code: ' . preg_last_error());
24
            }
25 506
            if ($success === 0) {
26 502
                continue;
27
            }
28 506
            if (isset($matches['domain'])) {
29
                $matches['domain'] = trim($matches['domain'], "'");
30 19
            }
31
32
            return $this->createToken($type, $position, $matches);
33
        }
34
        return new Token(Tokenizer::TOKEN_BAILOUT, mb_substr($string, $position, 1), $position);
35
    }
36
37
38
    /**
39
     * Return a map of regular expressions to token types.
40
     *
41
     * The returned map must be an array where key is a regular expression
42
     * and value is a corresponding token type. Regular expression must define
43
     * named capturing group 'lexeme' that identifies part of the input string
44
     * recognized as token.
45
     */
46
    abstract protected function getExpressionTypeMap(): array;
47
48
49
    /**
50
     * Create a term type token by the given parameters.
51
     *
52
     * @throw RuntimeException If token could not be created from the given $matches data
53
     */
54
    abstract protected function createTermToken(int $position, array $data): Token;
55
56 74
57
    /**
58 74
     * Create an instance of Group token by the given parameters.
59
     */
60
    protected function createGroupBeginToken(int $position, array $data): GroupBegin
61
    {
62 506
        return new GroupBegin($data['lexeme'], $position, $data['delimiter'], $data['domain']);
63
    }
64 506
65 88
66
    private function createToken(int $type, int $position, array $data): Token
67 506
    {
68 420
        if ($type === Tokenizer::TOKEN_GROUP_BEGIN) {
69
            return $this->createGroupBeginToken($position, $data);
70 293
        }
71
        if ($type === Tokenizer::TOKEN_TERM) {
72
            return $this->createTermToken($position, $data);
73
        }
74
        return new Token($type, $data['lexeme'], $position);
75
    }
76
77
78
    /**
79 507
     * Return the offset of the given $position in the input $string, in bytes.
80
     *
81 507
     * Offset in bytes is needed for preg_match $offset parameter.
82
     */
83
    private function getByteOffset(string $string, int $position): int
84
    {
85
        return strlen(mb_substr($string, 0, $position));
86
    }
87
88
}
89