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