Lexer::map()   C
last analyzed

Complexity

Conditions 8
Paths 8

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 15
nc 8
nop 1
dl 0
loc 27
rs 5.3846
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of Jitamin.
5
 *
6
 * Copyright (C) Jitamin Team
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Jitamin\Foundation\Filter;
13
14
/**
15
 * Lexer.
16
 */
17
class Lexer
18
{
19
    /**
20
     * Current position.
21
     *
22
     * @var int
23
     */
24
    private $offset = 0;
25
26
    /**
27
     * Token map.
28
     *
29
     * @var array
30
     */
31
    private $tokenMap = [
32
        '/^(\s+)/'                                  => 'T_WHITESPACE',
33
        '/^([<=>]{0,2}[0-9]{4}-[0-9]{2}-[0-9]{2})/' => 'T_STRING',
34
        '/^([<=>]{1,2}\w+)/u'                       => 'T_STRING',
35
        '/^([<=>]{1,2}".+")/'                       => 'T_STRING',
36
        '/^("(.+)")/'                               => 'T_STRING',
37
        '/^(\S+)/u'                                 => 'T_STRING',
38
        '/^(#\d+)/'                                 => 'T_STRING',
39
    ];
40
41
    /**
42
     * Default token.
43
     *
44
     * @var string
45
     */
46
    private $defaultToken = '';
47
48
    /**
49
     * Add token.
50
     *
51
     * @param string $regex
52
     * @param string $token
53
     *
54
     * @return $this
55
     */
56
    public function addToken($regex, $token)
57
    {
58
        $this->tokenMap = [$regex => $token] + $this->tokenMap;
59
60
        return $this;
61
    }
62
63
    /**
64
     * Set default token.
65
     *
66
     * @param string $token
67
     *
68
     * @return $this
69
     */
70
    public function setDefaultToken($token)
71
    {
72
        $this->defaultToken = $token;
73
74
        return $this;
75
    }
76
77
    /**
78
     * Tokenize input string.
79
     *
80
     * @param string $input
81
     *
82
     * @return array
83
     */
84
    public function tokenize($input)
85
    {
86
        $tokens = [];
87
        $this->offset = 0;
88
        $input_length = mb_strlen($input, 'UTF-8');
89
90
        while ($this->offset < $input_length) {
91
            $result = $this->match(mb_substr($input, $this->offset, $input_length, 'UTF-8'));
92
93
            if ($result === false) {
94
                return [];
95
            }
96
97
            $tokens[] = $result;
98
        }
99
100
        return $this->map($tokens);
101
    }
102
103
    /**
104
     * Find a token that match and move the offset.
105
     *
106
     * @param string $string
107
     *
108
     * @return array|bool
109
     */
110
    protected function match($string)
111
    {
112
        foreach ($this->tokenMap as $pattern => $name) {
113
            if (preg_match($pattern, $string, $matches)) {
114
                $this->offset += mb_strlen($matches[1], 'UTF-8');
115
116
                return [
117
                    'match' => str_replace('"', '', $matches[1]),
118
                    'token' => $name,
119
                ];
120
            }
121
        }
122
123
        return false;
124
    }
125
126
    /**
127
     * Build map of tokens and matches.
128
     *
129
     * @param array $tokens
130
     *
131
     * @return array
132
     */
133
    protected function map(array $tokens)
134
    {
135
        $map = [];
136
        $leftOver = '';
137
138
        while (false !== ($token = current($tokens))) {
139
            if ($token['token'] === 'T_STRING' || $token['token'] === 'T_WHITESPACE') {
140
                $leftOver .= $token['match'];
141
            } else {
142
                $next = next($tokens);
143
144
                if ($next !== false && $next['token'] === 'T_STRING') {
145
                    $map[$token['token']][] = $next['match'];
146
                }
147
            }
148
149
            next($tokens);
150
        }
151
152
        $leftOver = trim($leftOver);
153
154
        if ($this->defaultToken !== '' && $leftOver !== '') {
155
            $map[$this->defaultToken] = [$leftOver];
156
        }
157
158
        return $map;
159
    }
160
}
161