Lexer::performAction()   C
last analyzed

Complexity

Conditions 15
Paths 15

Size

Total Lines 52
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 52
rs 5.9385
cc 15
eloc 33
nc 15
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php namespace CMPayments\JsonLint;
2
3
use CMPayments\JsonLint\Exceptions\JsonLintException;
4
use CMPayments\JsonLint\Exceptions\UndefinedException;
5
6
/**
7
 * Class Lexer
8
 *
9
 * @package CMPayments\JsonLint
10
 */
11
class Lexer
12
{
13
    /**
14
     * @var int
15
     */
16
    private $EOF = 1;
17
18
    /**
19
     * @var array
20
     */
21
    private $rules = [
22
        0  => '/^\s+/',
23
        1  => '/^-?([0-9]|[1-9][0-9]+)(\.[0-9]+)?([eE][+-]?[0-9]+)?\b/',
24
        2  => '{^"(?:\\\\["bfnrt/\\\\]|\\\\u[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f\\\\"]+)*"}',
25
        3  => '/^\{/',
26
        4  => '/^\}/',
27
        5  => '/^\[/',
28
        6  => '/^\]/',
29
        7  => '/^,/',
30
        8  => '/^:/',
31
        9  => '/^true\b/',
32
        10 => '/^false\b/',
33
        11 => '/^null\b/',
34
        12 => '/^$/',
35
        13 => '/^./',
36
    ];
37
38
    /**
39
     * @var array
40
     */
41
    private $conditions = ["INITIAL" => ["rules" => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], "inclusive" => true]];
42
43
    /**
44
     * @var
45
     */
46
    private $conditionStack;
47
48
    /**
49
     * @var
50
     */
51
    private $input;
52
53
    /**
54
     * @var
55
     */
56
    private $done;
57
58
    /**
59
     * @var
60
     */
61
    private $matched;
62
63
    /**
64
     * @var
65
     */
66
    public $match;
67
68
    /**
69
     * @var
70
     */
71
    public $yLineNo;
72
73
    /**
74
     * @var
75
     */
76
    public $yColumnNo;
77
78
    /**
79
     * @var
80
     */
81
    public $yLength;
82
83
    /**
84
     * @var
85
     */
86
    public $yText;
87
88
    /**
89
     * @var
90
     */
91
    public $yLocation;
92
93
    /**
94
     * @return UndefinedException|int|null|string
95
     */
96
    public function lex()
97
    {
98
        $r = $this->next();
99
100
        if (!$r instanceof UndefinedException) {
101
102
            return $r;
103
        }
104
105
        return $this->lex();
106
    }
107
108
    /**
109
     * @param string $input
110
     *
111
     * @return $this
112
     */
113
    public function setInput($input)
114
    {
115
        $this->input          = $input;
116
        $this->done           = false;
117
        $this->yLineNo        = $this->yLength = $this->yColumnNo = 0;
118
        $this->yText          = $this->matched = $this->match = '';
119
        $this->conditionStack = ['INITIAL'];
120
        $this->yLocation      = ['last_line' => 1, 'last_column' => 0];
121
122
        return $this;
123
    }
124
125
    /**
126
     * @return string
127
     */
128
    public function getPastInput()
129
    {
130
        $past = substr($this->matched, 0, (strlen($this->matched) - strlen($this->yText)));
131
132
        return (strlen($past) > 20 ? '...' : '') . substr($past, -20);
133
    }
134
135
    /**
136
     * @return string
137
     */
138
    public function getUpcomingInput()
139
    {
140
        $next = $this->yText;
141
142
        if (strlen($next) < 20) {
143
            $next .= substr($this->input, 0, 20 - strlen($next));
144
        }
145
146
        return substr($next, 0, 20) . (strlen($next) > 20 ? '...' : '');
147
    }
148
149
    /**
150
     * @return UndefinedException|int|null|string
151
     * @throws \Exception
152
     */
153
    private function next()
154
    {
155
        if ($this->done) {
156
157
            return $this->EOF;
158
        }
159
160
        if (!$this->input) {
161
162
            $this->done = true;
163
        }
164
165
        $match = $lines = null;
166
167
        $this->yText = $this->match = '';
168
169
        $rules    = $this->getCurrentRules();
170
        $rulesLen = count($rules);
171
172
        for ($i = 0; $i < $rulesLen; $i++) {
173
174
            if (preg_match($this->rules[$rules[$i]], $this->input, $match)) {
175
176
                preg_match_all('/\n.*/', $match[0], $lines);
177
                $lines = $lines[0];
178
179
                if ($lines) {
180
181
                    $this->yLineNo += count($lines);
182
                }
183
184
                $this->yLocation = [
185
                    'last_line'   => $this->yLineNo + 1,
186
                    'last_column' => $lines ? strlen($lines[count($lines) - 1]) - 1 : $this->yLocation['last_column'] + strlen($match[0]),
187
                ];
188
189
                preg_match("/^[\"|']?(?P<match>.*?)(?:[\"|'](.*)$|$)/", explode("\n", $this->input)[0], $inputMatches);
190
191
                $this->yText .= $match[0];
192
                $this->match .= (isset($inputMatches['match']) ? $inputMatches['match'] : $match[0]);
193
                $this->yLength = strlen($this->yText);
194
                $this->yColumnNo = $this->yLocation['last_column'];
195
                $this->input   = substr($this->input, strlen($this->yText));
196
                $this->matched .= $this->yText;
197
                $token = $this->performAction($rules[$i]);
198
199
                if ($token) {
200
201
                    return $token;
202
                }
203
204
                return new UndefinedException(UndefinedException::ERROR_UNDEFINED_VALIDATION);
205
            }
206
        }
207
208
        if ($this->input === '') {
209
210
            return $this->EOF;
211
        }
212
213
        throw new JsonLintException(JsonLintException::ERROR_LEXICAL_ERROR, [($this->yLineNo + 1)]);
214
    }
215
216
    /**
217
     * @return mixed
218
     */
219
    private function getCurrentRules()
220
    {
221
        return $this->conditions[$this->conditionStack[count($this->conditionStack) - 1]]['rules'];
222
    }
223
224
    /**
225
     * @param $avoiding_name_collisions
226
     *
227
     * @return int|string
228
     */
229
    private function performAction($avoiding_name_collisions)
230
    {
231
        switch ($avoiding_name_collisions) {
232
233
            case 0:/* skip whitespace */
234
                return null;
235
236
            case 1:
237
                return 6;
238
239
            case 2:
240
                $this->yText = substr($this->yText, 1, $this->yLength - 2);
241
242
                return 4;
243
244
            case 3:
245
                return 17;
246
247
            case 4:
248
                return 18;
249
250
            case 5:
251
                return 23;
252
253
            case 6:
254
                return 24;
255
256
            case 7:
257
                return 22;
258
259
            case 8:
260
                return 21;
261
262
            case 9:
263
                return 10;
264
265
            case 10:
266
                return 11;
267
268
            case 11:
269
                return 8;
270
271
            case 12:
272
                return 14;
273
274
            case 13:
275
                return 'INVALID';
276
277
            default:
278
                return null;
279
        }
280
    }
281
}
282