Mercurial > hg > cmmr2012-drupal-site
comparison vendor/nikic/php-parser/grammar/rebuildParsers.php @ 0:c75dbcec494b
Initial commit from drush-created site
author | Chris Cannam |
---|---|
date | Thu, 05 Jul 2018 14:24:15 +0000 |
parents | |
children | a9cd425dd02b |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c75dbcec494b |
---|---|
1 <?php | |
2 | |
3 $grammarFileToName = [ | |
4 __DIR__ . '/php5.y' => 'Php5', | |
5 __DIR__ . '/php7.y' => 'Php7', | |
6 ]; | |
7 | |
8 $tokensFile = __DIR__ . '/tokens.y'; | |
9 $tokensTemplate = __DIR__ . '/tokens.template'; | |
10 $skeletonFile = __DIR__ . '/parser.template'; | |
11 $tmpGrammarFile = __DIR__ . '/tmp_parser.phpy'; | |
12 $tmpResultFile = __DIR__ . '/tmp_parser.php'; | |
13 $resultDir = __DIR__ . '/../lib/PhpParser/Parser'; | |
14 $tokensResultsFile = $resultDir . '/Tokens.php'; | |
15 | |
16 // check for kmyacc.exe binary in this directory, otherwise fall back to global name | |
17 $kmyacc = __DIR__ . '/kmyacc.exe'; | |
18 if (!file_exists($kmyacc)) { | |
19 $kmyacc = 'kmyacc'; | |
20 } | |
21 | |
22 $options = array_flip($argv); | |
23 $optionDebug = isset($options['--debug']); | |
24 $optionKeepTmpGrammar = isset($options['--keep-tmp-grammar']); | |
25 | |
26 /////////////////////////////// | |
27 /// Utility regex constants /// | |
28 /////////////////////////////// | |
29 | |
30 const LIB = '(?(DEFINE) | |
31 (?<singleQuotedString>\'[^\\\\\']*+(?:\\\\.[^\\\\\']*+)*+\') | |
32 (?<doubleQuotedString>"[^\\\\"]*+(?:\\\\.[^\\\\"]*+)*+") | |
33 (?<string>(?&singleQuotedString)|(?&doubleQuotedString)) | |
34 (?<comment>/\*[^*]*+(?:\*(?!/)[^*]*+)*+\*/) | |
35 (?<code>\{[^\'"/{}]*+(?:(?:(?&string)|(?&comment)|(?&code)|/)[^\'"/{}]*+)*+}) | |
36 )'; | |
37 | |
38 const PARAMS = '\[(?<params>[^[\]]*+(?:\[(?¶ms)\][^[\]]*+)*+)\]'; | |
39 const ARGS = '\((?<args>[^()]*+(?:\((?&args)\)[^()]*+)*+)\)'; | |
40 | |
41 /////////////////// | |
42 /// Main script /// | |
43 /////////////////// | |
44 | |
45 $tokens = file_get_contents($tokensFile); | |
46 | |
47 foreach ($grammarFileToName as $grammarFile => $name) { | |
48 echo "Building temporary $name grammar file.\n"; | |
49 | |
50 $grammarCode = file_get_contents($grammarFile); | |
51 $grammarCode = str_replace('%tokens', $tokens, $grammarCode); | |
52 | |
53 $grammarCode = resolveNodes($grammarCode); | |
54 $grammarCode = resolveMacros($grammarCode); | |
55 $grammarCode = resolveStackAccess($grammarCode); | |
56 | |
57 file_put_contents($tmpGrammarFile, $grammarCode); | |
58 | |
59 $additionalArgs = $optionDebug ? '-t -v' : ''; | |
60 | |
61 echo "Building $name parser.\n"; | |
62 $output = trim(shell_exec("$kmyacc $additionalArgs -l -m $skeletonFile -p $name $tmpGrammarFile 2>&1")); | |
63 echo "Output: \"$output\"\n"; | |
64 | |
65 $resultCode = file_get_contents($tmpResultFile); | |
66 $resultCode = removeTrailingWhitespace($resultCode); | |
67 | |
68 ensureDirExists($resultDir); | |
69 file_put_contents("$resultDir/$name.php", $resultCode); | |
70 unlink($tmpResultFile); | |
71 | |
72 echo "Building token definition.\n"; | |
73 $output = trim(shell_exec("$kmyacc -l -m $tokensTemplate $tmpGrammarFile 2>&1")); | |
74 assert($output === ''); | |
75 rename($tmpResultFile, $tokensResultsFile); | |
76 | |
77 if (!$optionKeepTmpGrammar) { | |
78 unlink($tmpGrammarFile); | |
79 } | |
80 } | |
81 | |
82 /////////////////////////////// | |
83 /// Preprocessing functions /// | |
84 /////////////////////////////// | |
85 | |
86 function resolveNodes($code) { | |
87 return preg_replace_callback( | |
88 '~\b(?<name>[A-Z][a-zA-Z_\\\\]++)\s*' . PARAMS . '~', | |
89 function($matches) { | |
90 // recurse | |
91 $matches['params'] = resolveNodes($matches['params']); | |
92 | |
93 $params = magicSplit( | |
94 '(?:' . PARAMS . '|' . ARGS . ')(*SKIP)(*FAIL)|,', | |
95 $matches['params'] | |
96 ); | |
97 | |
98 $paramCode = ''; | |
99 foreach ($params as $param) { | |
100 $paramCode .= $param . ', '; | |
101 } | |
102 | |
103 return 'new ' . $matches['name'] . '(' . $paramCode . 'attributes())'; | |
104 }, | |
105 $code | |
106 ); | |
107 } | |
108 | |
109 function resolveMacros($code) { | |
110 return preg_replace_callback( | |
111 '~\b(?<!::|->)(?!array\()(?<name>[a-z][A-Za-z]++)' . ARGS . '~', | |
112 function($matches) { | |
113 // recurse | |
114 $matches['args'] = resolveMacros($matches['args']); | |
115 | |
116 $name = $matches['name']; | |
117 $args = magicSplit( | |
118 '(?:' . PARAMS . '|' . ARGS . ')(*SKIP)(*FAIL)|,', | |
119 $matches['args'] | |
120 ); | |
121 | |
122 if ('attributes' == $name) { | |
123 assertArgs(0, $args, $name); | |
124 return '$this->startAttributeStack[#1] + $this->endAttributes'; | |
125 } | |
126 | |
127 if ('stackAttributes' == $name) { | |
128 assertArgs(1, $args, $name); | |
129 return '$this->startAttributeStack[' . $args[0] . ']' | |
130 . ' + $this->endAttributeStack[' . $args[0] . ']'; | |
131 } | |
132 | |
133 if ('init' == $name) { | |
134 return '$$ = array(' . implode(', ', $args) . ')'; | |
135 } | |
136 | |
137 if ('push' == $name) { | |
138 assertArgs(2, $args, $name); | |
139 | |
140 return $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0]; | |
141 } | |
142 | |
143 if ('pushNormalizing' == $name) { | |
144 assertArgs(2, $args, $name); | |
145 | |
146 return 'if (is_array(' . $args[1] . ')) { $$ = array_merge(' . $args[0] . ', ' . $args[1] . '); }' | |
147 . ' else { ' . $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0] . '; }'; | |
148 } | |
149 | |
150 if ('toArray' == $name) { | |
151 assertArgs(1, $args, $name); | |
152 | |
153 return 'is_array(' . $args[0] . ') ? ' . $args[0] . ' : array(' . $args[0] . ')'; | |
154 } | |
155 | |
156 if ('parseVar' == $name) { | |
157 assertArgs(1, $args, $name); | |
158 | |
159 return 'substr(' . $args[0] . ', 1)'; | |
160 } | |
161 | |
162 if ('parseEncapsed' == $name) { | |
163 assertArgs(3, $args, $name); | |
164 | |
165 return 'foreach (' . $args[0] . ' as $s) { if ($s instanceof Node\Scalar\EncapsedStringPart) {' | |
166 . ' $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, ' . $args[1] . ', ' . $args[2] . '); } }'; | |
167 } | |
168 | |
169 if ('parseEncapsedDoc' == $name) { | |
170 assertArgs(2, $args, $name); | |
171 | |
172 return 'foreach (' . $args[0] . ' as $s) { if ($s instanceof Node\Scalar\EncapsedStringPart) {' | |
173 . ' $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, null, ' . $args[1] . '); } }' | |
174 . ' $s->value = preg_replace(\'~(\r\n|\n|\r)\z~\', \'\', $s->value);' | |
175 . ' if (\'\' === $s->value) array_pop(' . $args[0] . ');'; | |
176 } | |
177 | |
178 if ('makeNop' == $name) { | |
179 assertArgs(3, $args, $name); | |
180 | |
181 return '$startAttributes = ' . $args[1] . ';' | |
182 . ' if (isset($startAttributes[\'comments\']))' | |
183 . ' { ' . $args[0] . ' = new Stmt\Nop($startAttributes + ' . $args[2] . '); }' | |
184 . ' else { ' . $args[0] . ' = null; }'; | |
185 } | |
186 | |
187 if ('strKind' == $name) { | |
188 assertArgs(1, $args, $name); | |
189 | |
190 return '(' . $args[0] . '[0] === "\'" || (' . $args[0] . '[1] === "\'" && ' | |
191 . '(' . $args[0] . '[0] === \'b\' || ' . $args[0] . '[0] === \'B\')) ' | |
192 . '? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED)'; | |
193 } | |
194 | |
195 if ('setDocStringAttrs' == $name) { | |
196 assertArgs(2, $args, $name); | |
197 | |
198 return $args[0] . '[\'kind\'] = strpos(' . $args[1] . ', "\'") === false ' | |
199 . '? Scalar\String_::KIND_HEREDOC : Scalar\String_::KIND_NOWDOC; ' | |
200 . 'preg_match(\'/\A[bB]?<<<[ \t]*[\\\'"]?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)[\\\'"]?(?:\r\n|\n|\r)\z/\', ' . $args[1] . ', $matches); ' | |
201 . $args[0] . '[\'docLabel\'] = $matches[1];'; | |
202 } | |
203 | |
204 if ('prependLeadingComments' == $name) { | |
205 assertArgs(1, $args, $name); | |
206 | |
207 return '$attrs = $this->startAttributeStack[#1]; $stmts = ' . $args[0] . '; ' | |
208 . 'if (!empty($attrs[\'comments\'])) {' | |
209 . '$stmts[0]->setAttribute(\'comments\', ' | |
210 . 'array_merge($attrs[\'comments\'], $stmts[0]->getAttribute(\'comments\', []))); }'; | |
211 } | |
212 | |
213 return $matches[0]; | |
214 }, | |
215 $code | |
216 ); | |
217 } | |
218 | |
219 function assertArgs($num, $args, $name) { | |
220 if ($num != count($args)) { | |
221 die('Wrong argument count for ' . $name . '().'); | |
222 } | |
223 } | |
224 | |
225 function resolveStackAccess($code) { | |
226 $code = preg_replace('/\$\d+/', '$this->semStack[$0]', $code); | |
227 $code = preg_replace('/#(\d+)/', '$$1', $code); | |
228 return $code; | |
229 } | |
230 | |
231 function removeTrailingWhitespace($code) { | |
232 $lines = explode("\n", $code); | |
233 $lines = array_map('rtrim', $lines); | |
234 return implode("\n", $lines); | |
235 } | |
236 | |
237 function ensureDirExists($dir) { | |
238 if (!is_dir($dir)) { | |
239 mkdir($dir, 0777, true); | |
240 } | |
241 } | |
242 | |
243 ////////////////////////////// | |
244 /// Regex helper functions /// | |
245 ////////////////////////////// | |
246 | |
247 function regex($regex) { | |
248 return '~' . LIB . '(?:' . str_replace('~', '\~', $regex) . ')~'; | |
249 } | |
250 | |
251 function magicSplit($regex, $string) { | |
252 $pieces = preg_split(regex('(?:(?&string)|(?&comment)|(?&code))(*SKIP)(*FAIL)|' . $regex), $string); | |
253 | |
254 foreach ($pieces as &$piece) { | |
255 $piece = trim($piece); | |
256 } | |
257 | |
258 if ($pieces === ['']) { | |
259 return []; | |
260 } | |
261 | |
262 return $pieces; | |
263 } |