| 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 |