Lexer::applyPostFunctions()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 2
crap 2
1
<?php
2
3
4
namespace CondParse;
5
6
7
use CondParse\Exception\LexerException;
8
9
class Lexer implements LexerInterface
10
{
11
    /** @var callable[] */
12
    private $postFunctions = [];
13
14
    /** @var LexerTokenFactory */
15
    private $lexerTokenFactory;
16
17 18
    public function __construct()
18
    {
19 18
        $this->lexerTokenFactory = new LexerTokenFactory;
20 18
    }
21
22
    /**
23
     * @param callable $postFunction
24
     * @return $this
25
     */
26 9
    public function registerPostFunction(callable $postFunction)
27
    {
28 9
        $this->postFunctions[] = $postFunction;
29 9
        return $this;
30
    }
31
32
    /**
33
     * @param TokenMap $tokenMap
34
     * @return string
35
     */
36 18
    protected function buildRegex(TokenMap $tokenMap)
37
    {
38 18
        return sprintf(
39 18
            '/%s/Si',
40 18
            join('|',
41 18
                array_map(function ($key, $value) {
42 18
                    return sprintf('(?P<%s>%s)', $key, $value);
43 18
                }, array_keys($tokenMap->getTokens()), $tokenMap->getTokens())
44 18
            )
45 18
        );
46
    }
47
48
    /**
49
     * @param string $token
50
     * @param string $match
51
     * @return string
52
     */
53 18
    protected function applyPostFunctions($token, $match)
54
    {
55 18
        foreach ($this->postFunctions as $postFunction) {
56 9
            $match = call_user_func($postFunction, $token, $match);
57 18
        }
58
59 18
        return $match;
60
    }
61
62
    /**
63
     * @param string $conditionString
64
     * @param string $regex
65
     * @return \Traversable <LexerToken>
66
     * @throws LexerException
67
     */
68 18
    protected function getTokenStreamWithRegex($conditionString, $regex)
69
    {
70 18
        $offSet = 0;
71
72 18
        $matches = [];
73 18
        while (preg_match($regex, $conditionString, $matches, 0, $offSet) !== 0) {
74 18
            list($match, $token) = $this->extractMatch($matches);
75
76 18
            $this->checkMatchOffset($conditionString, $match, $offSet);
77
78 18
            $offSet += strlen($match);
79
80 18
            yield $this->lexerTokenFactory->buildLexerToken($token, $this->applyPostFunctions($token, $match));
81 18
        }
82 17
    }
83
84
    /**
85
     * @param string $conditionString
86
     * @param TokenMap $tokenMap
87
     * @return \Traversable <string>
88
     */
89 18
    public function getTokenStream($conditionString, TokenMap $tokenMap) {
90 18
        return $this->getTokenStreamWithRegex($conditionString, $this->buildRegex($tokenMap));
91
    }
92
93
    /**
94
     * @param $matches
95
     * @return array
96
     */
97 18
    protected function extractMatch($matches)
98
    {
99 18
        foreach ($matches as $key => $value) {
100 18
            if (is_string($key) && $value !== '') {
101 18
                return [$value, $key];
102
            }
103 18
        }
104
105
        return [];
106
    }
107
108
    /**
109
     * @param $conditionString
110
     * @param $match
111
     * @param $offSet
112
     * @throws LexerException
113
     */
114 18
    protected function checkMatchOffset($conditionString, $match, $offSet)
115
    {
116 18
        if (($matchOffset = strpos($conditionString, $match, $offSet)) !== $offSet) {
117 1
            throw new LexerException(sprintf(
118 1
                'Found unrecognized token <%s> at offset %d',
119 1
                substr($conditionString, $offSet, ($matchOffset - $offSet)),
120
                $offSet
121 1
            ));
122
        }
123 18
    }
124
}
125