GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — v0.89-develop ( dbf016...e6ca53 )
by Zordius
03:50
created

Parser::analyze()   D

Complexity

Conditions 22
Paths 19

Size

Total Lines 101
Code Lines 63

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 63
CRAP Score 22

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 101
ccs 63
cts 63
cp 1
rs 4.6626
cc 22
eloc 63
nc 19
nop 2
crap 22

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
2
/*
3
4
Copyrights for code authored by Yahoo! Inc. is licensed under the following terms:
5
MIT License
6
Copyright (c) 2013-2015 Yahoo! Inc. All Rights Reserved.
7
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
11
Origin: https://github.com/zordius/lightncandy
12
*/
13
14
/**
15
 * file to keep LightnCandy Parser
16
 *
17
 * @package    LightnCandy
18
 * @author     Zordius <[email protected]>
19
 */
20
21
namespace LightnCandy;
22
23
use \LightnCandy\Token;
24
use \LightnCandy\SafeString;
25
26
/**
27
 * LightnCandy Parser
28
 */
29
class Parser extends Token
30
{
31
    // Compile time error handling flags
32
    const BLOCKPARAM = 9999;
33
34
    /**
35
     * Get block params and fix the variable list
36
     *
37
     * @param array<boolean|integer|array> $vars parsed token
38
     *
39
     * @return array<string>|null Return list of block params or null
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|integer|array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
40
     *
41
     */
42 179
    public static function getBlockParams(&$vars) {
43 179
        if (isset($vars[static::BLOCKPARAM])) {
44 6
            $list = $vars[static::BLOCKPARAM];
45 6
            unset($vars[static::BLOCKPARAM]);
46 6
            return $list;
47
        }
48 174
    }
49
50
    /**
51
     * Return array presentation for an expression
52
     *
53
     * @param string $name variable name.
54
     * @param boolean $asis keep the name as is or not
55
     * @param boolean $quote add single quote or not
56
     *
57
     * @return array<integer|string> Return variable name array
58
     *
59
     */
60 92
    protected static function getLiteral($name, $asis, $quote = false) {
61 92
        return $asis ? array($name) : array(0, $quote ? "'$name'" : $name);
62
    }
63
64
    /**
65
     * Return array presentation for an expression
66
     *
67
     * @param string $v analyzed expression names.
68
     * @param array<string,array|string|integer> $context Current compile content.
69
     * @param integer $pos expression position
70
     * @param integer $all total number of expressions
71
     *
72
     * @return array<integer,string> Return variable name array
73
     *
74
     * @expect array('this') when input 'this', array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 0)), 0, 2
75
     * @expect array() when input 'this', array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1)), 0, 2
76
     * @expect array(1) when input '../', array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
77
     * @expect array(1) when input '../.', array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
78
     * @expect array(1) when input '../this', array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
79
     * @expect array(1, 'a') when input '../a', array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
80
     * @expect array(2, 'a', 'b') when input '../../a.b', array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
81
     * @expect array(2, '[a]', 'b') when input '../../[a].b', array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
82
     * @expect array(2, 'a', 'b') when input '../../[a].b', array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
83
     * @expect array('id') when input 'this.id', array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
84
     * @expect array(0, '\'a.b\'') when input '"a.b"', array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
85
     * @expect array(0, '123') when input '123', array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
86
     * @expect array(0, 'null') when input 'null', array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 0, 'parent' => 1), 'usedFeature' => array('parent' => 0)), 0, 2
87
     */
88 617
    protected static function getExpression($v, &$context, $pos, $all) {
89 617
        $asis = ($all === 1) && ($pos === 0);
90
91
        // handle number
92 617
        if (is_numeric($v)) {
93 28
            return static::getLiteral(strval(1 * $v), $asis);
94
        }
95
96
        // handle double quoted string
97 613
        if (preg_match('/^"(.*)"$/', $v, $matched)) {
98 45
            return static::getLiteral(preg_replace('/([^\\\\])\\\\\\\\"/', '$1"', preg_replace('/^\\\\\\\\"/', '"', $matched[1])), $asis, true);
99
        }
100
101
        // handle single quoted string
102 607
        if (preg_match('/^\\\\\'(.*)\\\\\'$/', $v, $matched)) {
103 20
            return static::getLiteral($matched[1], $asis, true);
104
        }
105
106
        // handle boolean, null and undefined
107 604
        if (preg_match('/^(true|false|null|undefined)$/', $v)) {
108 29
            return static::getLiteral($v, $asis);
109
        }
110
111 599
        $ret = array();
112 599
        $levels = 0;
113
114
        // handle ..
115 599
        if ($v === '..') {
116 6
            $v = '../';
117
        }
118
119
        // Trace to parent for ../ N times
120 599
        $v = preg_replace_callback('/\\.\\.\\//', function() use (&$levels) {
121 45
            $levels++;
122 45
            return '';
123 599
        }, trim($v));
124
125
        // remove ./ in path
126 599
        $v = preg_replace('/\\.\\//', '', $v);
127
128 599
        $strp = (($pos !== 0) && $context['flags']['strpar']);
129 599
        if ($levels && !$strp) {
130 42
            $ret[] = $levels;
131 42
            if (!$context['flags']['parent']) {
132 4
                $context['error'][] = 'Do not support {{../var}}, you should do compile with LightnCandy::FLAG_PARENT flag';
133
            }
134 42
            $context['usedFeature']['parent'] ++;
135
        }
136
137 599
        if ($context['flags']['advar'] && preg_match('/\\]/', $v)) {
138 31
            preg_match_all(static::VARNAME_SEARCH, $v, $matchedall);
139
        } else {
140 574
            preg_match_all('/([^\\.\\/]+)/', $v, $matchedall);
141
        }
142
143 599
        foreach ($matchedall[1] as $m) {
144 592
            if ($context['flags']['advar'] && substr($m, 0, 1) === '[') {
145 25
                $ret[] = substr($m, 1, -1);
146 585
            } else if ((!$context['flags']['this'] || ($m !== 'this')) && ($m !== '.')) {
147 592
                $ret[] = $m;
148
            }
149
        }
150
151 599
        if ($strp) {
152 10
            return array(0, "'" . implode('.', $ret) . "'");
153
        }
154
155 599
        return $ret;
156
    }
157
158
    /**
159
     * Parse the token and return parsed result.
160
     *
161
     * @param array<string> $token preg_match results
162
     * @param array<string,array|string|integer> $context current compile context
163
     *
164
     * @return array<boolean|integer|array> Return parsed result
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<boolean|array<boolean|integer|array>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
165
     *
166
     * @expect array(false, array(array())) when input array(0,0,0,0,0,0,0,''), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
167
     * @expect array(true, array(array())) when input array(0,0,0,'{{',0,'{',0,''), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
168
     * @expect array(true, array(array())) when input array(0,0,0,0,0,0,0,''), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 1), 'rawblock' => false)
169
     * @expect array(false, array(array('a'))) when input array(0,0,0,0,0,0,0,'a'), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
170
     * @expect array(false, array(array('a'), array('b'))) when input array(0,0,0,0,0,0,0,'a  b'), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
171
     * @expect array(false, array(array('a'), array('"b'), array('c"'))) when input array(0,0,0,0,0,0,0,'a "b c"'), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
172
     * @expect array(false, array(array('a'), array(0, '\'b c\''))) when input array(0,0,0,0,0,0,0,'a "b c"'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
173
     * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,0,'a [b c]'), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
174
     * @expect array(false, array(array('a'), array('[b'), array('c]'))) when input array(0,0,0,0,0,0,0,'a [b c]'), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
175
     * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,0,'a [b c]'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
176
     * @expect array(false, array(array('a'), array('b c'))) when input array(0,0,0,0,0,0,0,'a [b c]'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
177
     * @expect array(false, array(array('a'), 'q' => array('b c'))) when input array(0,0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
178
     * @expect array(false, array(array('a'), array('q=[b c'))) when input array(0,0,0,0,0,0,0,'a [q=[b c]'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
179
     * @expect array(false, array(array('a'), 'q' => array('[b'), array('c]'))) when input array(0,0,0,0,0,0,0,'a q=[b c]'), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
180
     * @expect array(false, array(array('a'), 'q' => array('b'), array('c'))) when input array(0,0,0,0,0,0,0,'a [q]=b c'), array('flags' => array('strpar' => 0, 'advar' => 0, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
181
     * @expect array(false, array(array('a'), 'q' => array(0, '\'b c\''))) when input array(0,0,0,0,0,0,0,'a q="b c"'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
182
     * @expect array(false, array(array(-1, array(array('foo'), array('bar')), '(foo bar)'))) when input array(0,0,0,0,0,0,0,'(foo bar)'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1, 'lambda' => 0), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'rawblock' => false)
183
     * @expect array(false, array(array('foo'), array("'=='"), array('bar'))) when input array(0,0,0,0,0,0,0,"foo '==' bar"), array('flags' => array('strpar' => 0, 'advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'rawblock' => false)
184
     * @expect array(false, array(array(-1, array(array('foo'), array('bar')), '( foo bar)'))) when input array(0,0,0,0,0,0,0,'( foo bar)'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 1, 'lambda' => 0), 'ops' => array('seperator' => ''), 'usedFeature' => array('subexp' => 0), 'rawblock' => false)
185
     * @expect array(false, array(array('a'), array(0, '\' b c\''))) when input array(0,0,0,0,0,0,0,'a " b c"'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 0, 'noesc' => 0), 'rawblock' => false)
186
     * @expect array(false, array(array('a'), 'q' => array(0, '\' b c\''))) when input array(0,0,0,0,0,0,0,'a q=" b c"'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
187
     * @expect array(false, array(array('foo'), array(0, "' =='"), array('bar'))) when input array(0,0,0,0,0,0,0,"foo \' ==\' bar"), array('flags' => array('strpar' => 0, 'advar' => 1, 'namev' => 1, 'noesc' => 0, 'this' => 0), 'rawblock' => false)
188
     * @expect array(false, array(array('a'), array(' b c'))) when input array(0,0,0,0,0,0,0,'a [ b c]'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
189
     * @expect array(false, array(array('a'), 'q' => array(0, "' d e'"))) when input array(0,0,0,0,0,0,0,"a q=\' d e\'"), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0), 'rawblock' => false)
190
     * @expect array(false, array('q' => array(-1, array(array('foo'), array('bar')), '( foo bar)'))) when input array(0,0,0,0,0,0,0,'q=( foo bar)'), array('flags' => array('strpar' => 0, 'advar' => 1, 'this' => 1, 'namev' => 1, 'noesc' => 0, 'exhlp' => 0, 'lambda' => 0), 'usedFeature' => array('subexp' => 0), 'ops' => array('seperator' => 0), 'rawblock' => false)
191
     */
192 623
    public static function parse(&$token, &$context) {
193 623
        $vars = static::analyze($token[static::POS_INNERTAG], $context);
194 623
        if ($token[static::POS_OP] === '>' && isset($vars[0])) {
195 69
            $fn = $vars[0];
196
        }
197
198 623
        $avars = static::advancedVariable($vars, $context, static::toString($token));
199
200 623
        if ($token[static::POS_OP] === '>' && isset($fn)) {
201 69
            $avars[0] = preg_match(SafeString::IS_SUBEXP_SEARCH, $fn) ? $avars[0] : array(preg_replace('/^("(.+)")|(\\[(.+)\\])$/', '$2$4', $fn));
202
        }
203
204 623
        return array(($token[static::POS_BEGINRAW] === '{') || ($token[static::POS_OP] === '&') || $context['flags']['noesc'] || $context['rawblock'], $avars);
205
    }
206
207
    /**
208
     * Parse a subexpression then return parsed result.
209
     *
210
     * @param string $expression the full string of a sub expression
211
     * @param array<string,array|string|integer> $context current compile context
212
     *
213
     * @return array<boolean|integer|array> Return parsed result
0 ignored issues
show
Documentation introduced by
Should the return type not be array<integer|array<bool...|integer|array>|string>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
214
     */
215 41
    public static function subexpression($expression, &$context) {
216 41
        $context['usedFeature']['subexp']++;
217 41
        $vars = static::analyze(substr($expression, 1, -1), $context);
218 41
        $avars = static::advancedVariable($vars, $context, $expression);
219 41
        if (isset($avars[0][0]) && !$context['flags']['exhlp']) {
220 21
            if (!Validator::helper($context, $avars[0][0])) {
221 2
                $context['error'][] = "Can not find custom helper function defination {$avars[0][0]}() !";
222
            }
223
        }
224 41
        return array(-1, $avars, $expression);
225
    }
226
227
    /**
228
     * Check a parsed result is a subexpression or not
229
     *
230
     * @param array<string|integer|array> $var
231
     *
232
     * @return boolean return true when input is a subexpression
233
     */
234 380
    public static function isSubExp($var) {
235 380
        return is_array($var) && (count($var) === 3) && ($var[0] === -1) && is_string($var[2]);
236
    }
237
238
    /**
239
     * Analyze parsed token for advanved variables.
240
     *
241
     * @param array<boolean|integer|array> $vars parsed token
242
     * @param array<string,array|string|integer> $context current compile context
243
     * @param string $token original token
244
     *
245
     * @return array<boolean|integer|array> Return parsed result
246
     *
247
     */
248 622
    protected static function advancedVariable($vars, &$context, $token) {
249 622
        $ret = array();
250 622
        $i = 0;
251 622
        foreach ($vars as $idx => $var) {
252
            // handle (...)
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
253 616
            if (preg_match(SafeString::IS_SUBEXP_SEARCH, $var)) {
254 36
                $ret[$i] = static::subexpression($var, $context);
255 36
                $i++;
256 36
                continue;
257
            }
258
259
            // handle |...|
1 ignored issue
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
260 616
            if (preg_match(SafeString::IS_BLOCKPARAM_SEARCH, $var, $matched)) {
261 6
                $ret[static::BLOCKPARAM] = explode(' ', $matched[1]);
262 6
                continue;
263
            }
264
265 616
            if ($context['flags']['namev']) {
266 410
                if (preg_match('/^((\\[([^\\]]+)\\])|([^=^["\']+))=(.+)$/', $var, $m)) {
267 38
                    if (!$context['flags']['advar'] && $m[3]) {
268 1
                        $context['error'][] = "Wrong argument name as '[$m[3]]' in $token ! You should fix your template or compile with LightnCandy::FLAG_ADVARNAME flag.";
269
                    }
270 38
                    $idx = $m[3] ? $m[3] : $m[4];
271 38
                    $var = $m[5];
272
                    // handle foo=(...)
1 ignored issue
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
273 38
                    if (preg_match(SafeString::IS_SUBEXP_SEARCH, $var)) {
274 6
                        $ret[$idx] = static::subexpression($var, $context);
275 6
                        continue;
276
                    }
277
                }
278
            }
279
280 616
            if ($context['flags']['advar'] && !preg_match("/^(\"|\\\\')(.*)(\"|\\\\')$/", $var)) {
281
                    // foo]  Rule 1: no starting [ or [ not start from head
282 425
                if (preg_match('/^[^\\[\\.]+[\\]\\[]/', $var)
283
                    // [bar  Rule 2: no ending ] or ] not in the end
284 419
                    || preg_match('/[\\[\\]][^\\]\\.]+$/', $var)
285
                    // ]bar. Rule 3: middle ] not before .
286 417
                    || preg_match('/\\][^\\]\\[\\.]+\\./', $var)
287
                    // .foo[ Rule 4: middle [ not after .
288 425
                    || preg_match('/\\.[^\\]\\[\\.]+\\[/', preg_replace('/^(..\\/)+/', '', preg_replace('/\\[[^\\]]+\\]/', '[XXX]', $var)))
289
                ) {
290 12
                    $context['error'][] = "Wrong variable naming as '$var' in $token !";
291
                } else {
292 413
                    $name = preg_replace('/(\\[.+?\\])/', '', $var);
293
                    // Scan for invalid charactors which not be protected by [ ]
294
                    // now make ( and ) pass, later fix
295 413
                    if (preg_match('/[!"#%\'*+,;<=>{|}~]/', $name)) {
296 2
                        $context['error'][] = "Wrong variable naming as '$var' in $token ! You should wrap ! \" # % & ' * + , ; < = > { | } ~ into [ ]";
297
                    }
298
                }
299
            }
300
301 616
            $var = static::getExpression($var, $context, $idx, count($vars));
302
303 616
            if (is_string($idx)) {
304 33
                $ret[$idx] = $var;
305
            } else {
306 615
                $ret[$i] = $var;
307 616
                $i++;
308
            }
309
        }
310 622
        return $ret;
311
    }
312
313
    /**
314
     * Analyze a token string and return parsed result.
315
     *
316
     * @param string $token preg_match results
317
     * @param array<string,array|string|integer> $context current compile context
318
     *
319
     * @return array<boolean|integer|array> Return parsed result
320
     *
321
     */
322 622
    protected static function analyze($token, &$context) {
323 622
        $count = preg_match_all('/(\s*)([^\s]+)/', $token, $matchedall);
324
        // Parse arguments and deal with "..." or [...] or (...) or \'...\' or |...|
1 ignored issue
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
325 622
        if (($count > 0) && $context['flags']['advar']) {
326 438
            $vars = array();
327 438
            $prev = '';
328 438
            $expect = 0;
329 438
            $stack = 0;
330
331 438
            foreach ($matchedall[2] as $index => $t) {
332
                // continue from previous match when expect something
333 438
                if ($expect) {
334 50
                    $prev .= "{$matchedall[1][$index]}$t";
335 50
                    if (($stack > 0) && (substr($t, 0, 1) === '(')) {
336 10
                        $stack++;
337
                    }
338
                    // end an argument when end with expected charactor
339 50
                    if (substr($t, -1, 1) === $expect) {
340 50
                        if ($stack > 0) {
341 40
                            preg_match('/(\\)+)$/', $t, $matchedq);
342 40
                            $stack -= isset($matchedq[0]) ? strlen($matchedq[0]) : 1;
343 40
                            if ($stack > 0) {
344 4
                                continue;
345
                            }
346 40
                            if ($stack < 0) {
347 1
                                $context['error'][] = "Unexcepted ')' in expression '$token' !!";
348 1
                                break;
349
                            }
350
                        }
351 49
                        $vars[] = $prev;
352 49
                        $prev = '';
353 49
                        $expect = 0;
354
                    }
355 50
                    continue;
356
                }
357
358
                // continue to next match when begin with '(' without ending ')'
359 438
                if (preg_match('/^\([^\)]*$/', $t)) {
360 30
                    $prev = $t;
361 30
                    $expect = ')';
362 30
                    $stack=1;
363 30
                    continue;
364
                }
365
366
                // continue to next match when begin with '"' without ending '"'
367 438
                if (preg_match('/^"[^"]*$/', $t)) {
368 6
                    $prev = $t;
369 6
                    $expect = '"';
370 6
                    continue;
371
                }
372
373
                // continue to next match when begin with \' without ending '
374 437
                if (preg_match('/^\\\\\'[^\']*$/', $t)) {
375 6
                    $prev = $t;
376 6
                    $expect = '\'';
377 6
                    continue;
378
                }
379
380
                // continue to next match when '="' exists without ending '"'
381 436
                if (preg_match('/^[^"]*="[^"]*$/', $t)) {
382 2
                    $prev = $t;
383 2
                    $expect = '"';
384 2
                    continue;
385
                }
386
387
                // continue to next match when '[' exists without ending ']'
388 436
                if (preg_match('/^([^"\'].+)?\\[[^\\]]*$/', $t)) {
389 9
                    $prev = $t;
390 9
                    $expect = ']';
391 9
                    continue;
392
                }
393
394
                // continue to next match when =\' exists without ending '
395 428
                if (preg_match('/^[^\']*=\\\\\'[^\']*$/', $t)) {
396 1
                    $prev = $t;
397 1
                    $expect = '\'';
398 1
                    continue;
399
                }
400
401
                // continue to next match when =( exists without ending )
402 428
                if (preg_match('/.+\([^\)]*$/', $t)) {
403 5
                    $prev = $t;
404 5
                    $expect = ')';
405 5
                    $stack=1;
406 5
                    continue;
407
                }
408
409
                // continue to next match when 'as' without ending '|'
410 428
                if (($t === 'as') && (count($vars) > 0)) {
411 6
                    $prev = '';
412 6
                    $expect = '|';
413 6
                    $stack=1;
414 6
                    continue;
415
                }
416
417 428
                $vars[] = $t;
418
            }
419 438
            return $vars;
420
        }
421 207
        return ($count > 0) ? $matchedall[2] : explode(' ', $token);
422
    }
423
}
424
425