LEFT | RIGHT |
1 // Output an JsonML codec for the AST | |
2 | |
3 // Explanation of a node: | |
4 // { | |
5 // type: The type of the node | |
6 // location: "line:col-line:col" | |
7 // } | |
8 /** | |
9 * Node formats: | |
10 * Program | |
11 * sourceElements: Array of elements (functions, statements) | |
12 * FunctionDeclaration | |
13 * name: Name of the function | |
14 * arguments: Array of arguments | |
15 * body: Array of elements in function body | |
16 * VarStatement | |
17 * variables: Variables being initialized | |
18 * VarDeclaration | |
19 * name: Name of variable | |
20 * initializer: Initial value of variable | |
21 * CallExpression | |
22 * func: Name of the function being called | |
23 * arguments: Array of arguments | |
24 * IdentifierExpression | |
25 * name: Name of identifier | |
26 * LiteralExpression | |
27 * objtype: "null", "boolean", "numeric", "string", "regex" | |
28 * value: Value of the literal | |
29 * BinaryExpression | |
30 * operator: operator (e.g., '|', '+') | |
31 + lhs, rhs: left-hand, right-hand expressions for the operator | |
32 */ | |
33 include("../utils/dumpast.js"); | |
34 | |
35 function makeAST(pn) { | |
36 let ast = shellNode(pn, "Program"); | |
37 ast.sourceElements = parseToAst(pn).statements; | |
38 return ast; | |
39 } | |
40 | |
41 // Broken things: | |
42 // * Generators (i for (i in foo), not array comp) | |
43 // * let {a: x, b: y} = baz(); | |
44 // * let (x = 5, y = 12) {} (really!) | |
45 // * function ( {a: 1, b: 2} ) | |
46 // * E4x | |
47 | |
48 let structure = { | |
49 // Program : SourceElement* | |
50 "Program": [ "sourceElements" ], | |
51 // SourceElement : FunctionDeclaration | Statement | |
52 // FunctionDeclaration : function [name] ( Parameter * ) { SourceElement * } | |
53 "FunctionDeclaration": [ "arguments", "body" ], | |
54 "Parameter": [ ], // name: Parameter name | |
55 | |
56 // Statements | |
57 "BlockStatement": [ "statements" ], | |
58 "VarStatement": [ "variables" ], | |
59 "VarDeclaration": [ "initializer" ], // name: name of variable | |
60 "LetStatement": [ "variables", "body" ], | |
61 "EmptyStatement": [], | |
62 "ExpressionStatement": [ "expr" ], | |
63 "IfStatement": [ "cond", "body", "elsebody" ], | |
64 "DoWhileStatement": [ "cond", "body" ], | |
65 "WhileStatement": [ "cond", "body" ], | |
66 "ForStatement": [ "init", "cond", "inc", "body" ], | |
67 "ForInStatement": [ "itervar", "iterrange", "body" ], // itertype: for (each) | |
68 "ContinueStatement": [ ], // label: label to break to | |
69 "BreakStatement": [ ], // label: label to break to | |
70 "ReturnStatement": [ "expr" ], | |
71 "WithStatement": [ "variable", "body" ], | |
72 "LabeledStatement": [ "body" ], // label: label of statement | |
73 "SwitchStatement": [ "expr", "cases" ], | |
74 "SwitchCase": [ "expr", "body"], // default: no expr | |
75 "ThrowStatement": [ "expr" ], | |
76 "TryStatement": [ "body", "catchers", "fin" ], | |
77 "CatchStatement": [ "variable", "cond", "body" ], | |
78 "DebuggerStatement": [ ], | |
79 | |
80 // Expressions (all have a precedence attribute, 0 (primary) -17) | |
81 "ThisExpression": [], | |
82 "LiteralExpression": [], // objtype: typeof literal, value: value | |
83 "ObjectLiteral": [ "setters" ], | |
84 "PropertyLiteral": [ "property", "value" ], // proptype: getter, setter, not | |
85 "ArrayLiteral": [ "members" ], | |
86 "ArrayComprehensionExpression": [ "element", "itervar", "iterrange", | |
87 "iterif" ], // itertype | |
88 "IdentifierExpression": [], // name: name of node | |
89 "MemberExpression": [ "container", "member"], //constmember if constant | |
90 "NewExpression": [ "constructor", "arguments" ], | |
91 "CallExpression": [ "func", "arguments" ], | |
92 "PostfixExpression": [ "operand" ], // operator | |
93 // XXX: jorendorff says yield is weird precedence | |
94 // For now, it's an unary with precedence = 16 | |
95 "UnaryExpression": [ "operand" ], // operator | |
96 "BinaryExpression": [ "lhs", "rhs" ], // operator | |
97 "ConditionalExpression": [ "cond", "iftrue", "iffalse" ], | |
98 "AssignmentExpression": [ "lhs", "rhs" ], // operator | |
99 }; | |
100 function walkAST(ast, visitor) { | |
101 function astVisitor(node) { | |
102 let info = structure[node.type]; | |
103 if (!info) | |
104 throw "Need to define " + node.type; | |
105 let cback = "visit" + node.type; | |
106 let deep = false; | |
107 if (cback in visitor) | |
108 deep = visitor[cback](node); | |
109 if (!deep) { | |
110 for (let part of info) { | |
111 let piece = node[part]; | |
112 if (piece instanceof Array) { | |
113 piece.map(astVisitor); | |
114 } else if (piece) { | |
115 astVisitor(piece); | |
116 } | |
117 } | |
118 } | |
119 cback = "post" + cback; | |
120 if (cback in visitor) | |
121 visitor[cback](node); | |
122 } | |
123 astVisitor(ast); | |
124 } | |
125 | |
126 function getLocation(pn) { | |
127 return pn.line + ":" + pn.column; | |
128 } | |
129 function shellNode(pn, type) { | |
130 function visit(visitor) { | |
131 return walkAST(this, visitor); | |
132 } | |
133 return {type: type, location: getLocation(pn), visit: visit }; | |
134 } | |
135 function binaryNode(pn, operator, precedence) { | |
136 let ast = shellNode(pn, "BinaryExpression"); | |
137 ast.precedence = precedence; | |
138 ast.operator = operator; | |
139 ast.lhs = parseToAst(pn.kids[0]); | |
140 ast.rhs = parseToAst(pn.kids[1]); | |
141 for (let i = 2; i < pn.kids.length; i++) { | |
142 let sup = shellNode(pn.kids[i], "BinaryExpression"); | |
143 sup.precedence = precedence; | |
144 sup.operator = operator; | |
145 sup.lhs = ast; | |
146 sup.rhs = parseToAst(pn.kids[i]); | |
147 ast = sup; | |
148 } | |
149 return ast; | |
150 } | |
151 | |
152 function parseToAst(pn) { | |
153 if (!pn) | |
154 return pn; | |
155 try { | |
156 return global["convert" + decode_type(pn.type)](pn); | |
157 } catch (e if e instanceof TypeError) { | |
158 dump_ast(pn); | |
159 throw e; | |
160 //throw "Unexpected token " + decode_type(pn.type); | |
161 } | |
162 } | |
163 | |
164 // Nodes that I don't see in output | |
165 // TOK_ERROR, TOK_EOL, TOK_ELSE, TOK_FINALLY, TOK_SEQ | |
166 // TOK_XMLSTAGO - TOK_XMLLIST are XML and thus ignored | |
167 | |
168 function convertTOK_SEMI(pn) { | |
169 let ast = shellNode(pn, "ExpressionStatement"); | |
170 if (pn.kids[0]) | |
171 ast.expr = parseToAst(pn.kids[0]); | |
172 else { | |
173 ast.type = "EmptyStatement"; | |
174 } | |
175 return ast; | |
176 } | |
177 | |
178 function convertTOK_COMMA(pn) { | |
179 if (pn.kids.length == 0) { | |
180 let ast = shellNode(pn, "EmptyExpression"); | |
181 ast.precedence = 17; | |
182 return ast; | |
183 } else { | |
184 return binaryNode(pn, ",", 17); | |
185 } | |
186 } | |
187 | |
188 function convertTOK_ASSIGN(pn) { | |
189 let ast = shellNode(pn, "AssignmentExpression"); | |
190 ast.precedence = 16; | |
191 ast.lhs = parseToAst(pn.kids[0]); | |
192 ast.rhs = parseToAst(pn.kids[1]); | |
193 switch (pn.op) { | |
194 case JSOP_NOP: ast.operator = ''; break; | |
195 case JSOP_BITOR: ast.operator = '|'; break; | |
196 case JSOP_BITXOR: ast.operator = '^'; break; | |
197 case JSOP_BITAND: ast.operator = '&'; break; | |
198 case JSOP_LSH: ast.operator = '<<'; break; | |
199 case JSOP_RSH: ast.operator = '>>'; break; | |
200 case JSOP_URSH: ast.operator = '>>>'; break; | |
201 case JSOP_ADD: ast.operator = '+'; break; | |
202 case JSOP_SUB: ast.operator = '-'; break; | |
203 case JSOP_MUL: ast.operator = '*'; break; | |
204 case JSOP_DIV: ast.operator = '/'; break; | |
205 case JSOP_MOD: ast.operator = '%'; break; | |
206 default: throw "Unexpected operator " + decode_op(pn.op); | |
207 }; | |
208 return ast; | |
209 } | |
210 | |
211 function convertTOK_HOOK(pn) { | |
212 let ast = shellNode(pn, "ConditionalExpression"); | |
213 ast.precedence = 15; | |
214 ast.cond = parseToAst(pn.kids[0]); | |
215 ast.iftrue = parseToAst(pn.kids[1]); | |
216 ast.iffalse = parseToAst(pn.kids[2]); | |
217 return ast; | |
218 } | |
219 | |
220 function convertTOK_COLON(pn) { | |
221 if (pn.kids.length == 1) { | |
222 let ast = shellNode(pn, "LabeledStatement"); | |
223 ast.label = pn.atom; | |
224 ast.body = parseToAst(pn.kids[0]); | |
225 return ast; | |
226 } | |
227 let ast = shellNode(pn, "PropertyLiteral"); | |
228 ast.property = parseToAst(pn.kids[0]); | |
229 ast.value = parseToAst(pn.kids[1]); | |
230 if (pn.op == JSOP_GETTER) | |
231 ast.proptype = "getter"; | |
232 else if (pn.op == JSOP_SETTER) | |
233 ast.proptype = "setter"; | |
234 return ast; | |
235 } | |
236 | |
237 function convertTOK_OR(pn) { return binaryNode(pn, "||", 14); } | |
238 function convertTOK_AND(pn) { return binaryNode(pn, "&&", 13); } | |
239 function convertTOK_BITOR(pn) { return binaryNode(pn, "|", 12); } | |
240 function convertTOK_BITXOR(pn) { return binaryNode(pn, "^", 11); } | |
241 function convertTOK_BITAND(pn) { return binaryNode(pn, "&", 10); } | |
242 function convertTOK_EQOP(pn) { | |
243 switch (pn.op) { | |
244 case JSOP_EQ: return binaryNode(pn, "==", 9); | |
245 case JSOP_NE: return binaryNode(pn, "!=", 9); | |
246 case JSOP_STRICTEQ: return binaryNode(pn, "===", 9); | |
247 case JSOP_STRICTNE: return binaryNode(pn, "!==", 9); | |
248 } | |
249 throw "Unknown operator: " + decode_op(pn.op); | |
250 } | |
251 function convertTOK_RELOP(pn) { | |
252 switch (pn.op) { | |
253 case JSOP_LT: return binaryNode(pn, "<", 8); | |
254 case JSOP_LE: return binaryNode(pn, "<=", 8); | |
255 case JSOP_GT: return binaryNode(pn, ">", 8); | |
256 case JSOP_GE: return binaryNode(pn, ">=", 8); | |
257 } | |
258 throw "Unknown operator: " + decode_op(pn.op); | |
259 } | |
260 function convertTOK_SHOP(pn) { | |
261 switch (pn.op) { | |
262 case JSOP_LSH: return binaryNode(pn, "<<", 7); | |
263 case JSOP_RSH: return binaryNode(pn, ">>", 7); | |
264 case JSOP_URSH: return binaryNode(pn, ">>>", 7); | |
265 } | |
266 throw "Unknown operator: " + decode_op(pn.op); | |
267 } | |
268 function convertTOK_PLUS(pn) { return binaryNode(pn, "+", 6); } | |
269 function convertTOK_MINUS(pn) { return binaryNode(pn, "-", 6); } | |
270 function convertTOK_STAR(pn) { return binaryNode(pn, "*", 5); } | |
271 function convertTOK_DIVOP(pn) { | |
272 switch (pn.op) { | |
273 case JSOP_MUL: return binaryNode(pn, "*", 5); | |
274 case JSOP_DIV: return binaryNode(pn, "/", 5); | |
275 case JSOP_MOD: return binaryNode(pn, "%", 5); | |
276 } | |
277 throw "Unknown operator: " + decode_op(pn.op); | |
278 } | |
279 function convertTOK_UNARYOP(pn) { | |
280 let ast = shellNode(pn, "UnaryExpression"); | |
281 ast.precedence = 4; | |
282 ast.operand = parseToAst(pn.kids[0]); | |
283 switch (pn.op) { | |
284 case JSOP_NEG: ast.operator = "-"; break; | |
285 case JSOP_POS: ast.operator = "+"; break; | |
286 case JSOP_NOT: ast.operator = "!"; break; | |
287 case JSOP_BITNOT: ast.operator = "~"; break; | |
288 case JSOP_TYPEOF: ast.operator = "typeof"; break; | |
289 case JSOP_VOID: ast.operator = "void"; break; | |
290 case JSOP_TYPEOFEXPR: ast.operator = "typeof"; break; | |
291 default: | |
292 throw "Unknown operator: " + decode_op(pn.op); | |
293 } | |
294 return ast; | |
295 } | |
296 function convertTOK_INC(pn) { return convertPrePost(pn, '++'); } | |
297 function convertTOK_DEC(pn) { return convertPrePost(pn, '--'); } | |
298 function convertPrePost(pn, op) { | |
299 let ast = shellNode(pn, "UnaryExpression"); | |
300 ast.precedence = 3; | |
301 ast.operator = op; | |
302 ast.operand = parseToAst(pn.kids[0]); | |
303 switch (pn.op) { | |
304 case JSOP_INCNAME: | |
305 case JSOP_INCPROP: | |
306 case JSOP_INCELEM: | |
307 case JSOP_DECNAME: | |
308 case JSOP_DECPROP: | |
309 case JSOP_DECELEM: | |
310 /*ast.type = "PrefixExpression";*/ break; | |
311 case JSOP_NAMEINC: | |
312 case JSOP_PROPINC: | |
313 case JSOP_ELEMINC: | |
314 case JSOP_NAMEDEC: | |
315 case JSOP_PROPDEC: | |
316 case JSOP_ELEMDEC: | |
317 ast.type = "PostfixExpression"; break; | |
318 default: | |
319 throw "Unknown operator: " + decode_op(pn.op); | |
320 } | |
321 return ast; | |
322 } | |
323 | |
324 function convertTOK_DOT(pn) { | |
325 let ast = shellNode(pn, "MemberExpression"); | |
326 ast.precedence = 1; | |
327 ast.container = parseToAst(pn.kids[0]); | |
328 ast.member = shellNode(pn, "LiteralExpression"); | |
329 ast.member.objtype = "string"; | |
330 ast.member.value = pn.atom; | |
331 ast.constmember = pn.atom; | |
332 return ast; | |
333 } | |
334 | |
335 function convertTOK_LB(pn) { | |
336 let ast = shellNode(pn, "MemberExpression"); | |
337 ast.precedence = 1; | |
338 ast.container = parseToAst(pn.kids[0]); | |
339 ast.member = parseToAst(pn.kids[1]); | |
340 return ast; | |
341 } | |
342 | |
343 function convertTOK_RB(pn) { | |
344 let ast = shellNode(pn, "ArrayLiteral"); | |
345 ast.precedence = 0; | |
346 ast.members = pn.kids.map(parseToAst); | |
347 return ast; | |
348 } | |
349 | |
350 /* Returns a list */ | |
351 function convertTOK_LC(pn) { | |
352 let ast = shellNode(pn, "BlockStatement"); | |
353 ast.statements = pn.kinds.map(parseToAst); | |
354 if (ast.statements.length == 0) { | |
355 return shellNode(pn, "EmptyStatement"); | |
356 } | |
357 return ast; | |
358 } | |
359 | |
360 function convertTOK_RC(pn) { | |
361 let ast = shellNode(pn, "ObjectLiteral"); | |
362 ast.setters = pn.kids.map(parseToAst); | |
363 return ast; | |
364 } | |
365 | |
366 function convertTOK_LP(pn) { | |
367 if (pn.op != JSOP_CALL && pn.op != JSOP_APPLY) { | |
368 let ast = shellNode(pn, "LetStatement"); | |
369 ast.variables = pn.kids.map(parseToAst); | |
370 return ast; | |
371 } | |
372 let ast = shellNode(pn, "CallExpression"); | |
373 ast.precedence = 2; | |
374 ast.func = parseToAst(pn.kids[0]); | |
375 ast.arguments = []; | |
376 for (let i = 1; i < pn.kids.length; i++) | |
377 ast.arguments[i - 1] = parseToAst(pn.kids[i]); | |
378 return ast; | |
379 } | |
380 | |
381 function convertTOK_RP(pn) { | |
382 let ast = shellNode(pn, "UnaryExpression"); | |
383 ast.precedence = 2; | |
384 ast.operand = parseToAst(pn.kids[0]); | |
385 ast.operator = "()"; | |
386 return ast; | |
387 } | |
388 | |
389 function convertTOK_NAME(pn) { | |
390 let ast = shellNode(pn, "IdentifierExpression"); | |
391 ast.precedence = 0; | |
392 ast.name = pn.atom; | |
393 if (pn.kids.length > 0 && pn.kids[0]) { | |
394 ast.initializer = parseToAst(pn.kids[0]); | |
395 } | |
396 return ast; | |
397 } | |
398 | |
399 | |
400 function convertTOK_NUMBER(pn) { | |
401 let ast = shellNode(pn, "LiteralExpression"); | |
402 ast.precedence = 0; | |
403 ast.objtype = "number"; | |
404 ast.value = pn.value; | |
405 return ast; | |
406 } | |
407 | |
408 function convertTOK_STRING(pn) { | |
409 let ast = shellNode(pn, "LiteralExpression"); | |
410 ast.precedence = 0; | |
411 ast.objtype = "string"; | |
412 ast.value = pn.atom; | |
413 return ast; | |
414 } | |
415 | |
416 function convertTOK_REGEXP(pn) { | |
417 let ast = shellNode(pn, "LiteralExpression"); | |
418 ast.precedence = 0; | |
419 ast.objtype = "regex"; | |
420 ast.value = pn.value; | |
421 return ast; | |
422 } | |
423 | |
424 function convertTOK_PRIMARY(pn) { | |
425 let ast = shellNode(pn, "LiteralExpression"); | |
426 ast.precedence = 0; | |
427 switch (pn.op) { | |
428 case JSOP_ZERO: ast.objtype = "number"; ast.value = 0; break; | |
429 case JSOP_ONE: ast.objtype = "number"; ast.value = 1; break; | |
430 case JSOP_NULL: ast.objtype = "null"; ast.value = null; break; | |
431 case JSOP_FALSE: ast.objtype = "boolean"; ast.value = false; break; | |
432 case JSOP_TRUE: ast.objtype = "boolean"; ast.value = true; break; | |
433 case JSOP_THIS: | |
434 return shellNode(pn, "ThisExpression"); | |
435 default: | |
436 throw "Unknown operand: " + decode_op(pn.op); | |
437 } | |
438 return ast; | |
439 } | |
440 | |
441 function convertTOK_FUNCTION(pn) { | |
442 let ast = shellNode(pn, "FunctionDeclaration"); | |
443 // Precedence needs to be highest -> always wrapped | |
444 ast.precedence = 1.0 / 0.0; | |
445 ast.name = pn.name; | |
446 if (pn.kids[0].type == TOK_UPVARS) | |
447 pn = pn.kids[0]; | |
448 let args = []; | |
449 if (pn.kids[0].type == TOK_ARGSBODY) { | |
450 pn = pn.kids[0]; | |
451 while (pn.kids.length > 1) { | |
452 let argNode = parseToAst(pn.kids.shift()); | |
453 argNode.type = "Parameter"; | |
454 args.push(argNode); | |
455 } | |
456 } | |
457 ast.arguments = args; | |
458 ast.body = parseToAst(pn.kids[0]); | |
459 return ast; | |
460 } | |
461 | |
462 function convertTOK_IF(pn) { | |
463 let ast = shellNode(pn, "IfStatement"); | |
464 ast.cond = parseToAst(pn.kids[0]); | |
465 ast.body = parseToAst(pn.kids[1]); | |
466 if (pn.kids[1]) | |
467 ast.elsebody = parseToAst(pn.kids[2]); | |
468 return ast; | |
469 } | |
470 | |
471 | |
472 function convertTOK_SWITCH(pn) { | |
473 let ast = shellNode(pn, "SwitchStatement"); | |
474 ast.expr = parseToAst(pn.kids[0]); | |
475 let rhs = parseToAst(pn.kids[1]); | |
476 if (rhs instanceof Array) | |
477 ast.cases = rhs; | |
478 else | |
479 ast.cases = rhs.statements; | |
480 return ast; | |
481 } | |
482 | |
483 function convertTOK_CASE(pn) { | |
484 let ast = shellNode(pn, "SwitchCase"); | |
485 ast.expr = parseToAst(pn.kids[0]); | |
486 ast.body = parseToAst(pn.kids[1]); | |
487 return ast; | |
488 } | |
489 function convertTOK_DEFAULT(pn) { | |
490 let ast = shellNode(pn, "SwitchCase"); | |
491 ast.body = parseToAst(pn.kids[1]); | |
492 return ast; | |
493 } | |
494 | |
495 function convertTOK_WHILE(pn) { | |
496 let ast = shellNode(pn, "WhileStatement"); | |
497 ast.cond = parseToAst(pn.kids[0]); | |
498 ast.body = parseToAst(pn.kids[1]); | |
499 return ast; | |
500 } | |
501 function convertTOK_DO(pn) { | |
502 let ast = shellNode(pn, "DoWhileStatement"); | |
503 ast.body = parseToAst(pn.kids[0]); | |
504 ast.cond = parseToAst(pn.kids[1]); | |
505 return ast; | |
506 } | |
507 | |
508 function convertTOK_FOR(pn) { | |
509 let ast = shellNode(pn, "ForStatement"); | |
510 let expr = parseToAst(pn.kids[0]); | |
511 if (expr.type == "Forehead") { | |
512 ast.init = expr.init; | |
513 ast.cond = expr.condition; | |
514 ast.inc = expr.increment; | |
515 } else { | |
516 ast.type = "ForInStatement"; | |
517 ast.itervar = expr.lhs; | |
518 ast.iterrange = expr.rhs; | |
519 ast.itertype = (pn.iflags & 0x2 ? "for each" : "for"); | |
520 } | |
521 ast.body = parseToAst(pn.kids[1]); | |
522 return ast; | |
523 } | |
524 | |
525 function convertTOK_BREAK(pn) { | |
526 let ast = shellNode(pn, "BreakStatement"); | |
527 if (pn.atom) | |
528 ast.label = pn.atom; | |
529 return ast; | |
530 } | |
531 function convertTOK_CONTINUE(pn) { | |
532 let ast = shellNode(pn, "ContinueStatement"); | |
533 if (pn.atom) | |
534 ast.label = pn.atom; | |
535 return ast; | |
536 } | |
537 | |
538 function convertTOK_IN(pn) { return binaryNode(pn, "in", 8); } | |
539 | |
540 function convertTOK_VAR(pn) { | |
541 let ast = shellNode(pn, "VarStatement"); | |
542 if (pn.op == JSOP_DEFCONST) | |
543 ast.vartype = "const"; | |
544 else | |
545 ast.vartype = "var"; | |
546 ast.variables = pn.kids.map(parseToAst); | |
547 for (let x of ast.variables) { | |
548 if (x.type == "LetStatement") | |
549 return x; | |
550 if (x.type == "IdentifierExpression") | |
551 x.type = "VarDeclaration"; | |
552 } | |
553 return ast; | |
554 } | |
555 | |
556 function convertTOK_WITH(pn) { | |
557 let ast = shellNode(pn, "WithStatement"); | |
558 ast.variable = parseToAst(pn.kids[0]); | |
559 ast.body = parseToAst(pn.kids[1]); | |
560 return ast; | |
561 } | |
562 | |
563 function convertTOK_RETURN(pn) { | |
564 let ast = shellNode(pn, "ReturnStatement"); | |
565 ast.expr = parseToAst(pn.kids[0]); | |
566 return ast; | |
567 } | |
568 | |
569 function convertTOK_NEW(pn) { | |
570 let ast = shellNode(pn, "NewExpression"); | |
571 ast.precedence = 1; | |
572 ast.constructor = parseToAst(pn.kids[0]); | |
573 ast.arguments = []; | |
574 for (let i = 1; i < pn.kids.length; i++) | |
575 ast.arguments.push(parseToAst(pn.kids[i])); | |
576 return ast; | |
577 } | |
578 | |
579 function convertTOK_DELETE(pn) { | |
580 let ast = shellNode(pn, "UnaryExpression"); | |
581 ast.precedence = 4; | |
582 ast.operator = "delete"; | |
583 ast.operand = parseToAst(pn.kids[0]); | |
584 return ast; | |
585 } | |
586 | |
587 function convertTOK_DEFSHARP(pn) { | |
588 let ast = shellNode(pn, "SharpDefinitionExpression"); | |
589 ast.expr = parseToAst(pn.kids[0]); | |
590 ast.sharpnum = pn.number; | |
591 return ast; | |
592 } | |
593 function convertTOK_USESHARP(pn) { | |
594 let ast = shellNode(pn, "SharpExpression"); | |
595 ast.sharpnum = pn.number; | |
596 return ast; | |
597 } | |
598 | |
599 function convertTOK_TRY(pn) { | |
600 let ast = shellNode(pn, "TryStatement"); | |
601 ast.body = parseToAst(pn.kids[0]); | |
602 if (pn.kids[1]) | |
603 ast.catchers = parseToAst(pn.kids[1]); | |
604 else | |
605 ast.catchers = []; | |
606 if (pn.kids[2]) | |
607 ast.fin = parseToAst(pn.kids[2]); | |
608 return ast; | |
609 } | |
610 | |
611 function convertTOK_CATCH(pn) { | |
612 let ast = shellNode(pn, "CatchStatement"); | |
613 ast.variable = parseToAst(pn.kids[0]); | |
614 if (pn.kids[1]) | |
615 ast.cond = parseToAst(pn.kids[1]); | |
616 ast.body = parseToAst(pn.kids[2]); | |
617 return ast; | |
618 } | |
619 | |
620 function convertTOK_THROW(pn) { | |
621 let ast = shellNode(pn, "ThrowStatement"); | |
622 ast.expr = parseToAst(pn.kids[0]); | |
623 return ast; | |
624 } | |
625 | |
626 function convertTOK_INSTANCEOF(pn) { return binaryNode(pn, "instanceof", 8); } | |
627 | |
628 function convertTOK_DEBUGGER(pn) { return shellNode(pn, "DebuggerStatement"); } | |
629 // XML OPS | |
630 | |
631 function convertTOK_YIELD(pn) { | |
632 let ast = shellNode(pn, "UnaryExpression"); | |
633 ast.operand = parseToAst(pn.kids[0]); | |
634 ast.precedence = 16; | |
635 ast.operator = "yield"; | |
636 return ast; | |
637 } | |
638 | |
639 function convertTOK_ARRAYCOMP(pn) { | |
640 let ast = parseToAst(pn.kids[0]); | |
641 ast.precedence = 0; | |
642 ast.type = "ArrayComprehensionExpression"; | |
643 if ("expr" in ast.body) | |
644 ast.element = ast.body.expr; | |
645 else { | |
646 ast.element = ast.body.body.expr; | |
647 ast.iterif = ast.body.cond; | |
648 } | |
649 delete ast.body; | |
650 return ast; | |
651 } | |
652 | |
653 function convertTOK_ARRAYPUSH(pn) { | |
654 let ast = shellNode(pn, "ArrayPush"); | |
655 ast.expr = parseToAst(pn.kids[0]); | |
656 return ast; | |
657 } | |
658 | |
659 function convertTOK_LEXICALSCOPE(pn) { | |
660 return parseToAst(pn.kids[0]); | |
661 } | |
662 | |
663 function convertTOK_LET(pn) { | |
664 let ast = convertTOK_VAR(pn); | |
665 if (ast.type == "VarStatement") | |
666 ast.vartype = "let"; | |
667 return ast; | |
668 } | |
669 | |
670 function convertTOK_FORHEAD(pn) { | |
671 let ast = shellNode(pn, "Forehead"); | |
672 ast.init = pn.kids[0] ? parseToAst(pn.kids[0]) : | |
673 shellNode(pn, "EmptyStatement"); | |
674 ast.condition = pn.kids[1] ? parseToAst(pn.kids[1]) : | |
675 shellNode(pn, "EmptyStatement"); | |
676 ast.increment = pn.kids[2] ? parseToAst(pn.kids[2]) : | |
677 shellNode(pn, "EmptyStatement"); | |
678 return ast; | |
679 } | |
680 | |
681 function convertTOK_RESERVED(pn) { | |
682 return pn.kids.map(parseToAst); | |
683 } | |
LEFT | RIGHT |