1/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ 3/* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6"use strict"; 7 8const Cu = Components.utils; 9 10const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); 11const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); 12const { console } = require("resource://gre/modules/Console.jsm"); 13const DevToolsUtils = require("devtools/shared/DevToolsUtils"); 14 15XPCOMUtils.defineLazyModuleGetter(this, 16 "Reflect", "resource://gre/modules/reflect.jsm"); 17 18this.EXPORTED_SYMBOLS = ["Parser", "ParserHelpers", "SyntaxTreeVisitor"]; 19 20/** 21 * A JS parser using the reflection API. 22 */ 23this.Parser = function Parser() { 24 this._cache = new Map(); 25 this.errors = []; 26 this.logExceptions = true; 27}; 28 29Parser.prototype = { 30 /** 31 * Gets a collection of parser methods for a specified source. 32 * 33 * @param string source 34 * The source text content. 35 * @param string url [optional] 36 * The source url. The AST nodes will be cached, so you can use this 37 * identifier to avoid parsing the whole source again. 38 */ 39 get(source, url = "") { 40 // Try to use the cached AST nodes, to avoid useless parsing operations. 41 if (this._cache.has(url)) { 42 return this._cache.get(url); 43 } 44 45 // The source may not necessarily be JS, in which case we need to extract 46 // all the scripts. Fastest/easiest way is with a regular expression. 47 // Don't worry, the rules of using a <script> tag are really strict, 48 // this will work. 49 let regexp = /<script[^>]*?(?:>([^]*?)<\/script\s*>|\/>)/gim; 50 let syntaxTrees = []; 51 let scriptMatches = []; 52 let scriptMatch; 53 54 if (source.match(/^\s*</)) { 55 // First non whitespace character is <, so most definitely HTML. 56 while ((scriptMatch = regexp.exec(source))) { 57 // Contents are captured at index 1 or nothing: Self-closing scripts 58 // won't capture code content 59 scriptMatches.push(scriptMatch[1] || ""); 60 } 61 } 62 63 // If there are no script matches, send the whole source directly to the 64 // reflection API to generate the AST nodes. 65 if (!scriptMatches.length) { 66 // Reflect.parse throws when encounters a syntax error. 67 try { 68 let nodes = Reflect.parse(source); 69 let length = source.length; 70 syntaxTrees.push(new SyntaxTree(nodes, url, length)); 71 } catch (e) { 72 this.errors.push(e); 73 if (this.logExceptions) { 74 DevToolsUtils.reportException(url, e); 75 } 76 } 77 } else { 78 // Generate the AST nodes for each script. 79 for (let script of scriptMatches) { 80 // Reflect.parse throws when encounters a syntax error. 81 try { 82 let nodes = Reflect.parse(script); 83 let offset = source.indexOf(script); 84 let length = script.length; 85 syntaxTrees.push(new SyntaxTree(nodes, url, length, offset)); 86 } catch (e) { 87 this.errors.push(e); 88 if (this.logExceptions) { 89 DevToolsUtils.reportException(url, e); 90 } 91 } 92 } 93 } 94 95 let pool = new SyntaxTreesPool(syntaxTrees, url); 96 97 // Cache the syntax trees pool by the specified url. This is entirely 98 // optional, but it's strongly encouraged to cache ASTs because 99 // generating them can be costly with big/complex sources. 100 if (url) { 101 this._cache.set(url, pool); 102 } 103 104 return pool; 105 }, 106 107 /** 108 * Clears all the parsed sources from cache. 109 */ 110 clearCache() { 111 this._cache.clear(); 112 }, 113 114 /** 115 * Clears the AST for a particular source. 116 * 117 * @param String url 118 * The URL of the source that is being cleared. 119 */ 120 clearSource(url) { 121 this._cache.delete(url); 122 }, 123 124 _cache: null, 125 errors: null 126}; 127 128/** 129 * A pool handling a collection of AST nodes generated by the reflection API. 130 * 131 * @param object syntaxTrees 132 * A collection of AST nodes generated for a source. 133 * @param string url [optional] 134 * The source url. 135 */ 136function SyntaxTreesPool(syntaxTrees, url = "<unknown>") { 137 this._trees = syntaxTrees; 138 this._url = url; 139 this._cache = new Map(); 140} 141 142SyntaxTreesPool.prototype = { 143 /** 144 * @see SyntaxTree.prototype.getIdentifierAt 145 */ 146 getIdentifierAt({ line, column, scriptIndex, ignoreLiterals }) { 147 return this._call("getIdentifierAt", 148 scriptIndex, line, column, ignoreLiterals)[0]; 149 }, 150 151 /** 152 * @see SyntaxTree.prototype.getNamedFunctionDefinitions 153 */ 154 getNamedFunctionDefinitions(substring) { 155 return this._call("getNamedFunctionDefinitions", -1, substring); 156 }, 157 158 /** 159 * @return SyntaxTree 160 * The last tree in this._trees 161 */ 162 getLastSyntaxTree() { 163 return this._trees[this._trees.length - 1]; 164 }, 165 166 /** 167 * Gets the total number of scripts in the parent source. 168 * @return number 169 */ 170 get scriptCount() { 171 return this._trees.length; 172 }, 173 174 /** 175 * Finds the start and length of the script containing the specified offset 176 * relative to its parent source. 177 * 178 * @param number atOffset 179 * The offset relative to the parent source. 180 * @return object 181 * The offset and length relative to the enclosing script. 182 */ 183 getScriptInfo(atOffset) { 184 let info = { start: -1, length: -1, index: -1 }; 185 186 for (let { offset, length } of this._trees) { 187 info.index++; 188 if (offset <= atOffset && offset + length >= atOffset) { 189 info.start = offset; 190 info.length = length; 191 return info; 192 } 193 } 194 195 info.index = -1; 196 return info; 197 }, 198 199 /** 200 * Handles a request for a specific or all known syntax trees. 201 * 202 * @param string functionName 203 * The function name to call on the SyntaxTree instances. 204 * @param number syntaxTreeIndex 205 * The syntax tree for which to handle the request. If the tree at 206 * the specified index isn't found, the accumulated results for all 207 * syntax trees are returned. 208 * @param any params 209 * Any kind params to pass to the request function. 210 * @return array 211 * The results given by all known syntax trees. 212 */ 213 _call(functionName, syntaxTreeIndex, ...params) { 214 let results = []; 215 let requestId = [functionName, syntaxTreeIndex, params].toSource(); 216 217 if (this._cache.has(requestId)) { 218 return this._cache.get(requestId); 219 } 220 221 let requestedTree = this._trees[syntaxTreeIndex]; 222 let targettedTrees = requestedTree ? [requestedTree] : this._trees; 223 224 for (let syntaxTree of targettedTrees) { 225 try { 226 let parseResults = syntaxTree[functionName].apply(syntaxTree, params); 227 if (parseResults) { 228 parseResults.sourceUrl = syntaxTree.url; 229 parseResults.scriptLength = syntaxTree.length; 230 parseResults.scriptOffset = syntaxTree.offset; 231 results.push(parseResults); 232 } 233 } catch (e) { 234 // Can't guarantee that the tree traversal logic is forever perfect :) 235 // Language features may be added, in which case the recursive methods 236 // need to be updated. If an exception is thrown here, file a bug. 237 DevToolsUtils.reportException( 238 `Syntax tree visitor for ${this._url}`, e); 239 } 240 } 241 this._cache.set(requestId, results); 242 return results; 243 }, 244 245 _trees: null, 246 _cache: null 247}; 248 249/** 250 * A collection of AST nodes generated by the reflection API. 251 * 252 * @param object nodes 253 * The AST nodes. 254 * @param string url 255 * The source url. 256 * @param number length 257 * The total number of chars of the parsed script in the parent source. 258 * @param number offset [optional] 259 * The char offset of the parsed script in the parent source. 260 */ 261function SyntaxTree(nodes, url, length, offset = 0) { 262 this.AST = nodes; 263 this.url = url; 264 this.length = length; 265 this.offset = offset; 266} 267 268SyntaxTree.prototype = { 269 /** 270 * Gets the identifier at the specified location. 271 * 272 * @param number line 273 * The line in the source. 274 * @param number column 275 * The column in the source. 276 * @param boolean ignoreLiterals 277 * Specifies if alone literals should be ignored. 278 * @return object 279 * An object containing identifier information as { name, location, 280 * evalString } properties, or null if nothing is found. 281 */ 282 getIdentifierAt(line, column, ignoreLiterals) { 283 let info = null; 284 285 SyntaxTreeVisitor.walk(this.AST, { 286 /** 287 * Callback invoked for each identifier node. 288 * @param Node node 289 */ 290 onIdentifier(node) { 291 if (ParserHelpers.nodeContainsPoint(node, line, column)) { 292 info = { 293 name: node.name, 294 location: ParserHelpers.getNodeLocation(node), 295 evalString: ParserHelpers.getIdentifierEvalString(node) 296 }; 297 298 // Abruptly halt walking the syntax tree. 299 SyntaxTreeVisitor.break = true; 300 } 301 }, 302 303 /** 304 * Callback invoked for each literal node. 305 * @param Node node 306 */ 307 onLiteral(node) { 308 if (!ignoreLiterals) { 309 this.onIdentifier(node); 310 } 311 }, 312 313 /** 314 * Callback invoked for each 'this' node. 315 * @param Node node 316 */ 317 onThisExpression(node) { 318 this.onIdentifier(node); 319 } 320 }); 321 322 return info; 323 }, 324 325 /** 326 * Searches for all function definitions (declarations and expressions) 327 * whose names (or inferred names) contain a string. 328 * 329 * @param string substring 330 * The string to be contained in the function name (or inferred name). 331 * Can be an empty string to match all functions. 332 * @return array 333 * All the matching function declarations and expressions, as 334 * { functionName, functionLocation ... } object hashes. 335 */ 336 getNamedFunctionDefinitions(substring) { 337 let lowerCaseToken = substring.toLowerCase(); 338 let store = []; 339 340 function includesToken(name) { 341 return name && name.toLowerCase().includes(lowerCaseToken); 342 } 343 344 SyntaxTreeVisitor.walk(this.AST, { 345 /** 346 * Callback invoked for each function declaration node. 347 * @param Node node 348 */ 349 onFunctionDeclaration(node) { 350 let functionName = node.id.name; 351 if (includesToken(functionName)) { 352 store.push({ 353 functionName: functionName, 354 functionLocation: ParserHelpers.getNodeLocation(node) 355 }); 356 } 357 }, 358 359 /** 360 * Callback invoked for each function expression node. 361 * @param Node node 362 */ 363 onFunctionExpression(node) { 364 // Function expressions don't necessarily have a name. 365 let functionName = node.id ? node.id.name : ""; 366 let functionLocation = ParserHelpers.getNodeLocation(node); 367 368 // Infer the function's name from an enclosing syntax tree node. 369 let inferredInfo = ParserHelpers.inferFunctionExpressionInfo(node); 370 let inferredName = inferredInfo.name; 371 let inferredChain = inferredInfo.chain; 372 let inferredLocation = inferredInfo.loc; 373 374 // Current node may be part of a larger assignment expression stack. 375 if (node._parent.type == "AssignmentExpression") { 376 this.onFunctionExpression(node._parent); 377 } 378 379 if (includesToken(functionName) || includesToken(inferredName)) { 380 store.push({ 381 functionName: functionName, 382 functionLocation: functionLocation, 383 inferredName: inferredName, 384 inferredChain: inferredChain, 385 inferredLocation: inferredLocation 386 }); 387 } 388 }, 389 390 /** 391 * Callback invoked for each arrow expression node. 392 * @param Node node 393 */ 394 onArrowFunctionExpression(node) { 395 // Infer the function's name from an enclosing syntax tree node. 396 let inferredInfo = ParserHelpers.inferFunctionExpressionInfo(node); 397 let inferredName = inferredInfo.name; 398 let inferredChain = inferredInfo.chain; 399 let inferredLocation = inferredInfo.loc; 400 401 // Current node may be part of a larger assignment expression stack. 402 if (node._parent.type == "AssignmentExpression") { 403 this.onFunctionExpression(node._parent); 404 } 405 406 if (includesToken(inferredName)) { 407 store.push({ 408 inferredName: inferredName, 409 inferredChain: inferredChain, 410 inferredLocation: inferredLocation 411 }); 412 } 413 } 414 }); 415 416 return store; 417 }, 418 419 AST: null, 420 url: "", 421 length: 0, 422 offset: 0 423}; 424 425/** 426 * Parser utility methods. 427 */ 428var ParserHelpers = { 429 /** 430 * Gets the location information for a node. Not all nodes have a 431 * location property directly attached, or the location information 432 * is incorrect, in which cases it's accessible via the parent. 433 * 434 * @param Node node 435 * The node who's location needs to be retrieved. 436 * @return object 437 * An object containing { line, column } information. 438 */ 439 getNodeLocation(node) { 440 if (node.type != "Identifier") { 441 return node.loc; 442 } 443 // Work around the fact that some identifier nodes don't have the 444 // correct location attached. 445 let { loc: parentLocation, type: parentType } = node._parent; 446 let { loc: nodeLocation } = node; 447 if (!nodeLocation) { 448 if (parentType == "FunctionDeclaration" || 449 parentType == "FunctionExpression") { 450 // e.g. "function foo() {}" or "{ bar: function foo() {} }" 451 // The location is unavailable for the identifier node "foo". 452 let loc = Cu.cloneInto(parentLocation, {}); 453 loc.end.line = loc.start.line; 454 loc.end.column = loc.start.column + node.name.length; 455 return loc; 456 } 457 if (parentType == "MemberExpression") { 458 // e.g. "foo.bar" 459 // The location is unavailable for the identifier node "bar". 460 let loc = Cu.cloneInto(parentLocation, {}); 461 loc.start.line = loc.end.line; 462 loc.start.column = loc.end.column - node.name.length; 463 return loc; 464 } 465 if (parentType == "LabeledStatement") { 466 // e.g. label: ... 467 // The location is unavailable for the identifier node "label". 468 let loc = Cu.cloneInto(parentLocation, {}); 469 loc.end.line = loc.start.line; 470 loc.end.column = loc.start.column + node.name.length; 471 return loc; 472 } 473 if (parentType == "ContinueStatement" || parentType == "BreakStatement") { 474 // e.g. continue label; or break label; 475 // The location is unavailable for the identifier node "label". 476 let loc = Cu.cloneInto(parentLocation, {}); 477 loc.start.line = loc.end.line; 478 loc.start.column = loc.end.column - node.name.length; 479 return loc; 480 } 481 } else if (parentType == "VariableDeclarator") { 482 // e.g. "let foo = 42" 483 // The location incorrectly spans across the whole variable declaration, 484 // not just the identifier node "foo". 485 let loc = Cu.cloneInto(nodeLocation, {}); 486 loc.end.line = loc.start.line; 487 loc.end.column = loc.start.column + node.name.length; 488 return loc; 489 } 490 return node.loc; 491 }, 492 493 /** 494 * Checks if a node's bounds contains a specified line. 495 * 496 * @param Node node 497 * The node's bounds used as reference. 498 * @param number line 499 * The line number to check. 500 * @return boolean 501 * True if the line and column is contained in the node's bounds. 502 */ 503 nodeContainsLine(node, line) { 504 let { start: s, end: e } = this.getNodeLocation(node); 505 return s.line <= line && e.line >= line; 506 }, 507 508 /** 509 * Checks if a node's bounds contains a specified line and column. 510 * 511 * @param Node node 512 * The node's bounds used as reference. 513 * @param number line 514 * The line number to check. 515 * @param number column 516 * The column number to check. 517 * @return boolean 518 * True if the line and column is contained in the node's bounds. 519 */ 520 nodeContainsPoint(node, line, column) { 521 let { start: s, end: e } = this.getNodeLocation(node); 522 return s.line == line && e.line == line && 523 s.column <= column && e.column >= column; 524 }, 525 526 /** 527 * Try to infer a function expression's name & other details based on the 528 * enclosing VariableDeclarator, AssignmentExpression or ObjectExpression. 529 * 530 * @param Node node 531 * The function expression node to get the name for. 532 * @return object 533 * The inferred function name, or empty string can't infer the name, 534 * along with the chain (a generic "context", like a prototype chain) 535 * and location if available. 536 */ 537 inferFunctionExpressionInfo(node) { 538 let parent = node._parent; 539 540 // A function expression may be defined in a variable declarator, 541 // e.g. var foo = function(){}, in which case it is possible to infer 542 // the variable name. 543 if (parent.type == "VariableDeclarator") { 544 return { 545 name: parent.id.name, 546 chain: null, 547 loc: this.getNodeLocation(parent.id) 548 }; 549 } 550 551 // Function expressions can also be defined in assignment expressions, 552 // e.g. foo = function(){} or foo.bar = function(){}, in which case it is 553 // possible to infer the assignee name ("foo" and "bar" respectively). 554 if (parent.type == "AssignmentExpression") { 555 let propertyChain = this._getMemberExpressionPropertyChain(parent.left); 556 let propertyLeaf = propertyChain.pop(); 557 return { 558 name: propertyLeaf, 559 chain: propertyChain, 560 loc: this.getNodeLocation(parent.left) 561 }; 562 } 563 564 // If a function expression is defined in an object expression, 565 // e.g. { foo: function(){} }, then it is possible to infer the name 566 // from the corresponding property. 567 if (parent.type == "ObjectExpression") { 568 let propertyKey = this._getObjectExpressionPropertyKeyForValue(node); 569 let propertyChain = this._getObjectExpressionPropertyChain(parent); 570 let propertyLeaf = propertyKey.name; 571 return { 572 name: propertyLeaf, 573 chain: propertyChain, 574 loc: this.getNodeLocation(propertyKey) 575 }; 576 } 577 578 // Can't infer the function expression's name. 579 return { 580 name: "", 581 chain: null, 582 loc: null 583 }; 584 }, 585 586 /** 587 * Gets the name of an object expression's property to which a specified 588 * value is assigned. 589 * 590 * Used for inferring function expression information and retrieving 591 * an identifier evaluation string. 592 * 593 * For example, if "node" represents the "bar" identifier in a hypothetical 594 * "{ foo: bar }" object expression, the returned node is the "foo" 595 * identifier. 596 * 597 * @param Node node 598 * The value node in an object expression. 599 * @return object 600 * The key identifier node in the object expression. 601 */ 602 _getObjectExpressionPropertyKeyForValue(node) { 603 let parent = node._parent; 604 if (parent.type != "ObjectExpression") { 605 return null; 606 } 607 for (let property of parent.properties) { 608 if (property.value == node) { 609 return property.key; 610 } 611 } 612 return null; 613 }, 614 615 /** 616 * Gets an object expression's property chain to its parent 617 * variable declarator or assignment expression, if available. 618 * 619 * Used for inferring function expression information and retrieving 620 * an identifier evaluation string. 621 * 622 * For example, if node represents the "baz: {}" object expression in a 623 * hypothetical "foo = { bar: { baz: {} } }" assignment expression, the 624 * returned chain is ["foo", "bar", "baz"]. 625 * 626 * @param Node node 627 * The object expression node to begin the scan from. 628 * @param array aStore [optional] 629 * The chain to store the nodes into. 630 * @return array 631 * The chain to the parent variable declarator, as strings. 632 */ 633 _getObjectExpressionPropertyChain(node, aStore = []) { 634 switch (node.type) { 635 case "ObjectExpression": 636 this._getObjectExpressionPropertyChain(node._parent, aStore); 637 let propertyKey = this._getObjectExpressionPropertyKeyForValue(node); 638 if (propertyKey) { 639 aStore.push(propertyKey.name); 640 } 641 break; 642 // Handle "var foo = { ... }" variable declarators. 643 case "VariableDeclarator": 644 aStore.push(node.id.name); 645 break; 646 // Handle "foo.bar = { ... }" assignment expressions, since they're 647 // commonly used when defining an object's prototype methods; e.g: 648 // "Foo.prototype = { ... }". 649 case "AssignmentExpression": 650 this._getMemberExpressionPropertyChain(node.left, aStore); 651 break; 652 // Additionally handle stuff like "foo = bar.baz({ ... })", because it's 653 // commonly used in prototype-based inheritance in many libraries; e.g: 654 // "Foo = Bar.extend({ ... })". 655 case "NewExpression": 656 case "CallExpression": 657 this._getObjectExpressionPropertyChain(node._parent, aStore); 658 break; 659 } 660 return aStore; 661 }, 662 663 /** 664 * Gets a member expression's property chain. 665 * 666 * Used for inferring function expression information and retrieving 667 * an identifier evaluation string. 668 * 669 * For example, if node represents a hypothetical "foo.bar.baz" 670 * member expression, the returned chain ["foo", "bar", "baz"]. 671 * 672 * More complex expressions like foo.bar().baz are intentionally not handled. 673 * 674 * @param Node node 675 * The member expression node to begin the scan from. 676 * @param array store [optional] 677 * The chain to store the nodes into. 678 * @return array 679 * The full member chain, as strings. 680 */ 681 _getMemberExpressionPropertyChain(node, store = []) { 682 switch (node.type) { 683 case "MemberExpression": 684 this._getMemberExpressionPropertyChain(node.object, store); 685 this._getMemberExpressionPropertyChain(node.property, store); 686 break; 687 case "ThisExpression": 688 store.push("this"); 689 break; 690 case "Identifier": 691 store.push(node.name); 692 break; 693 } 694 return store; 695 }, 696 697 /** 698 * Returns an evaluation string which can be used to obtain the 699 * current value for the respective identifier. 700 * 701 * @param Node node 702 * The leaf node (e.g. Identifier, Literal) to begin the scan from. 703 * @return string 704 * The corresponding evaluation string, or empty string if 705 * the specified leaf node can't be used. 706 */ 707 getIdentifierEvalString(node) { 708 switch (node._parent.type) { 709 case "ObjectExpression": 710 // If the identifier is the actual property value, it can be used 711 // directly as an evaluation string. Otherwise, construct the property 712 // access chain, since the value might have changed. 713 if (!this._getObjectExpressionPropertyKeyForValue(node)) { 714 let propertyChain = 715 this._getObjectExpressionPropertyChain(node._parent); 716 let propertyLeaf = node.name; 717 return [...propertyChain, propertyLeaf].join("."); 718 } 719 break; 720 case "MemberExpression": 721 // Make sure this is a property identifier, not the parent object. 722 if (node._parent.property == node) { 723 return this._getMemberExpressionPropertyChain(node._parent).join("."); 724 } 725 break; 726 } 727 switch (node.type) { 728 case "ThisExpression": 729 return "this"; 730 case "Identifier": 731 return node.name; 732 case "Literal": 733 return uneval(node.value); 734 default: 735 return ""; 736 } 737 } 738}; 739 740/** 741 * A visitor for a syntax tree generated by the reflection API. 742 * See https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API. 743 * 744 * All node types implement the following interface: 745 * interface Node { 746 * type: string; 747 * loc: SourceLocation | null; 748 * } 749 */ 750var SyntaxTreeVisitor = { 751 /** 752 * Walks a syntax tree. 753 * 754 * @param object tree 755 * The AST nodes generated by the reflection API 756 * @param object callbacks 757 * A map of all the callbacks to invoke when passing through certain 758 * types of noes (e.g: onFunctionDeclaration, onBlockStatement etc.). 759 */ 760 walk(tree, callbacks) { 761 this.break = false; 762 this[tree.type](tree, callbacks); 763 }, 764 765 /** 766 * Filters all the nodes in this syntax tree based on a predicate. 767 * 768 * @param object tree 769 * The AST nodes generated by the reflection API 770 * @param function predicate 771 * The predicate ran on each node. 772 * @return array 773 * An array of nodes validating the predicate. 774 */ 775 filter(tree, predicate) { 776 let store = []; 777 this.walk(tree, { 778 onNode: e => { 779 if (predicate(e)) { 780 store.push(e); 781 } 782 } 783 }); 784 return store; 785 }, 786 787 /** 788 * A flag checked on each node in the syntax tree. If true, walking is 789 * abruptly halted. 790 */ 791 break: false, 792 793 /** 794 * A complete program source tree. 795 * 796 * interface Program <: Node { 797 * type: "Program"; 798 * body: [ Statement ]; 799 * } 800 */ 801 Program(node, callbacks) { 802 if (callbacks.onProgram) { 803 callbacks.onProgram(node); 804 } 805 for (let statement of node.body) { 806 this[statement.type](statement, node, callbacks); 807 } 808 }, 809 810 /** 811 * Any statement. 812 * 813 * interface Statement <: Node { } 814 */ 815 Statement(node, parent, callbacks) { 816 node._parent = parent; 817 818 if (this.break) { 819 return; 820 } 821 if (callbacks.onNode) { 822 if (callbacks.onNode(node, parent) === false) { 823 return; 824 } 825 } 826 if (callbacks.onStatement) { 827 callbacks.onStatement(node); 828 } 829 }, 830 831 /** 832 * An empty statement, i.e., a solitary semicolon. 833 * 834 * interface EmptyStatement <: Statement { 835 * type: "EmptyStatement"; 836 * } 837 */ 838 EmptyStatement(node, parent, callbacks) { 839 node._parent = parent; 840 841 if (this.break) { 842 return; 843 } 844 if (callbacks.onNode) { 845 if (callbacks.onNode(node, parent) === false) { 846 return; 847 } 848 } 849 if (callbacks.onEmptyStatement) { 850 callbacks.onEmptyStatement(node); 851 } 852 }, 853 854 /** 855 * A block statement, i.e., a sequence of statements surrounded by braces. 856 * 857 * interface BlockStatement <: Statement { 858 * type: "BlockStatement"; 859 * body: [ Statement ]; 860 * } 861 */ 862 BlockStatement(node, parent, callbacks) { 863 node._parent = parent; 864 865 if (this.break) { 866 return; 867 } 868 if (callbacks.onNode) { 869 if (callbacks.onNode(node, parent) === false) { 870 return; 871 } 872 } 873 if (callbacks.onBlockStatement) { 874 callbacks.onBlockStatement(node); 875 } 876 for (let statement of node.body) { 877 this[statement.type](statement, node, callbacks); 878 } 879 }, 880 881 /** 882 * An expression statement, i.e., a statement consisting of a single 883 * expression. 884 * 885 * interface ExpressionStatement <: Statement { 886 * type: "ExpressionStatement"; 887 * expression: Expression; 888 * } 889 */ 890 ExpressionStatement(node, parent, callbacks) { 891 node._parent = parent; 892 893 if (this.break) { 894 return; 895 } 896 if (callbacks.onNode) { 897 if (callbacks.onNode(node, parent) === false) { 898 return; 899 } 900 } 901 if (callbacks.onExpressionStatement) { 902 callbacks.onExpressionStatement(node); 903 } 904 this[node.expression.type](node.expression, node, callbacks); 905 }, 906 907 /** 908 * An if statement. 909 * 910 * interface IfStatement <: Statement { 911 * type: "IfStatement"; 912 * test: Expression; 913 * consequent: Statement; 914 * alternate: Statement | null; 915 * } 916 */ 917 IfStatement(node, parent, callbacks) { 918 node._parent = parent; 919 920 if (this.break) { 921 return; 922 } 923 if (callbacks.onNode) { 924 if (callbacks.onNode(node, parent) === false) { 925 return; 926 } 927 } 928 if (callbacks.onIfStatement) { 929 callbacks.onIfStatement(node); 930 } 931 this[node.test.type](node.test, node, callbacks); 932 this[node.consequent.type](node.consequent, node, callbacks); 933 if (node.alternate) { 934 this[node.alternate.type](node.alternate, node, callbacks); 935 } 936 }, 937 938 /** 939 * A labeled statement, i.e., a statement prefixed by a break/continue label. 940 * 941 * interface LabeledStatement <: Statement { 942 * type: "LabeledStatement"; 943 * label: Identifier; 944 * body: Statement; 945 * } 946 */ 947 LabeledStatement(node, parent, callbacks) { 948 node._parent = parent; 949 950 if (this.break) { 951 return; 952 } 953 if (callbacks.onNode) { 954 if (callbacks.onNode(node, parent) === false) { 955 return; 956 } 957 } 958 if (callbacks.onLabeledStatement) { 959 callbacks.onLabeledStatement(node); 960 } 961 this[node.label.type](node.label, node, callbacks); 962 this[node.body.type](node.body, node, callbacks); 963 }, 964 965 /** 966 * A break statement. 967 * 968 * interface BreakStatement <: Statement { 969 * type: "BreakStatement"; 970 * label: Identifier | null; 971 * } 972 */ 973 BreakStatement(node, parent, callbacks) { 974 node._parent = parent; 975 976 if (this.break) { 977 return; 978 } 979 if (callbacks.onNode) { 980 if (callbacks.onNode(node, parent) === false) { 981 return; 982 } 983 } 984 if (callbacks.onBreakStatement) { 985 callbacks.onBreakStatement(node); 986 } 987 if (node.label) { 988 this[node.label.type](node.label, node, callbacks); 989 } 990 }, 991 992 /** 993 * A continue statement. 994 * 995 * interface ContinueStatement <: Statement { 996 * type: "ContinueStatement"; 997 * label: Identifier | null; 998 * } 999 */ 1000 ContinueStatement(node, parent, callbacks) { 1001 node._parent = parent; 1002 1003 if (this.break) { 1004 return; 1005 } 1006 if (callbacks.onNode) { 1007 if (callbacks.onNode(node, parent) === false) { 1008 return; 1009 } 1010 } 1011 if (callbacks.onContinueStatement) { 1012 callbacks.onContinueStatement(node); 1013 } 1014 if (node.label) { 1015 this[node.label.type](node.label, node, callbacks); 1016 } 1017 }, 1018 1019 /** 1020 * A with statement. 1021 * 1022 * interface WithStatement <: Statement { 1023 * type: "WithStatement"; 1024 * object: Expression; 1025 * body: Statement; 1026 * } 1027 */ 1028 WithStatement(node, parent, callbacks) { 1029 node._parent = parent; 1030 1031 if (this.break) { 1032 return; 1033 } 1034 if (callbacks.onNode) { 1035 if (callbacks.onNode(node, parent) === false) { 1036 return; 1037 } 1038 } 1039 if (callbacks.onWithStatement) { 1040 callbacks.onWithStatement(node); 1041 } 1042 this[node.object.type](node.object, node, callbacks); 1043 this[node.body.type](node.body, node, callbacks); 1044 }, 1045 1046 /** 1047 * A switch statement. The lexical flag is metadata indicating whether the 1048 * switch statement contains any unnested let declarations (and therefore 1049 * introduces a new lexical scope). 1050 * 1051 * interface SwitchStatement <: Statement { 1052 * type: "SwitchStatement"; 1053 * discriminant: Expression; 1054 * cases: [ SwitchCase ]; 1055 * lexical: boolean; 1056 * } 1057 */ 1058 SwitchStatement(node, parent, callbacks) { 1059 node._parent = parent; 1060 1061 if (this.break) { 1062 return; 1063 } 1064 if (callbacks.onNode) { 1065 if (callbacks.onNode(node, parent) === false) { 1066 return; 1067 } 1068 } 1069 if (callbacks.onSwitchStatement) { 1070 callbacks.onSwitchStatement(node); 1071 } 1072 this[node.discriminant.type](node.discriminant, node, callbacks); 1073 for (let _case of node.cases) { 1074 this[_case.type](_case, node, callbacks); 1075 } 1076 }, 1077 1078 /** 1079 * A return statement. 1080 * 1081 * interface ReturnStatement <: Statement { 1082 * type: "ReturnStatement"; 1083 * argument: Expression | null; 1084 * } 1085 */ 1086 ReturnStatement(node, parent, callbacks) { 1087 node._parent = parent; 1088 1089 if (this.break) { 1090 return; 1091 } 1092 if (callbacks.onNode) { 1093 if (callbacks.onNode(node, parent) === false) { 1094 return; 1095 } 1096 } 1097 if (callbacks.onReturnStatement) { 1098 callbacks.onReturnStatement(node); 1099 } 1100 if (node.argument) { 1101 this[node.argument.type](node.argument, node, callbacks); 1102 } 1103 }, 1104 1105 /** 1106 * A throw statement. 1107 * 1108 * interface ThrowStatement <: Statement { 1109 * type: "ThrowStatement"; 1110 * argument: Expression; 1111 * } 1112 */ 1113 ThrowStatement(node, parent, callbacks) { 1114 node._parent = parent; 1115 1116 if (this.break) { 1117 return; 1118 } 1119 if (callbacks.onNode) { 1120 if (callbacks.onNode(node, parent) === false) { 1121 return; 1122 } 1123 } 1124 if (callbacks.onThrowStatement) { 1125 callbacks.onThrowStatement(node); 1126 } 1127 this[node.argument.type](node.argument, node, callbacks); 1128 }, 1129 1130 /** 1131 * A try statement. 1132 * 1133 * interface TryStatement <: Statement { 1134 * type: "TryStatement"; 1135 * block: BlockStatement; 1136 * handler: CatchClause | null; 1137 * guardedHandlers: [ CatchClause ]; 1138 * finalizer: BlockStatement | null; 1139 * } 1140 */ 1141 TryStatement(node, parent, callbacks) { 1142 node._parent = parent; 1143 1144 if (this.break) { 1145 return; 1146 } 1147 if (callbacks.onNode) { 1148 if (callbacks.onNode(node, parent) === false) { 1149 return; 1150 } 1151 } 1152 if (callbacks.onTryStatement) { 1153 callbacks.onTryStatement(node); 1154 } 1155 this[node.block.type](node.block, node, callbacks); 1156 if (node.handler) { 1157 this[node.handler.type](node.handler, node, callbacks); 1158 } 1159 for (let guardedHandler of node.guardedHandlers) { 1160 this[guardedHandler.type](guardedHandler, node, callbacks); 1161 } 1162 if (node.finalizer) { 1163 this[node.finalizer.type](node.finalizer, node, callbacks); 1164 } 1165 }, 1166 1167 /** 1168 * A while statement. 1169 * 1170 * interface WhileStatement <: Statement { 1171 * type: "WhileStatement"; 1172 * test: Expression; 1173 * body: Statement; 1174 * } 1175 */ 1176 WhileStatement(node, parent, callbacks) { 1177 node._parent = parent; 1178 1179 if (this.break) { 1180 return; 1181 } 1182 if (callbacks.onNode) { 1183 if (callbacks.onNode(node, parent) === false) { 1184 return; 1185 } 1186 } 1187 if (callbacks.onWhileStatement) { 1188 callbacks.onWhileStatement(node); 1189 } 1190 this[node.test.type](node.test, node, callbacks); 1191 this[node.body.type](node.body, node, callbacks); 1192 }, 1193 1194 /** 1195 * A do/while statement. 1196 * 1197 * interface DoWhileStatement <: Statement { 1198 * type: "DoWhileStatement"; 1199 * body: Statement; 1200 * test: Expression; 1201 * } 1202 */ 1203 DoWhileStatement(node, parent, callbacks) { 1204 node._parent = parent; 1205 1206 if (this.break) { 1207 return; 1208 } 1209 if (callbacks.onNode) { 1210 if (callbacks.onNode(node, parent) === false) { 1211 return; 1212 } 1213 } 1214 if (callbacks.onDoWhileStatement) { 1215 callbacks.onDoWhileStatement(node); 1216 } 1217 this[node.body.type](node.body, node, callbacks); 1218 this[node.test.type](node.test, node, callbacks); 1219 }, 1220 1221 /** 1222 * A for statement. 1223 * 1224 * interface ForStatement <: Statement { 1225 * type: "ForStatement"; 1226 * init: VariableDeclaration | Expression | null; 1227 * test: Expression | null; 1228 * update: Expression | null; 1229 * body: Statement; 1230 * } 1231 */ 1232 ForStatement(node, parent, callbacks) { 1233 node._parent = parent; 1234 1235 if (this.break) { 1236 return; 1237 } 1238 if (callbacks.onNode) { 1239 if (callbacks.onNode(node, parent) === false) { 1240 return; 1241 } 1242 } 1243 if (callbacks.onForStatement) { 1244 callbacks.onForStatement(node); 1245 } 1246 if (node.init) { 1247 this[node.init.type](node.init, node, callbacks); 1248 } 1249 if (node.test) { 1250 this[node.test.type](node.test, node, callbacks); 1251 } 1252 if (node.update) { 1253 this[node.update.type](node.update, node, callbacks); 1254 } 1255 this[node.body.type](node.body, node, callbacks); 1256 }, 1257 1258 /** 1259 * A for/in statement, or, if each is true, a for each/in statement. 1260 * 1261 * interface ForInStatement <: Statement { 1262 * type: "ForInStatement"; 1263 * left: VariableDeclaration | Expression; 1264 * right: Expression; 1265 * body: Statement; 1266 * each: boolean; 1267 * } 1268 */ 1269 ForInStatement(node, parent, callbacks) { 1270 node._parent = parent; 1271 1272 if (this.break) { 1273 return; 1274 } 1275 if (callbacks.onNode) { 1276 if (callbacks.onNode(node, parent) === false) { 1277 return; 1278 } 1279 } 1280 if (callbacks.onForInStatement) { 1281 callbacks.onForInStatement(node); 1282 } 1283 this[node.left.type](node.left, node, callbacks); 1284 this[node.right.type](node.right, node, callbacks); 1285 this[node.body.type](node.body, node, callbacks); 1286 }, 1287 1288 /** 1289 * A for/of statement. 1290 * 1291 * interface ForOfStatement <: Statement { 1292 * type: "ForOfStatement"; 1293 * left: VariableDeclaration | Expression; 1294 * right: Expression; 1295 * body: Statement; 1296 * } 1297 */ 1298 ForOfStatement(node, parent, callbacks) { 1299 node._parent = parent; 1300 1301 if (this.break) { 1302 return; 1303 } 1304 if (callbacks.onNode) { 1305 if (callbacks.onNode(node, parent) === false) { 1306 return; 1307 } 1308 } 1309 if (callbacks.onForOfStatement) { 1310 callbacks.onForOfStatement(node); 1311 } 1312 this[node.left.type](node.left, node, callbacks); 1313 this[node.right.type](node.right, node, callbacks); 1314 this[node.body.type](node.body, node, callbacks); 1315 }, 1316 1317 /** 1318 * A let statement. 1319 * 1320 * interface LetStatement <: Statement { 1321 * type: "LetStatement"; 1322 * head: [ { id: Pattern, init: Expression | null } ]; 1323 * body: Statement; 1324 * } 1325 */ 1326 LetStatement(node, parent, callbacks) { 1327 node._parent = parent; 1328 1329 if (this.break) { 1330 return; 1331 } 1332 if (callbacks.onNode) { 1333 if (callbacks.onNode(node, parent) === false) { 1334 return; 1335 } 1336 } 1337 if (callbacks.onLetStatement) { 1338 callbacks.onLetStatement(node); 1339 } 1340 for (let { id, init } of node.head) { 1341 this[id.type](id, node, callbacks); 1342 if (init) { 1343 this[init.type](init, node, callbacks); 1344 } 1345 } 1346 this[node.body.type](node.body, node, callbacks); 1347 }, 1348 1349 /** 1350 * A debugger statement. 1351 * 1352 * interface DebuggerStatement <: Statement { 1353 * type: "DebuggerStatement"; 1354 * } 1355 */ 1356 DebuggerStatement(node, parent, callbacks) { 1357 node._parent = parent; 1358 1359 if (this.break) { 1360 return; 1361 } 1362 if (callbacks.onNode) { 1363 if (callbacks.onNode(node, parent) === false) { 1364 return; 1365 } 1366 } 1367 if (callbacks.onDebuggerStatement) { 1368 callbacks.onDebuggerStatement(node); 1369 } 1370 }, 1371 1372 /** 1373 * Any declaration node. Note that declarations are considered statements; 1374 * this is because declarations can appear in any statement context in the 1375 * language recognized by the SpiderMonkey parser. 1376 * 1377 * interface Declaration <: Statement { } 1378 */ 1379 Declaration(node, parent, callbacks) { 1380 node._parent = parent; 1381 1382 if (this.break) { 1383 return; 1384 } 1385 if (callbacks.onNode) { 1386 if (callbacks.onNode(node, parent) === false) { 1387 return; 1388 } 1389 } 1390 if (callbacks.onDeclaration) { 1391 callbacks.onDeclaration(node); 1392 } 1393 }, 1394 1395 /** 1396 * A function declaration. 1397 * 1398 * interface FunctionDeclaration <: Function, Declaration { 1399 * type: "FunctionDeclaration"; 1400 * id: Identifier; 1401 * params: [ Pattern ]; 1402 * defaults: [ Expression ]; 1403 * rest: Identifier | null; 1404 * body: BlockStatement | Expression; 1405 * generator: boolean; 1406 * expression: boolean; 1407 * } 1408 */ 1409 FunctionDeclaration(node, parent, callbacks) { 1410 node._parent = parent; 1411 1412 if (this.break) { 1413 return; 1414 } 1415 if (callbacks.onNode) { 1416 if (callbacks.onNode(node, parent) === false) { 1417 return; 1418 } 1419 } 1420 if (callbacks.onFunctionDeclaration) { 1421 callbacks.onFunctionDeclaration(node); 1422 } 1423 this[node.id.type](node.id, node, callbacks); 1424 for (let param of node.params) { 1425 this[param.type](param, node, callbacks); 1426 } 1427 for (let _default of node.defaults) { 1428 if (_default) { 1429 this[_default.type](_default, node, callbacks); 1430 } 1431 } 1432 if (node.rest) { 1433 this[node.rest.type](node.rest, node, callbacks); 1434 } 1435 this[node.body.type](node.body, node, callbacks); 1436 }, 1437 1438 /** 1439 * A variable declaration, via one of var, let, or const. 1440 * 1441 * interface VariableDeclaration <: Declaration { 1442 * type: "VariableDeclaration"; 1443 * declarations: [ VariableDeclarator ]; 1444 * kind: "var" | "let" | "const"; 1445 * } 1446 */ 1447 VariableDeclaration(node, parent, callbacks) { 1448 node._parent = parent; 1449 1450 if (this.break) { 1451 return; 1452 } 1453 if (callbacks.onNode) { 1454 if (callbacks.onNode(node, parent) === false) { 1455 return; 1456 } 1457 } 1458 if (callbacks.onVariableDeclaration) { 1459 callbacks.onVariableDeclaration(node); 1460 } 1461 for (let declaration of node.declarations) { 1462 this[declaration.type](declaration, node, callbacks); 1463 } 1464 }, 1465 1466 /** 1467 * A variable declarator. 1468 * 1469 * interface VariableDeclarator <: Node { 1470 * type: "VariableDeclarator"; 1471 * id: Pattern; 1472 * init: Expression | null; 1473 * } 1474 */ 1475 VariableDeclarator(node, parent, callbacks) { 1476 node._parent = parent; 1477 1478 if (this.break) { 1479 return; 1480 } 1481 if (callbacks.onNode) { 1482 if (callbacks.onNode(node, parent) === false) { 1483 return; 1484 } 1485 } 1486 if (callbacks.onVariableDeclarator) { 1487 callbacks.onVariableDeclarator(node); 1488 } 1489 this[node.id.type](node.id, node, callbacks); 1490 if (node.init) { 1491 this[node.init.type](node.init, node, callbacks); 1492 } 1493 }, 1494 1495 /** 1496 * Any expression node. Since the left-hand side of an assignment may be any 1497 * expression in general, an expression can also be a pattern. 1498 * 1499 * interface Expression <: Node, Pattern { } 1500 */ 1501 Expression(node, parent, callbacks) { 1502 node._parent = parent; 1503 1504 if (this.break) { 1505 return; 1506 } 1507 if (callbacks.onNode) { 1508 if (callbacks.onNode(node, parent) === false) { 1509 return; 1510 } 1511 } 1512 if (callbacks.onExpression) { 1513 callbacks.onExpression(node); 1514 } 1515 }, 1516 1517 /** 1518 * A this expression. 1519 * 1520 * interface ThisExpression <: Expression { 1521 * type: "ThisExpression"; 1522 * } 1523 */ 1524 ThisExpression(node, parent, callbacks) { 1525 node._parent = parent; 1526 1527 if (this.break) { 1528 return; 1529 } 1530 if (callbacks.onNode) { 1531 if (callbacks.onNode(node, parent) === false) { 1532 return; 1533 } 1534 } 1535 if (callbacks.onThisExpression) { 1536 callbacks.onThisExpression(node); 1537 } 1538 }, 1539 1540 /** 1541 * An array expression. 1542 * 1543 * interface ArrayExpression <: Expression { 1544 * type: "ArrayExpression"; 1545 * elements: [ Expression | null ]; 1546 * } 1547 */ 1548 ArrayExpression(node, parent, callbacks) { 1549 node._parent = parent; 1550 1551 if (this.break) { 1552 return; 1553 } 1554 if (callbacks.onNode) { 1555 if (callbacks.onNode(node, parent) === false) { 1556 return; 1557 } 1558 } 1559 if (callbacks.onArrayExpression) { 1560 callbacks.onArrayExpression(node); 1561 } 1562 for (let element of node.elements) { 1563 if (element) { 1564 this[element.type](element, node, callbacks); 1565 } 1566 } 1567 }, 1568 1569 /** 1570 * A spread expression. 1571 * 1572 * interface SpreadExpression <: Expression { 1573 * type: "SpreadExpression"; 1574 * expression: Expression; 1575 * } 1576 */ 1577 SpreadExpression(node, parent, callbacks) { 1578 node._parent = parent; 1579 1580 if (this.break) { 1581 return; 1582 } 1583 if (callbacks.onNode) { 1584 if (callbacks.onNode(node, parent) === false) { 1585 return; 1586 } 1587 } 1588 if (callbacks.onSpreadExpression) { 1589 callbacks.onSpreadExpression(node); 1590 } 1591 this[node.expression.type](node.expression, node, callbacks); 1592 }, 1593 1594 /** 1595 * An object expression. A literal property in an object expression can have 1596 * either a string or number as its value. Ordinary property initializers 1597 * have a kind value "init"; getters and setters have the kind values "get" 1598 * and "set", respectively. 1599 * 1600 * interface ObjectExpression <: Expression { 1601 * type: "ObjectExpression"; 1602 * properties: [ { key: Literal | Identifier | ComputedName, 1603 * value: Expression, 1604 * kind: "init" | "get" | "set" } ]; 1605 * } 1606 */ 1607 ObjectExpression(node, parent, callbacks) { 1608 node._parent = parent; 1609 1610 if (this.break) { 1611 return; 1612 } 1613 if (callbacks.onNode) { 1614 if (callbacks.onNode(node, parent) === false) { 1615 return; 1616 } 1617 } 1618 if (callbacks.onObjectExpression) { 1619 callbacks.onObjectExpression(node); 1620 } 1621 for (let { key, value } of node.properties) { 1622 this[key.type](key, node, callbacks); 1623 this[value.type](value, node, callbacks); 1624 } 1625 }, 1626 1627 /** 1628 * A computed property name in object expression, like in { [a]: b } 1629 * 1630 * interface ComputedName <: Node { 1631 * type: "ComputedName"; 1632 * name: Expression; 1633 * } 1634 */ 1635 ComputedName(node, parent, callbacks) { 1636 node._parent = parent; 1637 1638 if (this.break) { 1639 return; 1640 } 1641 if (callbacks.onNode) { 1642 if (callbacks.onNode(node, parent) === false) { 1643 return; 1644 } 1645 } 1646 if (callbacks.onComputedName) { 1647 callbacks.onComputedName(node); 1648 } 1649 this[node.name.type](node.name, node, callbacks); 1650 }, 1651 1652 /** 1653 * A function expression. 1654 * 1655 * interface FunctionExpression <: Function, Expression { 1656 * type: "FunctionExpression"; 1657 * id: Identifier | null; 1658 * params: [ Pattern ]; 1659 * defaults: [ Expression ]; 1660 * rest: Identifier | null; 1661 * body: BlockStatement | Expression; 1662 * generator: boolean; 1663 * expression: boolean; 1664 * } 1665 */ 1666 FunctionExpression(node, parent, callbacks) { 1667 node._parent = parent; 1668 1669 if (this.break) { 1670 return; 1671 } 1672 if (callbacks.onNode) { 1673 if (callbacks.onNode(node, parent) === false) { 1674 return; 1675 } 1676 } 1677 if (callbacks.onFunctionExpression) { 1678 callbacks.onFunctionExpression(node); 1679 } 1680 if (node.id) { 1681 this[node.id.type](node.id, node, callbacks); 1682 } 1683 for (let param of node.params) { 1684 this[param.type](param, node, callbacks); 1685 } 1686 for (let _default of node.defaults) { 1687 if (_default) { 1688 this[_default.type](_default, node, callbacks); 1689 } 1690 } 1691 if (node.rest) { 1692 this[node.rest.type](node.rest, node, callbacks); 1693 } 1694 this[node.body.type](node.body, node, callbacks); 1695 }, 1696 1697 /** 1698 * An arrow expression. 1699 * 1700 * interface ArrowFunctionExpression <: Function, Expression { 1701 * type: "ArrowFunctionExpression"; 1702 * params: [ Pattern ]; 1703 * defaults: [ Expression ]; 1704 * rest: Identifier | null; 1705 * body: BlockStatement | Expression; 1706 * generator: boolean; 1707 * expression: boolean; 1708 * } 1709 */ 1710 ArrowFunctionExpression(node, parent, callbacks) { 1711 node._parent = parent; 1712 1713 if (this.break) { 1714 return; 1715 } 1716 if (callbacks.onNode) { 1717 if (callbacks.onNode(node, parent) === false) { 1718 return; 1719 } 1720 } 1721 if (callbacks.onArrowFunctionExpression) { 1722 callbacks.onArrowFunctionExpression(node); 1723 } 1724 for (let param of node.params) { 1725 this[param.type](param, node, callbacks); 1726 } 1727 for (let _default of node.defaults) { 1728 if (_default) { 1729 this[_default.type](_default, node, callbacks); 1730 } 1731 } 1732 if (node.rest) { 1733 this[node.rest.type](node.rest, node, callbacks); 1734 } 1735 this[node.body.type](node.body, node, callbacks); 1736 }, 1737 1738 /** 1739 * A sequence expression, i.e., a comma-separated sequence of expressions. 1740 * 1741 * interface SequenceExpression <: Expression { 1742 * type: "SequenceExpression"; 1743 * expressions: [ Expression ]; 1744 * } 1745 */ 1746 SequenceExpression(node, parent, callbacks) { 1747 node._parent = parent; 1748 1749 if (this.break) { 1750 return; 1751 } 1752 if (callbacks.onNode) { 1753 if (callbacks.onNode(node, parent) === false) { 1754 return; 1755 } 1756 } 1757 if (callbacks.onSequenceExpression) { 1758 callbacks.onSequenceExpression(node); 1759 } 1760 for (let expression of node.expressions) { 1761 this[expression.type](expression, node, callbacks); 1762 } 1763 }, 1764 1765 /** 1766 * A unary operator expression. 1767 * 1768 * interface UnaryExpression <: Expression { 1769 * type: "UnaryExpression"; 1770 * operator: UnaryOperator; 1771 * prefix: boolean; 1772 * argument: Expression; 1773 * } 1774 */ 1775 UnaryExpression(node, parent, callbacks) { 1776 node._parent = parent; 1777 1778 if (this.break) { 1779 return; 1780 } 1781 if (callbacks.onNode) { 1782 if (callbacks.onNode(node, parent) === false) { 1783 return; 1784 } 1785 } 1786 if (callbacks.onUnaryExpression) { 1787 callbacks.onUnaryExpression(node); 1788 } 1789 this[node.argument.type](node.argument, node, callbacks); 1790 }, 1791 1792 /** 1793 * A binary operator expression. 1794 * 1795 * interface BinaryExpression <: Expression { 1796 * type: "BinaryExpression"; 1797 * operator: BinaryOperator; 1798 * left: Expression; 1799 * right: Expression; 1800 * } 1801 */ 1802 BinaryExpression(node, parent, callbacks) { 1803 node._parent = parent; 1804 1805 if (this.break) { 1806 return; 1807 } 1808 if (callbacks.onNode) { 1809 if (callbacks.onNode(node, parent) === false) { 1810 return; 1811 } 1812 } 1813 if (callbacks.onBinaryExpression) { 1814 callbacks.onBinaryExpression(node); 1815 } 1816 this[node.left.type](node.left, node, callbacks); 1817 this[node.right.type](node.right, node, callbacks); 1818 }, 1819 1820 /** 1821 * An assignment operator expression. 1822 * 1823 * interface AssignmentExpression <: Expression { 1824 * type: "AssignmentExpression"; 1825 * operator: AssignmentOperator; 1826 * left: Expression; 1827 * right: Expression; 1828 * } 1829 */ 1830 AssignmentExpression(node, parent, callbacks) { 1831 node._parent = parent; 1832 1833 if (this.break) { 1834 return; 1835 } 1836 if (callbacks.onNode) { 1837 if (callbacks.onNode(node, parent) === false) { 1838 return; 1839 } 1840 } 1841 if (callbacks.onAssignmentExpression) { 1842 callbacks.onAssignmentExpression(node); 1843 } 1844 this[node.left.type](node.left, node, callbacks); 1845 this[node.right.type](node.right, node, callbacks); 1846 }, 1847 1848 /** 1849 * An update (increment or decrement) operator expression. 1850 * 1851 * interface UpdateExpression <: Expression { 1852 * type: "UpdateExpression"; 1853 * operator: UpdateOperator; 1854 * argument: Expression; 1855 * prefix: boolean; 1856 * } 1857 */ 1858 UpdateExpression(node, parent, callbacks) { 1859 node._parent = parent; 1860 1861 if (this.break) { 1862 return; 1863 } 1864 if (callbacks.onNode) { 1865 if (callbacks.onNode(node, parent) === false) { 1866 return; 1867 } 1868 } 1869 if (callbacks.onUpdateExpression) { 1870 callbacks.onUpdateExpression(node); 1871 } 1872 this[node.argument.type](node.argument, node, callbacks); 1873 }, 1874 1875 /** 1876 * A logical operator expression. 1877 * 1878 * interface LogicalExpression <: Expression { 1879 * type: "LogicalExpression"; 1880 * operator: LogicalOperator; 1881 * left: Expression; 1882 * right: Expression; 1883 * } 1884 */ 1885 LogicalExpression(node, parent, callbacks) { 1886 node._parent = parent; 1887 1888 if (this.break) { 1889 return; 1890 } 1891 if (callbacks.onNode) { 1892 if (callbacks.onNode(node, parent) === false) { 1893 return; 1894 } 1895 } 1896 if (callbacks.onLogicalExpression) { 1897 callbacks.onLogicalExpression(node); 1898 } 1899 this[node.left.type](node.left, node, callbacks); 1900 this[node.right.type](node.right, node, callbacks); 1901 }, 1902 1903 /** 1904 * A conditional expression, i.e., a ternary ?/: expression. 1905 * 1906 * interface ConditionalExpression <: Expression { 1907 * type: "ConditionalExpression"; 1908 * test: Expression; 1909 * alternate: Expression; 1910 * consequent: Expression; 1911 * } 1912 */ 1913 ConditionalExpression(node, parent, callbacks) { 1914 node._parent = parent; 1915 1916 if (this.break) { 1917 return; 1918 } 1919 if (callbacks.onNode) { 1920 if (callbacks.onNode(node, parent) === false) { 1921 return; 1922 } 1923 } 1924 if (callbacks.onConditionalExpression) { 1925 callbacks.onConditionalExpression(node); 1926 } 1927 this[node.test.type](node.test, node, callbacks); 1928 this[node.alternate.type](node.alternate, node, callbacks); 1929 this[node.consequent.type](node.consequent, node, callbacks); 1930 }, 1931 1932 /** 1933 * A new expression. 1934 * 1935 * interface NewExpression <: Expression { 1936 * type: "NewExpression"; 1937 * callee: Expression; 1938 * arguments: [ Expression | null ]; 1939 * } 1940 */ 1941 NewExpression(node, parent, callbacks) { 1942 node._parent = parent; 1943 1944 if (this.break) { 1945 return; 1946 } 1947 if (callbacks.onNode) { 1948 if (callbacks.onNode(node, parent) === false) { 1949 return; 1950 } 1951 } 1952 if (callbacks.onNewExpression) { 1953 callbacks.onNewExpression(node); 1954 } 1955 this[node.callee.type](node.callee, node, callbacks); 1956 for (let argument of node.arguments) { 1957 if (argument) { 1958 this[argument.type](argument, node, callbacks); 1959 } 1960 } 1961 }, 1962 1963 /** 1964 * A function or method call expression. 1965 * 1966 * interface CallExpression <: Expression { 1967 * type: "CallExpression"; 1968 * callee: Expression; 1969 * arguments: [ Expression | null ]; 1970 * } 1971 */ 1972 CallExpression(node, parent, callbacks) { 1973 node._parent = parent; 1974 1975 if (this.break) { 1976 return; 1977 } 1978 if (callbacks.onNode) { 1979 if (callbacks.onNode(node, parent) === false) { 1980 return; 1981 } 1982 } 1983 if (callbacks.onCallExpression) { 1984 callbacks.onCallExpression(node); 1985 } 1986 this[node.callee.type](node.callee, node, callbacks); 1987 for (let argument of node.arguments) { 1988 if (argument) { 1989 if (!this[argument.type]) { 1990 console.error("Unknown parser object:", argument.type); 1991 } 1992 this[argument.type](argument, node, callbacks); 1993 } 1994 } 1995 }, 1996 1997 /** 1998 * A member expression. If computed is true, the node corresponds to a 1999 * computed e1[e2] expression and property is an Expression. If computed is 2000 * false, the node corresponds to a static e1.x expression and property is an 2001 * Identifier. 2002 * 2003 * interface MemberExpression <: Expression { 2004 * type: "MemberExpression"; 2005 * object: Expression; 2006 * property: Identifier | Expression; 2007 * computed: boolean; 2008 * } 2009 */ 2010 MemberExpression(node, parent, callbacks) { 2011 node._parent = parent; 2012 2013 if (this.break) { 2014 return; 2015 } 2016 if (callbacks.onNode) { 2017 if (callbacks.onNode(node, parent) === false) { 2018 return; 2019 } 2020 } 2021 if (callbacks.onMemberExpression) { 2022 callbacks.onMemberExpression(node); 2023 } 2024 this[node.object.type](node.object, node, callbacks); 2025 this[node.property.type](node.property, node, callbacks); 2026 }, 2027 2028 /** 2029 * A yield expression. 2030 * 2031 * interface YieldExpression <: Expression { 2032 * argument: Expression | null; 2033 * } 2034 */ 2035 YieldExpression(node, parent, callbacks) { 2036 node._parent = parent; 2037 2038 if (this.break) { 2039 return; 2040 } 2041 if (callbacks.onNode) { 2042 if (callbacks.onNode(node, parent) === false) { 2043 return; 2044 } 2045 } 2046 if (callbacks.onYieldExpression) { 2047 callbacks.onYieldExpression(node); 2048 } 2049 if (node.argument) { 2050 this[node.argument.type](node.argument, node, callbacks); 2051 } 2052 }, 2053 2054 /** 2055 * An array comprehension. The blocks array corresponds to the sequence of 2056 * for and for each blocks. The optional filter expression corresponds to the 2057 * final if clause, if present. 2058 * 2059 * interface ComprehensionExpression <: Expression { 2060 * body: Expression; 2061 * blocks: [ ComprehensionBlock ]; 2062 * filter: Expression | null; 2063 * } 2064 */ 2065 ComprehensionExpression(node, parent, callbacks) { 2066 node._parent = parent; 2067 2068 if (this.break) { 2069 return; 2070 } 2071 if (callbacks.onNode) { 2072 if (callbacks.onNode(node, parent) === false) { 2073 return; 2074 } 2075 } 2076 if (callbacks.onComprehensionExpression) { 2077 callbacks.onComprehensionExpression(node); 2078 } 2079 this[node.body.type](node.body, node, callbacks); 2080 for (let block of node.blocks) { 2081 this[block.type](block, node, callbacks); 2082 } 2083 if (node.filter) { 2084 this[node.filter.type](node.filter, node, callbacks); 2085 } 2086 }, 2087 2088 /** 2089 * A generator expression. As with array comprehensions, the blocks array 2090 * corresponds to the sequence of for and for each blocks, and the optional 2091 * filter expression corresponds to the final if clause, if present. 2092 * 2093 * interface GeneratorExpression <: Expression { 2094 * body: Expression; 2095 * blocks: [ ComprehensionBlock ]; 2096 * filter: Expression | null; 2097 * } 2098 */ 2099 GeneratorExpression(node, parent, callbacks) { 2100 node._parent = parent; 2101 2102 if (this.break) { 2103 return; 2104 } 2105 if (callbacks.onNode) { 2106 if (callbacks.onNode(node, parent) === false) { 2107 return; 2108 } 2109 } 2110 if (callbacks.onGeneratorExpression) { 2111 callbacks.onGeneratorExpression(node); 2112 } 2113 this[node.body.type](node.body, node, callbacks); 2114 for (let block of node.blocks) { 2115 this[block.type](block, node, callbacks); 2116 } 2117 if (node.filter) { 2118 this[node.filter.type](node.filter, node, callbacks); 2119 } 2120 }, 2121 2122 /** 2123 * A graph expression, aka "sharp literal," such as #1={ self: #1# }. 2124 * 2125 * interface GraphExpression <: Expression { 2126 * index: uint32; 2127 * expression: Literal; 2128 * } 2129 */ 2130 GraphExpression(node, parent, callbacks) { 2131 node._parent = parent; 2132 2133 if (this.break) { 2134 return; 2135 } 2136 if (callbacks.onNode) { 2137 if (callbacks.onNode(node, parent) === false) { 2138 return; 2139 } 2140 } 2141 if (callbacks.onGraphExpression) { 2142 callbacks.onGraphExpression(node); 2143 } 2144 this[node.expression.type](node.expression, node, callbacks); 2145 }, 2146 2147 /** 2148 * A graph index expression, aka "sharp variable," such as #1#. 2149 * 2150 * interface GraphIndexExpression <: Expression { 2151 * index: uint32; 2152 * } 2153 */ 2154 GraphIndexExpression(node, parent, callbacks) { 2155 node._parent = parent; 2156 2157 if (this.break) { 2158 return; 2159 } 2160 if (callbacks.onNode) { 2161 if (callbacks.onNode(node, parent) === false) { 2162 return; 2163 } 2164 } 2165 if (callbacks.onGraphIndexExpression) { 2166 callbacks.onGraphIndexExpression(node); 2167 } 2168 }, 2169 2170 /** 2171 * A let expression. 2172 * 2173 * interface LetExpression <: Expression { 2174 * type: "LetExpression"; 2175 * head: [ { id: Pattern, init: Expression | null } ]; 2176 * body: Expression; 2177 * } 2178 */ 2179 LetExpression(node, parent, callbacks) { 2180 node._parent = parent; 2181 2182 if (this.break) { 2183 return; 2184 } 2185 if (callbacks.onNode) { 2186 if (callbacks.onNode(node, parent) === false) { 2187 return; 2188 } 2189 } 2190 if (callbacks.onLetExpression) { 2191 callbacks.onLetExpression(node); 2192 } 2193 for (let { id, init } of node.head) { 2194 this[id.type](id, node, callbacks); 2195 if (init) { 2196 this[init.type](init, node, callbacks); 2197 } 2198 } 2199 this[node.body.type](node.body, node, callbacks); 2200 }, 2201 2202 /** 2203 * Any pattern. 2204 * 2205 * interface Pattern <: Node { } 2206 */ 2207 Pattern(node, parent, callbacks) { 2208 node._parent = parent; 2209 2210 if (this.break) { 2211 return; 2212 } 2213 if (callbacks.onNode) { 2214 if (callbacks.onNode(node, parent) === false) { 2215 return; 2216 } 2217 } 2218 if (callbacks.onPattern) { 2219 callbacks.onPattern(node); 2220 } 2221 }, 2222 2223 /** 2224 * An object-destructuring pattern. A literal property in an object pattern 2225 * can have either a string or number as its value. 2226 * 2227 * interface ObjectPattern <: Pattern { 2228 * type: "ObjectPattern"; 2229 * properties: [ { key: Literal | Identifier, value: Pattern } ]; 2230 * } 2231 */ 2232 ObjectPattern(node, parent, callbacks) { 2233 node._parent = parent; 2234 2235 if (this.break) { 2236 return; 2237 } 2238 if (callbacks.onNode) { 2239 if (callbacks.onNode(node, parent) === false) { 2240 return; 2241 } 2242 } 2243 if (callbacks.onObjectPattern) { 2244 callbacks.onObjectPattern(node); 2245 } 2246 for (let { key, value } of node.properties) { 2247 this[key.type](key, node, callbacks); 2248 this[value.type](value, node, callbacks); 2249 } 2250 }, 2251 2252 /** 2253 * An array-destructuring pattern. 2254 * 2255 * interface ArrayPattern <: Pattern { 2256 * type: "ArrayPattern"; 2257 * elements: [ Pattern | null ]; 2258 * } 2259 */ 2260 ArrayPattern(node, parent, callbacks) { 2261 node._parent = parent; 2262 2263 if (this.break) { 2264 return; 2265 } 2266 if (callbacks.onNode) { 2267 if (callbacks.onNode(node, parent) === false) { 2268 return; 2269 } 2270 } 2271 if (callbacks.onArrayPattern) { 2272 callbacks.onArrayPattern(node); 2273 } 2274 for (let element of node.elements) { 2275 if (element) { 2276 this[element.type](element, node, callbacks); 2277 } 2278 } 2279 }, 2280 2281 /** 2282 * A case (if test is an Expression) or default (if test is null) clause in 2283 * the body of a switch statement. 2284 * 2285 * interface SwitchCase <: Node { 2286 * type: "SwitchCase"; 2287 * test: Expression | null; 2288 * consequent: [ Statement ]; 2289 * } 2290 */ 2291 SwitchCase(node, parent, callbacks) { 2292 node._parent = parent; 2293 2294 if (this.break) { 2295 return; 2296 } 2297 if (callbacks.onNode) { 2298 if (callbacks.onNode(node, parent) === false) { 2299 return; 2300 } 2301 } 2302 if (callbacks.onSwitchCase) { 2303 callbacks.onSwitchCase(node); 2304 } 2305 if (node.test) { 2306 this[node.test.type](node.test, node, callbacks); 2307 } 2308 for (let consequent of node.consequent) { 2309 this[consequent.type](consequent, node, callbacks); 2310 } 2311 }, 2312 2313 /** 2314 * A catch clause following a try block. The optional guard property 2315 * corresponds to the optional expression guard on the bound variable. 2316 * 2317 * interface CatchClause <: Node { 2318 * type: "CatchClause"; 2319 * param: Pattern; 2320 * guard: Expression | null; 2321 * body: BlockStatement; 2322 * } 2323 */ 2324 CatchClause(node, parent, callbacks) { 2325 node._parent = parent; 2326 2327 if (this.break) { 2328 return; 2329 } 2330 if (callbacks.onNode) { 2331 if (callbacks.onNode(node, parent) === false) { 2332 return; 2333 } 2334 } 2335 if (callbacks.onCatchClause) { 2336 callbacks.onCatchClause(node); 2337 } 2338 this[node.param.type](node.param, node, callbacks); 2339 if (node.guard) { 2340 this[node.guard.type](node.guard, node, callbacks); 2341 } 2342 this[node.body.type](node.body, node, callbacks); 2343 }, 2344 2345 /** 2346 * A for or for each block in an array comprehension or generator expression. 2347 * 2348 * interface ComprehensionBlock <: Node { 2349 * left: Pattern; 2350 * right: Expression; 2351 * each: boolean; 2352 * } 2353 */ 2354 ComprehensionBlock(node, parent, callbacks) { 2355 node._parent = parent; 2356 2357 if (this.break) { 2358 return; 2359 } 2360 if (callbacks.onNode) { 2361 if (callbacks.onNode(node, parent) === false) { 2362 return; 2363 } 2364 } 2365 if (callbacks.onComprehensionBlock) { 2366 callbacks.onComprehensionBlock(node); 2367 } 2368 this[node.left.type](node.left, node, callbacks); 2369 this[node.right.type](node.right, node, callbacks); 2370 }, 2371 2372 /** 2373 * An identifier. Note that an identifier may be an expression or a 2374 * destructuring pattern. 2375 * 2376 * interface Identifier <: Node, Expression, Pattern { 2377 * type: "Identifier"; 2378 * name: string; 2379 * } 2380 */ 2381 Identifier(node, parent, callbacks) { 2382 node._parent = parent; 2383 2384 if (this.break) { 2385 return; 2386 } 2387 if (callbacks.onNode) { 2388 if (callbacks.onNode(node, parent) === false) { 2389 return; 2390 } 2391 } 2392 if (callbacks.onIdentifier) { 2393 callbacks.onIdentifier(node); 2394 } 2395 }, 2396 2397 /** 2398 * A literal token. Note that a literal can be an expression. 2399 * 2400 * interface Literal <: Node, Expression { 2401 * type: "Literal"; 2402 * value: string | boolean | null | number | RegExp; 2403 * } 2404 */ 2405 Literal(node, parent, callbacks) { 2406 node._parent = parent; 2407 2408 if (this.break) { 2409 return; 2410 } 2411 if (callbacks.onNode) { 2412 if (callbacks.onNode(node, parent) === false) { 2413 return; 2414 } 2415 } 2416 if (callbacks.onLiteral) { 2417 callbacks.onLiteral(node); 2418 } 2419 }, 2420 2421 /** 2422 * A template string literal. 2423 * 2424 * interface TemplateLiteral <: Node { 2425 * type: "TemplateLiteral"; 2426 * elements: [ Expression ]; 2427 * } 2428 */ 2429 TemplateLiteral(node, parent, callbacks) { 2430 node._parent = parent; 2431 2432 if (this.break) { 2433 return; 2434 } 2435 if (callbacks.onNode) { 2436 if (callbacks.onNode(node, parent) === false) { 2437 return; 2438 } 2439 } 2440 if (callbacks.onTemplateLiteral) { 2441 callbacks.onTemplateLiteral(node); 2442 } 2443 for (let element of node.elements) { 2444 if (element) { 2445 this[element.type](element, node, callbacks); 2446 } 2447 } 2448 } 2449}; 2450 2451XPCOMUtils.defineLazyGetter(Parser, "reflectionAPI", () => Reflect); 2452