Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
38.78% |
38 / 98 |
|
50.00% |
2 / 4 |
CRAP | |
0.00% |
0 / 1 |
Less_Exception_Chunk | |
38.78% |
38 / 98 |
|
50.00% |
2 / 4 |
576.76 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
Chunks | |
31.40% |
27 / 86 |
|
0.00% |
0 / 1 |
669.12 | |||
CharCode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
fail | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 |
1 | <?php |
2 | /** |
3 | * @private |
4 | */ |
5 | class Less_Exception_Chunk extends Less_Exception_Parser { |
6 | |
7 | protected $parserCurrentIndex = 0; |
8 | |
9 | protected $emitFrom = 0; |
10 | |
11 | protected $input_len; |
12 | |
13 | /** |
14 | * @param string $input |
15 | * @param Exception|null $previous Previous exception |
16 | * @param int|null $index The current parser index |
17 | * @param array|null $currentFile The file |
18 | * @param int $code The exception code |
19 | */ |
20 | public function __construct( $input, ?Exception $previous = null, $index = null, $currentFile = null, $code = 0 ) { |
21 | $this->message = 'ParseError: Unexpected input'; // default message |
22 | |
23 | $this->index = $index; |
24 | |
25 | $this->currentFile = $currentFile; |
26 | |
27 | $this->input = $input; |
28 | $this->input_len = strlen( $input ); |
29 | |
30 | $this->Chunks(); |
31 | $this->genMessage(); |
32 | } |
33 | |
34 | /** |
35 | * See less.js chunks() |
36 | * We don't actually need the chunks |
37 | */ |
38 | protected function Chunks() { |
39 | $level = 0; |
40 | $parenLevel = 0; |
41 | $lastMultiCommentEndBrace = null; |
42 | $lastOpening = null; |
43 | $lastMultiComment = null; |
44 | $lastParen = null; |
45 | |
46 | // phpcs:ignore Generic.CodeAnalysis.JumbledIncrementer |
47 | for ( $this->parserCurrentIndex = 0; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++ ) { |
48 | $cc = $this->CharCode( $this->parserCurrentIndex ); |
49 | if ( ( ( $cc >= 97 ) && ( $cc <= 122 ) ) || ( $cc < 34 ) ) { |
50 | // a-z or whitespace |
51 | continue; |
52 | } |
53 | |
54 | switch ( $cc ) { |
55 | |
56 | // ( |
57 | case 40: |
58 | $parenLevel++; |
59 | $lastParen = $this->parserCurrentIndex; |
60 | break; |
61 | |
62 | // ) |
63 | case 41: |
64 | $parenLevel--; |
65 | if ( $parenLevel < 0 ) { |
66 | return $this->fail( "missing opening `(`" ); |
67 | } |
68 | break; |
69 | |
70 | // ; |
71 | case 59: |
72 | // if (!$parenLevel) { $this->emitChunk(); } |
73 | break; |
74 | |
75 | // { |
76 | case 123: |
77 | $level++; |
78 | $lastOpening = $this->parserCurrentIndex; |
79 | break; |
80 | |
81 | // } |
82 | case 125: |
83 | $level--; |
84 | if ( $level < 0 ) { |
85 | return $this->fail( "missing opening `{`" ); |
86 | |
87 | } |
88 | // if (!$level && !$parenLevel) { $this->emitChunk(); } |
89 | break; |
90 | // \ |
91 | case 92: |
92 | if ( $this->parserCurrentIndex < $this->input_len - 1 ) { |
93 | $this->parserCurrentIndex++; |
94 | break; |
95 | } |
96 | return $this->fail( "unescaped `\\`" ); |
97 | |
98 | // ", ' and ` |
99 | case 34: |
100 | case 39: |
101 | case 96: |
102 | $matched = 0; |
103 | $currentChunkStartIndex = $this->parserCurrentIndex; |
104 | for ( $this->parserCurrentIndex += 1; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++ ) { |
105 | $cc2 = $this->CharCode( $this->parserCurrentIndex ); |
106 | if ( $cc2 > 96 ) { |
107 | continue; |
108 | } |
109 | if ( $cc2 == $cc ) { |
110 | $matched = 1; |
111 | break; |
112 | } |
113 | if ( $cc2 == 92 ) { // \ |
114 | if ( $this->parserCurrentIndex == $this->input_len - 1 ) { |
115 | return $this->fail( "unescaped `\\`" ); |
116 | } |
117 | $this->parserCurrentIndex++; |
118 | } |
119 | } |
120 | if ( $matched ) { |
121 | break; |
122 | } |
123 | return $this->fail( "unmatched `" . chr( $cc ) . "`", $currentChunkStartIndex ); |
124 | |
125 | // /, check for comment |
126 | case 47: |
127 | if ( $parenLevel || ( $this->parserCurrentIndex == $this->input_len - 1 ) ) { |
128 | break; |
129 | } |
130 | $cc2 = $this->CharCode( $this->parserCurrentIndex + 1 ); |
131 | if ( $cc2 == 47 ) { |
132 | // //, find lnfeed |
133 | for ( $this->parserCurrentIndex += 2; $this->parserCurrentIndex < $this->input_len; $this->parserCurrentIndex++ ) { |
134 | $cc2 = $this->CharCode( $this->parserCurrentIndex ); |
135 | if ( ( $cc2 <= 13 ) && ( ( $cc2 == 10 ) || ( $cc2 == 13 ) ) ) { |
136 | break; |
137 | } |
138 | } |
139 | } elseif ( $cc2 == 42 ) { |
140 | // /*, find */ |
141 | $lastMultiComment = $currentChunkStartIndex = $this->parserCurrentIndex; |
142 | for ( $this->parserCurrentIndex += 2; $this->parserCurrentIndex < $this->input_len - 1; $this->parserCurrentIndex++ ) { |
143 | $cc2 = $this->CharCode( $this->parserCurrentIndex ); |
144 | if ( $cc2 == 125 ) { |
145 | $lastMultiCommentEndBrace = $this->parserCurrentIndex; |
146 | } |
147 | if ( $cc2 != 42 ) { |
148 | continue; |
149 | } |
150 | if ( $this->CharCode( $this->parserCurrentIndex + 1 ) == 47 ) { |
151 | break; |
152 | } |
153 | } |
154 | if ( $this->parserCurrentIndex == $this->input_len - 1 ) { |
155 | return $this->fail( "missing closing `*/`", $currentChunkStartIndex ); |
156 | } |
157 | } |
158 | break; |
159 | |
160 | // *, check for unmatched */ |
161 | case 42: |
162 | if ( ( $this->parserCurrentIndex < $this->input_len - 1 ) && ( $this->CharCode( $this->parserCurrentIndex + 1 ) == 47 ) ) { |
163 | return $this->fail( "unmatched `/*`" ); |
164 | } |
165 | break; |
166 | } |
167 | } |
168 | |
169 | if ( $level !== 0 ) { |
170 | if ( ( $lastMultiComment > $lastOpening ) && ( $lastMultiCommentEndBrace > $lastMultiComment ) ) { |
171 | return $this->fail( "missing closing `}` or `*/`", $lastOpening ); |
172 | } else { |
173 | return $this->fail( "missing closing `}`", $lastOpening ); |
174 | } |
175 | } elseif ( $parenLevel !== 0 ) { |
176 | return $this->fail( "missing closing `)`", $lastParen ); |
177 | } |
178 | |
179 | // chunk didn't fail |
180 | |
181 | //$this->emitChunk(true); |
182 | } |
183 | |
184 | public function CharCode( $pos ) { |
185 | return ord( $this->input[$pos] ); |
186 | } |
187 | |
188 | public function fail( $msg, $index = null ) { |
189 | if ( !$index ) { |
190 | $this->index = $this->parserCurrentIndex; |
191 | } else { |
192 | $this->index = $index; |
193 | } |
194 | $this->message = 'ParseError: ' . $msg; |
195 | } |
196 | |
197 | /* |
198 | function emitChunk( $force = false ){ |
199 | $len = $this->parserCurrentIndex - $this->emitFrom; |
200 | if ((($len < 512) && !$force) || !$len) { |
201 | return; |
202 | } |
203 | $chunks[] = substr($this->input, $this->emitFrom, $this->parserCurrentIndex + 1 - $this->emitFrom ); |
204 | $this->emitFrom = $this->parserCurrentIndex + 1; |
205 | } |
206 | */ |
207 | |
208 | } |