Web Inspector: Add ability to distinguish if a Script was parsed as a module
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Models / ScriptSyntaxTree.js
1 /*
2  * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.ScriptSyntaxTree = class ScriptSyntaxTree extends WebInspector.Object
27 {
28     constructor(sourceText, script)
29     {
30         super();
31
32         console.assert(script && script instanceof WebInspector.Script, script);
33
34         this._script = script;
35
36         try {
37             let sourceType = this._script.sourceType === WebInspector.Script.SourceType.Module ? "module" : "script";
38             let esprimaSyntaxTree = esprima.parse(sourceText, {range: true, sourceType});
39             this._syntaxTree = this._createInternalSyntaxTree(esprimaSyntaxTree);
40             this._parsedSuccessfully = true;
41         } catch (error) {
42             this._parsedSuccessfully = false;
43             this._syntaxTree = null;
44             console.error("Couldn't parse JavaScript File: " + script.url, error);
45         }
46     }
47
48     // Public
49
50     get parsedSuccessfully()
51     {
52         return this._parsedSuccessfully;
53     }
54
55     forEachNode(callback)
56     {
57         console.assert(this._parsedSuccessfully);
58         if (!this._parsedSuccessfully)
59             return;
60
61         this._recurse(this._syntaxTree, callback, this._defaultParserState());
62     }
63
64     filter(predicate, startNode)
65     {
66         console.assert(startNode && this._parsedSuccessfully);
67         if (!this._parsedSuccessfully)
68             return [];
69
70         var nodes = [];
71         function filter(node, state)
72         {
73             if (predicate(node))
74                 nodes.push(node);
75             else
76                 state.skipChildNodes = true;
77         }
78
79         this._recurse(startNode, filter, this._defaultParserState());
80
81         return nodes;
82     }
83
84     containersOfOffset(offset)
85     {
86         console.assert(this._parsedSuccessfully);
87         if (!this._parsedSuccessfully)
88             return [];
89
90         let allNodes = [];
91         const start = 0;
92         const end = 1;
93
94         this.forEachNode((node, state) => {
95             if (node.range[end] < offset)
96                 state.skipChildNodes = true;
97             if (node.range[start] > offset)
98                 state.shouldStopEarly = true;
99             if (node.range[start] <= offset && node.range[end] >= offset)
100                 allNodes.push(node);
101         });
102
103         return allNodes;
104     }
105
106     filterByRange(startOffset, endOffset)
107     {
108         console.assert(this._parsedSuccessfully);
109         if (!this._parsedSuccessfully)
110             return [];
111
112         var allNodes = [];
113         var start = 0;
114         var end = 1;
115         function filterForNodesInRange(node, state)
116         {
117             // program start        range            program end
118             // [                 [         ]               ]
119             //            [ ]  [   [        ] ]  [ ]
120
121             // If a node's range ends before the range we're interested in starts, we don't need to search any of its
122             // enclosing ranges, because, by definition, those enclosing ranges are contained within this node's range.
123             if (node.range[end] < startOffset)
124                 state.skipChildNodes = true;
125
126             // We are only interested in nodes whose start position is within our range.
127             if (startOffset <= node.range[start] && node.range[start] <= endOffset)
128                 allNodes.push(node);
129
130             // Once we see nodes that start beyond our range, we can quit traversing the AST. We can do this safely
131             // because we know the AST is traversed using depth first search, so it will traverse into enclosing ranges
132             // before it traverses into adjacent ranges.
133             if (node.range[start] > endOffset)
134                 state.shouldStopEarly = true;
135         }
136
137         this.forEachNode(filterForNodesInRange);
138
139         return allNodes;
140     }
141
142     containsNonEmptyReturnStatement(startNode)
143     {
144         console.assert(startNode && this._parsedSuccessfully);
145         if (!this._parsedSuccessfully)
146             return false;
147
148         if (startNode.attachments._hasNonEmptyReturnStatement !== undefined)
149             return startNode.attachments._hasNonEmptyReturnStatement;
150
151         function removeFunctionsFilter(node)
152         {
153             return node.type !== WebInspector.ScriptSyntaxTree.NodeType.FunctionExpression
154                 && node.type !== WebInspector.ScriptSyntaxTree.NodeType.FunctionDeclaration
155                 && node.type !== WebInspector.ScriptSyntaxTree.NodeType.ArrowFunctionExpression;
156         }
157
158         var nodes = this.filter(removeFunctionsFilter, startNode);
159         var hasNonEmptyReturnStatement = false;
160         var returnStatementType = WebInspector.ScriptSyntaxTree.NodeType.ReturnStatement;
161         for (var node of nodes) {
162             if (node.type === returnStatementType && node.argument) {
163                 hasNonEmptyReturnStatement = true;
164                 break;
165             }
166         }
167
168         startNode.attachments._hasNonEmptyReturnStatement = hasNonEmptyReturnStatement;
169
170         return hasNonEmptyReturnStatement;
171     }
172
173     static functionReturnDivot(node)
174     {
175         console.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.FunctionDeclaration || node.type === WebInspector.ScriptSyntaxTree.NodeType.FunctionExpression || node.type === WebInspector.ScriptSyntaxTree.NodeType.MethodDefinition || node.type === WebInspector.ScriptSyntaxTree.NodeType.ArrowFunctionExpression);
176
177         // COMPATIBILITY (iOS 9): Legacy Backends view the return type as being the opening "{" of the function body.
178         // After iOS 9, this is to move to the start of the function statement/expression. See below:
179         // FIXME: Need a better way to determine backend versions. Using DOM.pseudoElement because that was added after iOS 9.
180         if (!DOMAgent.hasEvent("pseudoElementAdded"))
181             return node.body.range[0];
182
183         // "f" in "function". "s" in "set". "g" in "get". First letter in any method name for classes and object literals.
184         // The "[" for computed methods in classes and object literals.
185         return node.typeProfilingReturnDivot;
186     }
187
188     updateTypes(nodesToUpdate, callback)
189     {
190         console.assert(RuntimeAgent.getRuntimeTypesForVariablesAtOffsets);
191         console.assert(Array.isArray(nodesToUpdate) && this._parsedSuccessfully);
192
193         if (!this._parsedSuccessfully)
194             return;
195
196         var allRequests = [];
197         var allRequestNodes = [];
198         var sourceID = this._script.id;
199
200         for (var node of nodesToUpdate) {
201             switch (node.type) {
202             case WebInspector.ScriptSyntaxTree.NodeType.FunctionDeclaration:
203             case WebInspector.ScriptSyntaxTree.NodeType.FunctionExpression:
204             case WebInspector.ScriptSyntaxTree.NodeType.ArrowFunctionExpression:
205                 for (var param of node.params) {
206                     for (var identifier of this._gatherIdentifiersInDeclaration(param)) {
207                         allRequests.push({
208                             typeInformationDescriptor: WebInspector.ScriptSyntaxTree.TypeProfilerSearchDescriptor.NormalExpression,
209                             sourceID,
210                             divot: identifier.range[0]
211                         });
212                         allRequestNodes.push(identifier);
213                     }
214                 }
215
216                 allRequests.push({
217                     typeInformationDescriptor: WebInspector.ScriptSyntaxTree.TypeProfilerSearchDescriptor.FunctionReturn,
218                     sourceID,
219                     divot: WebInspector.ScriptSyntaxTree.functionReturnDivot(node)
220                 });
221                 allRequestNodes.push(node);
222                 break;
223             case WebInspector.ScriptSyntaxTree.NodeType.VariableDeclarator:
224                 for (var identifier of this._gatherIdentifiersInDeclaration(node.id)) {
225                     allRequests.push({
226                         typeInformationDescriptor: WebInspector.ScriptSyntaxTree.TypeProfilerSearchDescriptor.NormalExpression,
227                         sourceID,
228                         divot: identifier.range[0]
229                     });
230                     allRequestNodes.push(identifier);
231                 }
232                 break;
233             }
234         }
235
236         console.assert(allRequests.length === allRequestNodes.length);
237
238         function handleTypes(error, typeInformationArray)
239         {
240             if (error)
241                 return;
242
243             console.assert(typeInformationArray.length === allRequests.length);
244
245             for (var i = 0; i < typeInformationArray.length; i++) {
246                 var node = allRequestNodes[i];
247                 var typeInformation = WebInspector.TypeDescription.fromPayload(typeInformationArray[i]);
248                 if (allRequests[i].typeInformationDescriptor === WebInspector.ScriptSyntaxTree.TypeProfilerSearchDescriptor.FunctionReturn)
249                     node.attachments.returnTypes = typeInformation;
250                 else
251                     node.attachments.types = typeInformation;
252             }
253
254             callback(allRequestNodes);
255         }
256
257         this._script.target.RuntimeAgent.getRuntimeTypesForVariablesAtOffsets(allRequests, handleTypes);
258     }
259
260     // Private
261
262     _gatherIdentifiersInDeclaration(node)
263     {
264         function gatherIdentifiers(node)
265         {
266             switch (node.type) {
267                 case WebInspector.ScriptSyntaxTree.NodeType.Identifier:
268                     return [node];
269                 case WebInspector.ScriptSyntaxTree.NodeType.Property:
270                     return gatherIdentifiers(node.value);
271                 case WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern:
272                     var identifiers = [];
273                     for (var property of node.properties) {
274                         for (var identifier of gatherIdentifiers(property))
275                             identifiers.push(identifier);
276                     }
277                     return identifiers;
278                 case WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern:
279                     var identifiers = [];
280                     for (var element of node.elements) {
281                         for (var identifier of gatherIdentifiers(element))
282                             identifiers.push(identifier);
283                     }
284                     return identifiers;
285                 case WebInspector.ScriptSyntaxTree.NodeType.AssignmentPattern:
286                     return gatherIdentifiers(node.left);
287                 case WebInspector.ScriptSyntaxTree.NodeType.RestElement:
288                     return gatherIdentifiers(node.argument);
289                 default:
290                     console.assert(false, "Unexpected node type in variable declarator: " + node.type);
291                     return [];
292             }
293         }
294
295         console.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.Identifier || node.type === WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern || node.type === WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern || node.type === WebInspector.ScriptSyntaxTree.NodeType.RestElement);
296
297         return gatherIdentifiers(node);
298     }
299
300     _defaultParserState()
301     {
302         return {
303             shouldStopEarly: false,
304             skipChildNodes: false
305         };
306     }
307
308     _recurse(node, callback, state)
309     {
310         if (!node)
311             return;
312
313         if (state.shouldStopEarly || state.skipChildNodes)
314             return;
315
316         callback(node, state);
317
318         switch (node.type) {
319         case WebInspector.ScriptSyntaxTree.NodeType.AssignmentExpression:
320             this._recurse(node.left, callback, state);
321             this._recurse(node.right, callback, state);
322             break;
323         case WebInspector.ScriptSyntaxTree.NodeType.ArrayExpression:
324         case WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern:
325             this._recurseArray(node.elements, callback, state);
326             break;
327         case WebInspector.ScriptSyntaxTree.NodeType.AssignmentPattern:
328             this._recurse(node.left, callback, state);
329             this._recurse(node.right, callback, state);
330             break;
331         case WebInspector.ScriptSyntaxTree.NodeType.AwaitExpression:
332             this._recurse(node.argument, callback, state);
333             break;
334         case WebInspector.ScriptSyntaxTree.NodeType.BlockStatement:
335             this._recurseArray(node.body, callback, state);
336             break;
337         case WebInspector.ScriptSyntaxTree.NodeType.BinaryExpression:
338             this._recurse(node.left, callback, state);
339             this._recurse(node.right, callback, state);
340             break;
341         case WebInspector.ScriptSyntaxTree.NodeType.BreakStatement:
342             this._recurse(node.label, callback, state);
343             break;
344         case WebInspector.ScriptSyntaxTree.NodeType.CatchClause:
345             this._recurse(node.param, callback, state);
346             this._recurse(node.body, callback, state);
347             break;
348         case WebInspector.ScriptSyntaxTree.NodeType.CallExpression:
349             this._recurse(node.callee, callback, state);
350             this._recurseArray(node.arguments, callback, state);
351             break;
352         case WebInspector.ScriptSyntaxTree.NodeType.ClassBody:
353             this._recurseArray(node.body, callback, state);
354             break;
355         case WebInspector.ScriptSyntaxTree.NodeType.ClassDeclaration:
356         case WebInspector.ScriptSyntaxTree.NodeType.ClassExpression:
357             this._recurse(node.id, callback, state);
358             this._recurse(node.superClass, callback, state);
359             this._recurse(node.body, callback, state);
360             break;
361         case WebInspector.ScriptSyntaxTree.NodeType.ContinueStatement:
362             this._recurse(node.label, callback, state);
363             break;
364         case WebInspector.ScriptSyntaxTree.NodeType.DoWhileStatement:
365             this._recurse(node.body, callback, state);
366             this._recurse(node.test, callback, state);
367             break;
368         case WebInspector.ScriptSyntaxTree.NodeType.ExpressionStatement:
369             this._recurse(node.expression, callback, state);
370             break;
371         case WebInspector.ScriptSyntaxTree.NodeType.ForStatement:
372             this._recurse(node.init, callback, state);
373             this._recurse(node.test, callback, state);
374             this._recurse(node.update, callback, state);
375             this._recurse(node.body, callback, state);
376             break;
377         case WebInspector.ScriptSyntaxTree.NodeType.ForInStatement:
378         case WebInspector.ScriptSyntaxTree.NodeType.ForOfStatement:
379             this._recurse(node.left, callback, state);
380             this._recurse(node.right, callback, state);
381             this._recurse(node.body, callback, state);
382             break;
383         case WebInspector.ScriptSyntaxTree.NodeType.FunctionDeclaration:
384         case WebInspector.ScriptSyntaxTree.NodeType.FunctionExpression:
385         case WebInspector.ScriptSyntaxTree.NodeType.ArrowFunctionExpression:
386             this._recurse(node.id, callback, state);
387             this._recurseArray(node.params, callback, state);
388             this._recurse(node.body, callback, state);
389             break;
390         case WebInspector.ScriptSyntaxTree.NodeType.IfStatement:
391             this._recurse(node.test, callback, state);
392             this._recurse(node.consequent, callback, state);
393             this._recurse(node.alternate, callback, state);
394             break;
395         case WebInspector.ScriptSyntaxTree.NodeType.LabeledStatement:
396             this._recurse(node.label, callback, state);
397             this._recurse(node.body, callback, state);
398             break;
399         case WebInspector.ScriptSyntaxTree.NodeType.LogicalExpression:
400             this._recurse(node.left, callback, state);
401             this._recurse(node.right, callback, state);
402             break;
403         case WebInspector.ScriptSyntaxTree.NodeType.MemberExpression:
404             this._recurse(node.object, callback, state);
405             this._recurse(node.property, callback, state);
406             break;
407         case WebInspector.ScriptSyntaxTree.NodeType.MethodDefinition:
408             this._recurse(node.key, callback, state);
409             this._recurse(node.value, callback, state);
410             break;
411         case WebInspector.ScriptSyntaxTree.NodeType.NewExpression:
412             this._recurse(node.callee, callback, state);
413             this._recurseArray(node.arguments, callback, state);
414             break;
415         case WebInspector.ScriptSyntaxTree.NodeType.ObjectExpression:
416         case WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern:
417             this._recurseArray(node.properties, callback, state);
418             break;
419         case WebInspector.ScriptSyntaxTree.NodeType.Program:
420             this._recurseArray(node.body, callback, state);
421             break;
422         case WebInspector.ScriptSyntaxTree.NodeType.Property:
423             this._recurse(node.key, callback, state);
424             this._recurse(node.value, callback, state);
425             break;
426         case WebInspector.ScriptSyntaxTree.NodeType.RestElement:
427             this._recurse(node.argument, callback, state);
428             break;
429         case WebInspector.ScriptSyntaxTree.NodeType.ReturnStatement:
430             this._recurse(node.argument, callback, state);
431             break;
432         case WebInspector.ScriptSyntaxTree.NodeType.SequenceExpression:
433             this._recurseArray(node.expressions, callback, state);
434             break;
435         case WebInspector.ScriptSyntaxTree.NodeType.SpreadElement:
436             this._recurse(node.argument, callback, state);
437             break;
438         case WebInspector.ScriptSyntaxTree.NodeType.SwitchStatement:
439             this._recurse(node.discriminant, callback, state);
440             this._recurseArray(node.cases, callback, state);
441             break;
442         case WebInspector.ScriptSyntaxTree.NodeType.SwitchCase:
443             this._recurse(node.test, callback, state);
444             this._recurseArray(node.consequent, callback, state);
445             break;
446         case WebInspector.ScriptSyntaxTree.NodeType.ConditionalExpression:
447             this._recurse(node.test, callback, state);
448             this._recurse(node.consequent, callback, state);
449             this._recurse(node.alternate, callback, state);
450             break;
451         case WebInspector.ScriptSyntaxTree.NodeType.TaggedTemplateExpression:
452             this._recurse(node.tag, callback, state);
453             this._recurse(node.quasi, callback, state);
454             break;
455         case WebInspector.ScriptSyntaxTree.NodeType.TemplateLiteral:
456             this._recurseArray(node.quasis, callback, state);
457             this._recurseArray(node.expressions, callback, state);
458             break;
459         case WebInspector.ScriptSyntaxTree.NodeType.ThrowStatement:
460             this._recurse(node.argument, callback, state);
461             break;
462         case WebInspector.ScriptSyntaxTree.NodeType.TryStatement:
463             this._recurse(node.block, callback, state);
464             this._recurse(node.handler, callback, state);
465             this._recurse(node.finalizer, callback, state);
466             break;
467         case WebInspector.ScriptSyntaxTree.NodeType.UnaryExpression:
468             this._recurse(node.argument, callback, state);
469             break;
470         case WebInspector.ScriptSyntaxTree.NodeType.UpdateExpression:
471             this._recurse(node.argument, callback, state);
472             break;
473         case WebInspector.ScriptSyntaxTree.NodeType.VariableDeclaration:
474             this._recurseArray(node.declarations, callback, state);
475             break;
476         case WebInspector.ScriptSyntaxTree.NodeType.VariableDeclarator:
477             this._recurse(node.id, callback, state);
478             this._recurse(node.init, callback, state);
479             break;
480         case WebInspector.ScriptSyntaxTree.NodeType.WhileStatement:
481             this._recurse(node.test, callback, state);
482             this._recurse(node.body, callback, state);
483             break;
484         case WebInspector.ScriptSyntaxTree.NodeType.WithStatement:
485             this._recurse(node.object, callback, state);
486             this._recurse(node.body, callback, state);
487             break;
488         case WebInspector.ScriptSyntaxTree.NodeType.YieldExpression:
489             this._recurse(node.argument, callback, state);
490             break;
491
492         // Modules.
493
494         case WebInspector.ScriptSyntaxTree.NodeType.ExportAllDeclaration:
495             this._recurse(node.source, callback, state);
496             break;
497         case WebInspector.ScriptSyntaxTree.NodeType.ExportNamedDeclaration:
498             this._recurse(node.declaration, callback, state);
499             this._recurseArray(node.specifiers, callback, state);
500             this._recurse(node.source, callback, state);
501             break;
502         case WebInspector.ScriptSyntaxTree.NodeType.ExportDefaultDeclaration:
503             this._recurse(node.declaration, callback, state);
504             break;
505         case WebInspector.ScriptSyntaxTree.NodeType.ExportSpecifier:
506             this._recurse(node.local, callback, state);
507             this._recurse(node.exported, callback, state);
508             break;
509         case WebInspector.ScriptSyntaxTree.NodeType.ImportDeclaration:
510             this._recurseArray(node.specifiers, callback, state);
511             this._recurse(node.source, callback, state);
512             break;
513         case WebInspector.ScriptSyntaxTree.NodeType.ImportDefaultSpecifier:
514             this._recurse(node.local, callback, state);
515             break;
516         case WebInspector.ScriptSyntaxTree.NodeType.ImportNamespaceSpecifier:
517             this._recurse(node.local, callback, state);
518             break;
519         case WebInspector.ScriptSyntaxTree.NodeType.ImportSpecifier:
520             this._recurse(node.imported, callback, state);
521             this._recurse(node.local, callback, state);
522             break;
523
524         // All the leaf nodes go here.
525         case WebInspector.ScriptSyntaxTree.NodeType.DebuggerStatement:
526         case WebInspector.ScriptSyntaxTree.NodeType.EmptyStatement:
527         case WebInspector.ScriptSyntaxTree.NodeType.Identifier:
528         case WebInspector.ScriptSyntaxTree.NodeType.Literal:
529         case WebInspector.ScriptSyntaxTree.NodeType.MetaProperty:
530         case WebInspector.ScriptSyntaxTree.NodeType.Super:
531         case WebInspector.ScriptSyntaxTree.NodeType.ThisExpression:
532         case WebInspector.ScriptSyntaxTree.NodeType.TemplateElement:
533             break;
534         }
535
536         state.skipChildNodes = false;
537     }
538
539     _recurseArray(array, callback, state)
540     {
541         for (var node of array)
542             this._recurse(node, callback, state);
543     }
544
545     // This function translates from esprima's Abstract Syntax Tree to ours.
546     // Mostly, this is just the identity function. We've added an extra typeProfilingReturnDivot property for functions/methods.
547     // Our AST complies with the Mozilla parser API:
548     // https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API
549     _createInternalSyntaxTree(node)
550     {
551         if (!node)
552             return null;
553
554         var result = null;
555         switch (node.type) {
556         case "ArrayExpression":
557             result = {
558                 type: WebInspector.ScriptSyntaxTree.NodeType.ArrayExpression,
559                 elements: node.elements.map(this._createInternalSyntaxTree, this)
560             };
561             break;
562         case "ArrayPattern":
563             result = {
564                 type: WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern,
565                 elements: node.elements.map(this._createInternalSyntaxTree, this)
566             };
567             break;
568         case "ArrowFunctionExpression":
569             result = {
570                 type: WebInspector.ScriptSyntaxTree.NodeType.ArrowFunctionExpression,
571                 id: this._createInternalSyntaxTree(node.id),
572                 params: node.params.map(this._createInternalSyntaxTree, this),
573                 body: this._createInternalSyntaxTree(node.body),
574                 generator: node.generator,
575                 expression: node.expression, // Boolean indicating if the body a single expression or a block statement.
576                 async: node.async,
577                 typeProfilingReturnDivot: node.range[0]
578             };
579             break;
580         case "AssignmentExpression":
581             result = {
582                 type: WebInspector.ScriptSyntaxTree.NodeType.AssignmentExpression,
583                 operator: node.operator,
584                 left: this._createInternalSyntaxTree(node.left),
585                 right: this._createInternalSyntaxTree(node.right)
586             };
587             break;
588         case "AssignmentPattern":
589             result = {
590                 type: WebInspector.ScriptSyntaxTree.NodeType.AssignmentPattern,
591                 left: this._createInternalSyntaxTree(node.left),
592                 right: this._createInternalSyntaxTree(node.right),
593             };
594             break;
595         case "AwaitExpression":
596             result = {
597                 type: WebInspector.ScriptSyntaxTree.NodeType.AwaitExpression,
598                 argument: this._createInternalSyntaxTree(node.argument),
599             };
600             break;
601         case "BlockStatement":
602             result = {
603                 type: WebInspector.ScriptSyntaxTree.NodeType.BlockStatement,
604                 body: node.body.map(this._createInternalSyntaxTree, this)
605             };
606             break;
607         case "BinaryExpression":
608             result = {
609                 type: WebInspector.ScriptSyntaxTree.NodeType.BinaryExpression,
610                 operator: node.operator,
611                 left: this._createInternalSyntaxTree(node.left),
612                 right: this._createInternalSyntaxTree(node.right)
613             };
614             break;
615         case "BreakStatement":
616             result = {
617                 type: WebInspector.ScriptSyntaxTree.NodeType.BreakStatement,
618                 label: this._createInternalSyntaxTree(node.label)
619             };
620             break;
621         case "CallExpression":
622             result = {
623                 type: WebInspector.ScriptSyntaxTree.NodeType.CallExpression,
624                 callee: this._createInternalSyntaxTree(node.callee),
625                 arguments: node.arguments.map(this._createInternalSyntaxTree, this)
626             };
627             break;
628         case "CatchClause":
629             result = {
630                 type: WebInspector.ScriptSyntaxTree.NodeType.CatchClause,
631                 param: this._createInternalSyntaxTree(node.param),
632                 body: this._createInternalSyntaxTree(node.body)
633             };
634             break;
635         case "ClassBody":
636             result = {
637                 type: WebInspector.ScriptSyntaxTree.NodeType.ClassBody,
638                 body: node.body.map(this._createInternalSyntaxTree, this)
639             };
640             break;
641         case "ClassDeclaration":
642             result = {
643                 type: WebInspector.ScriptSyntaxTree.NodeType.ClassDeclaration,
644                 id: this._createInternalSyntaxTree(node.id),
645                 superClass: this._createInternalSyntaxTree(node.superClass),
646                 body: this._createInternalSyntaxTree(node.body),
647             };
648             break;
649         case "ClassExpression":
650             result = {
651                 type: WebInspector.ScriptSyntaxTree.NodeType.ClassExpression,
652                 id: this._createInternalSyntaxTree(node.id),
653                 superClass: this._createInternalSyntaxTree(node.superClass),
654                 body: this._createInternalSyntaxTree(node.body),
655             };
656             break;
657         case "ConditionalExpression":
658             result = {
659                 type: WebInspector.ScriptSyntaxTree.NodeType.ConditionalExpression,
660                 test: this._createInternalSyntaxTree(node.test),
661                 consequent: this._createInternalSyntaxTree(node.consequent),
662                 alternate: this._createInternalSyntaxTree(node.alternate)
663             };
664             break;
665         case "ContinueStatement":
666             result = {
667                 type: WebInspector.ScriptSyntaxTree.NodeType.ContinueStatement,
668                 label: this._createInternalSyntaxTree(node.label)
669             };
670             break;
671         case "DoWhileStatement":
672             result = {
673                 type: WebInspector.ScriptSyntaxTree.NodeType.DoWhileStatement,
674                 body: this._createInternalSyntaxTree(node.body),
675                 test: this._createInternalSyntaxTree(node.test)
676             };
677             break;
678         case "DebuggerStatement":
679             result = {
680                 type: WebInspector.ScriptSyntaxTree.NodeType.DebuggerStatement
681             };
682             break;
683         case "EmptyStatement":
684             result = {
685                 type: WebInspector.ScriptSyntaxTree.NodeType.EmptyStatement
686             };
687             break;
688         case "ExpressionStatement":
689             result = {
690                 type: WebInspector.ScriptSyntaxTree.NodeType.ExpressionStatement,
691                 expression: this._createInternalSyntaxTree(node.expression)
692             };
693             break;
694         case "ForStatement":
695             result = {
696                 type: WebInspector.ScriptSyntaxTree.NodeType.ForStatement,
697                 init: this._createInternalSyntaxTree(node.init),
698                 test: this._createInternalSyntaxTree(node.test),
699                 update: this._createInternalSyntaxTree(node.update),
700                 body: this._createInternalSyntaxTree(node.body)
701             };
702             break;
703         case "ForInStatement":
704             result = {
705                 type: WebInspector.ScriptSyntaxTree.NodeType.ForInStatement,
706                 left: this._createInternalSyntaxTree(node.left),
707                 right: this._createInternalSyntaxTree(node.right),
708                 body: this._createInternalSyntaxTree(node.body)
709             };
710             break;
711         case "ForOfStatement":
712             result = {
713                 type: WebInspector.ScriptSyntaxTree.NodeType.ForOfStatement,
714                 left: this._createInternalSyntaxTree(node.left),
715                 right: this._createInternalSyntaxTree(node.right),
716                 body: this._createInternalSyntaxTree(node.body)
717             };
718             break;
719         case "FunctionDeclaration":
720             result = {
721                 type: WebInspector.ScriptSyntaxTree.NodeType.FunctionDeclaration,
722                 id: this._createInternalSyntaxTree(node.id),
723                 params: node.params.map(this._createInternalSyntaxTree, this),
724                 body: this._createInternalSyntaxTree(node.body),
725                 generator: node.generator,
726                 async: node.async,
727                 typeProfilingReturnDivot: node.range[0]
728             };
729             break;
730         case "FunctionExpression":
731             result = {
732                 type: WebInspector.ScriptSyntaxTree.NodeType.FunctionExpression,
733                 id: this._createInternalSyntaxTree(node.id),
734                 params: node.params.map(this._createInternalSyntaxTree, this),
735                 body: this._createInternalSyntaxTree(node.body),
736                 generator: node.generator,
737                 async: node.async,
738                 typeProfilingReturnDivot: node.range[0] // This may be overridden in the Property AST node.
739             };
740             break;
741         case "Identifier":
742             result = {
743                 type: WebInspector.ScriptSyntaxTree.NodeType.Identifier,
744                 name: node.name
745             };
746             break;
747         case "IfStatement":
748             result = {
749                 type: WebInspector.ScriptSyntaxTree.NodeType.IfStatement,
750                 test: this._createInternalSyntaxTree(node.test),
751                 consequent: this._createInternalSyntaxTree(node.consequent),
752                 alternate: this._createInternalSyntaxTree(node.alternate)
753             };
754             break;
755         case "Literal":
756             result = {
757                 type: WebInspector.ScriptSyntaxTree.NodeType.Literal,
758                 value: node.value,
759                 raw: node.raw
760             };
761             break;
762         case "LabeledStatement":
763             result = {
764                 type: WebInspector.ScriptSyntaxTree.NodeType.LabeledStatement,
765                 label: this._createInternalSyntaxTree(node.label),
766                 body: this._createInternalSyntaxTree(node.body)
767             };
768             break;
769         case "LogicalExpression":
770             result = {
771                 type: WebInspector.ScriptSyntaxTree.NodeType.LogicalExpression,
772                 left: this._createInternalSyntaxTree(node.left),
773                 right: this._createInternalSyntaxTree(node.right),
774                 operator: node.operator
775             };
776             break;
777         case "MemberExpression":
778             result = {
779                 type: WebInspector.ScriptSyntaxTree.NodeType.MemberExpression,
780                 object: this._createInternalSyntaxTree(node.object),
781                 property: this._createInternalSyntaxTree(node.property),
782                 computed: node.computed
783             };
784             break;
785         case "MetaProperty":
786             // i.e: new.target produces {meta: "new", property: "target"}
787             result = {
788                 type: WebInspector.ScriptSyntaxTree.NodeType.MetaProperty,
789                 meta: this._createInternalSyntaxTree(node.meta),
790                 property: this._createInternalSyntaxTree(node.property),
791             };
792             break;
793         case "MethodDefinition":
794             result = {
795                 type: WebInspector.ScriptSyntaxTree.NodeType.MethodDefinition,
796                 key: this._createInternalSyntaxTree(node.key),
797                 value: this._createInternalSyntaxTree(node.value),
798                 computed: node.computed,
799                 kind: node.kind,
800                 static: node.static
801             };
802             result.value.typeProfilingReturnDivot = node.range[0]; // "g" in "get" or "s" in "set" or "[" in "['computed']" or "m" in "methodName".
803             break;
804         case "NewExpression":
805             result = {
806                 type: WebInspector.ScriptSyntaxTree.NodeType.NewExpression,
807                 callee: this._createInternalSyntaxTree(node.callee),
808                 arguments: node.arguments.map(this._createInternalSyntaxTree, this)
809             };
810             break;
811         case "ObjectExpression":
812             result = {
813                 type: WebInspector.ScriptSyntaxTree.NodeType.ObjectExpression,
814                 properties: node.properties.map(this._createInternalSyntaxTree, this)
815             };
816             break;
817         case "ObjectPattern":
818             result = {
819                 type: WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern,
820                 properties: node.properties.map(this._createInternalSyntaxTree, this)
821             };
822             break;
823         case "Program":
824             result = {
825                 type: WebInspector.ScriptSyntaxTree.NodeType.Program,
826                 sourceType: node.sourceType,
827                 body: node.body.map(this._createInternalSyntaxTree, this)
828             };
829             break;
830         case "Property":
831             result = {
832                 type: WebInspector.ScriptSyntaxTree.NodeType.Property,
833                 key: this._createInternalSyntaxTree(node.key),
834                 value: this._createInternalSyntaxTree(node.value),
835                 kind: node.kind,
836                 method: node.method,
837                 computed: node.computed
838             };
839             if (result.kind === "get" || result.kind === "set" || result.method)
840                 result.value.typeProfilingReturnDivot = node.range[0];  // "g" in "get" or "s" in "set" or "[" in "['computed']" method or "m" in "methodName".
841             break;
842         case "RestElement":
843             result = {
844                 type: WebInspector.ScriptSyntaxTree.NodeType.RestElement,
845                 argument: this._createInternalSyntaxTree(node.argument)
846             };
847             break;
848         case "ReturnStatement":
849             result = {
850                 type: WebInspector.ScriptSyntaxTree.NodeType.ReturnStatement,
851                 argument: this._createInternalSyntaxTree(node.argument)
852             };
853             break;
854         case "SequenceExpression":
855             result = {
856                 type: WebInspector.ScriptSyntaxTree.NodeType.SequenceExpression,
857                 expressions: node.expressions.map(this._createInternalSyntaxTree, this)
858             };
859             break;
860         case "SpreadElement":
861             result = {
862                 type: WebInspector.ScriptSyntaxTree.NodeType.SpreadElement,
863                 argument: this._createInternalSyntaxTree(node.argument),
864             };
865             break;
866         case "Super":
867             result = {
868                 type: WebInspector.ScriptSyntaxTree.NodeType.Super
869             };
870             break;
871         case "SwitchStatement":
872             result = {
873                 type: WebInspector.ScriptSyntaxTree.NodeType.SwitchStatement,
874                 discriminant: this._createInternalSyntaxTree(node.discriminant),
875                 cases: node.cases.map(this._createInternalSyntaxTree, this)
876             };
877             break;
878         case "SwitchCase":
879             result = {
880                 type: WebInspector.ScriptSyntaxTree.NodeType.SwitchCase,
881                 test: this._createInternalSyntaxTree(node.test),
882                 consequent: node.consequent.map(this._createInternalSyntaxTree, this)
883             };
884             break;
885         case "TaggedTemplateExpression":
886             result = {
887                 type: WebInspector.ScriptSyntaxTree.NodeType.TaggedTemplateExpression,
888                 tag: this._createInternalSyntaxTree(node.tag),
889                 quasi: this._createInternalSyntaxTree(node.quasi)
890             };
891             break;
892         case "TemplateElement":
893             result = {
894                 type: WebInspector.ScriptSyntaxTree.NodeType.TemplateElement,
895                 value: node.value,
896                 tail: node.tail
897             };
898             break;
899         case "TemplateLiteral":
900             result = {
901                 type: WebInspector.ScriptSyntaxTree.NodeType.TemplateLiteral,
902                 quasis: node.quasis.map(this._createInternalSyntaxTree, this),
903                 expressions: node.expressions.map(this._createInternalSyntaxTree, this)
904             };
905             break;
906         case "ThisExpression":
907             result = {
908                 type: WebInspector.ScriptSyntaxTree.NodeType.ThisExpression
909             };
910             break;
911         case "ThrowStatement":
912             result = {
913                 type: WebInspector.ScriptSyntaxTree.NodeType.ThrowStatement,
914                 argument: this._createInternalSyntaxTree(node.argument)
915             };
916             break;
917         case "TryStatement":
918             result = {
919                 type: WebInspector.ScriptSyntaxTree.NodeType.TryStatement,
920                 block: this._createInternalSyntaxTree(node.block),
921                 handler: this._createInternalSyntaxTree(node.handler),
922                 finalizer: this._createInternalSyntaxTree(node.finalizer)
923             };
924             break;
925         case "UnaryExpression":
926             result = {
927                 type: WebInspector.ScriptSyntaxTree.NodeType.UnaryExpression,
928                 operator: node.operator,
929                 argument: this._createInternalSyntaxTree(node.argument)
930             };
931             break;
932         case "UpdateExpression":
933             result = {
934                 type: WebInspector.ScriptSyntaxTree.NodeType.UpdateExpression,
935                 operator: node.operator,
936                 prefix: node.prefix,
937                 argument: this._createInternalSyntaxTree(node.argument)
938             };
939             break;
940         case "VariableDeclaration":
941             result = {
942                 type: WebInspector.ScriptSyntaxTree.NodeType.VariableDeclaration,
943                 declarations: node.declarations.map(this._createInternalSyntaxTree, this),
944                 kind: node.kind
945             };
946             break;
947         case "VariableDeclarator":
948             result = {
949                 type: WebInspector.ScriptSyntaxTree.NodeType.VariableDeclarator,
950                 id: this._createInternalSyntaxTree(node.id),
951                 init: this._createInternalSyntaxTree(node.init)
952             };
953             break;
954         case "WhileStatement":
955             result = {
956                 type: WebInspector.ScriptSyntaxTree.NodeType.WhileStatement,
957                 test: this._createInternalSyntaxTree(node.test),
958                 body: this._createInternalSyntaxTree(node.body)
959             };
960             break;
961         case "WithStatement":
962             result = {
963                 type: WebInspector.ScriptSyntaxTree.NodeType.WithStatement,
964                 object: this._createInternalSyntaxTree(node.object),
965                 body: this._createInternalSyntaxTree(node.body)
966             };
967             break;
968         case "YieldExpression":
969             result = {
970                 type: WebInspector.ScriptSyntaxTree.NodeType.YieldExpression,
971                 argument: this._createInternalSyntaxTree(node.argument),
972                 delegate: node.delegate
973             };
974             break;
975
976         // Modules.
977
978         case "ExportAllDeclaration":
979             result = {
980                 type: WebInspector.ScriptSyntaxTree.NodeType.ExportAllDeclaration,
981                 source: this._createInternalSyntaxTree(node.source),
982             };
983             break;
984         case "ExportNamedDeclaration":
985             result = {
986                 type: WebInspector.ScriptSyntaxTree.NodeType.ExportNamedDeclaration,
987                 declaration: this._createInternalSyntaxTree(node.declaration),
988                 specifiers: node.specifiers.map(this._createInternalSyntaxTree, this),
989                 source: this._createInternalSyntaxTree(node.source),
990             };
991             break;
992         case "ExportDefaultDeclaration":
993             result = {
994                 type: WebInspector.ScriptSyntaxTree.NodeType.ExportDefaultDeclaration,
995                 declaration: this._createInternalSyntaxTree(node.declaration),
996             };
997             break;
998         case "ExportSpecifier":
999             result = {
1000                 type: WebInspector.ScriptSyntaxTree.NodeType.ExportSpecifier,
1001                 local: this._createInternalSyntaxTree(node.local),
1002                 exported: this._createInternalSyntaxTree(node.exported),
1003             };
1004             break;
1005         case "ImportDeclaration":
1006             result = {
1007                 type: WebInspector.ScriptSyntaxTree.NodeType.ImportDeclaration,
1008                 specifiers: node.specifiers.map(this._createInternalSyntaxTree, this),
1009                 source: this._createInternalSyntaxTree(node.source),
1010             };
1011             break;
1012         case "ImportDefaultSpecifier":
1013             result = {
1014                 type: WebInspector.ScriptSyntaxTree.NodeType.ImportDefaultSpecifier,
1015                 local: this._createInternalSyntaxTree(node.local),
1016             };
1017             break;
1018         case "ImportNamespaceSpecifier":
1019             result = {
1020                 type: WebInspector.ScriptSyntaxTree.NodeType.ImportNamespaceSpecifier,
1021                 local: this._createInternalSyntaxTree(node.local),
1022             };
1023             break;
1024         case "ImportSpecifier":
1025             result = {
1026                 type: WebInspector.ScriptSyntaxTree.NodeType.ImportSpecifier,
1027                 imported: this._createInternalSyntaxTree(node.imported),
1028                 local: this._createInternalSyntaxTree(node.local),
1029             };
1030             break;
1031
1032         default:
1033             console.error("Unsupported Syntax Tree Node: " + node.type, node);
1034             return null;
1035         }
1036
1037         result.range = node.range;
1038         // This is an object for which you can add fields to an AST node without worrying about polluting the syntax-related fields of the node.
1039         result.attachments = {};
1040
1041         return result;
1042     }
1043 };
1044
1045 // This should be kept in sync with an enum in JavaSciptCore/runtime/TypeProfiler.h
1046 WebInspector.ScriptSyntaxTree.TypeProfilerSearchDescriptor = {
1047     NormalExpression: 1,
1048     FunctionReturn: 2
1049 };
1050
1051 WebInspector.ScriptSyntaxTree.NodeType = {
1052     ArrayExpression: Symbol("array-expression"),
1053     ArrayPattern: Symbol("array-pattern"),
1054     ArrowFunctionExpression: Symbol("arrow-function-expression"),
1055     AssignmentExpression: Symbol("assignment-expression"),
1056     AssignmentPattern: Symbol("assignment-pattern"),
1057     AwaitExpression: Symbol("await-expression"),
1058     BinaryExpression: Symbol("binary-expression"),
1059     BlockStatement: Symbol("block-statement"),
1060     BreakStatement: Symbol("break-statement"),
1061     CallExpression: Symbol("call-expression"),
1062     CatchClause: Symbol("catch-clause"),
1063     ClassBody: Symbol("class-body"),
1064     ClassDeclaration: Symbol("class-declaration"),
1065     ClassExpression: Symbol("class-expression"),
1066     ConditionalExpression: Symbol("conditional-expression"),
1067     ContinueStatement: Symbol("continue-statement"),
1068     DebuggerStatement: Symbol("debugger-statement"),
1069     DoWhileStatement: Symbol("do-while-statement"),
1070     EmptyStatement: Symbol("empty-statement"),
1071     ExportAllDeclaration: Symbol("export-all-declaration"),
1072     ExportDefaultDeclaration: Symbol("export-default-declaration"),
1073     ExportNamedDeclaration: Symbol("export-named-declaration"),
1074     ExportSpecifier: Symbol("export-specifier"),
1075     ExpressionStatement: Symbol("expression-statement"),
1076     ForInStatement: Symbol("for-in-statement"),
1077     ForOfStatement: Symbol("for-of-statement"),
1078     ForStatement: Symbol("for-statement"),
1079     FunctionDeclaration: Symbol("function-declaration"),
1080     FunctionExpression: Symbol("function-expression"),
1081     Identifier: Symbol("identifier"),
1082     IfStatement: Symbol("if-statement"),
1083     ImportDeclaration: Symbol("import-declaration"),
1084     ImportDefaultSpecifier: Symbol("import-default-specifier"),
1085     ImportNamespaceSpecifier: Symbol("import-namespace-specifier"),
1086     ImportSpecifier: Symbol("import-specifier"),
1087     LabeledStatement: Symbol("labeled-statement"),
1088     Literal: Symbol("literal"),
1089     LogicalExpression: Symbol("logical-expression"),
1090     MemberExpression: Symbol("member-expression"),
1091     MetaProperty: Symbol("meta-property"),
1092     MethodDefinition: Symbol("method-definition"),
1093     NewExpression: Symbol("new-expression"),
1094     ObjectExpression: Symbol("object-expression"),
1095     ObjectPattern: Symbol("object-pattern"),
1096     Program: Symbol("program"),
1097     Property: Symbol("property"),
1098     RestElement: Symbol("rest-element"),
1099     ReturnStatement: Symbol("return-statement"),
1100     SequenceExpression: Symbol("sequence-expression"),
1101     SpreadElement: Symbol("spread-element"),
1102     Super: Symbol("super"),
1103     SwitchCase: Symbol("switch-case"),
1104     SwitchStatement: Symbol("switch-statement"),
1105     TaggedTemplateExpression: Symbol("tagged-template-expression"),
1106     TemplateElement: Symbol("template-element"),
1107     TemplateLiteral: Symbol("template-literal"),
1108     ThisExpression: Symbol("this-expression"),
1109     ThrowStatement: Symbol("throw-statement"),
1110     TryStatement: Symbol("try-statement"),
1111     UnaryExpression: Symbol("unary-expression"),
1112     UpdateExpression: Symbol("update-expression"),
1113     VariableDeclaration: Symbol("variable-declaration"),
1114     VariableDeclarator: Symbol("variable-declarator"),
1115     WhileStatement: Symbol("while-statement"),
1116     WithStatement: Symbol("with-statement"),
1117     YieldExpression: Symbol("yield-expression"),
1118 };