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