<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[180388] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/180388">180388</a></dd>
<dt>Author</dt> <dd>saambarati1@gmail.com</dd>
<dt>Date</dt> <dd>2015-02-19 22:33:49 -0800 (Thu, 19 Feb 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>Web Inspector: merge in upstream Esprima to support parsing more of ES6
https://bugs.webkit.org/show_bug.cgi?id=141215
Reviewed by Timothy Hatcher.
Source/WebInspectorUI:
This patch merges in a new esprima that has some ES6 support.
Specifically, the ES6 support ScriptSyntaxTree now has is:
- ForOf loops
- Object destructuring
- Array destructuring
ScriptSyntaxTree now uses Symbols for identifying AST node types
instead of strings. This will prevent any direct usage of strings
for node types instead of a direct property access off the
ScriptSyntaxTree constructor.
This patch also does some gardening work:
- TypeTokenAnnotator only walks over the incoming type information
data once to be more efficient.
- TypeTokenView is now smarter about updating its associated DOM node
only if its display name has changed.
* UserInterface/Controllers/TypeTokenAnnotator.js:
(WebInspector.TypeTokenAnnotator.prototype._insertTypeTokensForEachNode):
* UserInterface/External/Esprima/esprima.js:
(.):
* UserInterface/Models/ScriptSyntaxTree.js:
(WebInspector.ScriptSyntaxTree.prototype.gatherIdentifiersInVariableDeclaration):
(WebInspector.ScriptSyntaxTree.prototype._recurse):
(WebInspector.ScriptSyntaxTree.prototype._createInternalSyntaxTree):
* UserInterface/Views/TypeTokenView.js:
(WebInspector.TypeTokenView.prototype.update):
LayoutTests:
* inspector/model/parse-script-syntax-tree-expected.txt:
* inspector/model/parse-script-syntax-tree.html:</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsinspectormodelparsescriptsyntaxtreeexpectedtxt">trunk/LayoutTests/inspector/model/parse-script-syntax-tree-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectormodelparsescriptsyntaxtreehtml">trunk/LayoutTests/inspector/model/parse-script-syntax-tree.html</a></li>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersTypeTokenAnnotatorjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/TypeTokenAnnotator.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalEsprimaesprimajs">trunk/Source/WebInspectorUI/UserInterface/External/Esprima/esprima.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsScriptSyntaxTreejs">trunk/Source/WebInspectorUI/UserInterface/Models/ScriptSyntaxTree.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTypeTokenViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/TypeTokenView.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (180387 => 180388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-02-20 06:31:55 UTC (rev 180387)
+++ trunk/LayoutTests/ChangeLog        2015-02-20 06:33:49 UTC (rev 180388)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2015-02-19 Saam Barati <saambarati1@gmail.com>
+
+ Web Inspector: merge in upstream Esprima to support parsing more of ES6
+ https://bugs.webkit.org/show_bug.cgi?id=141215
+
+ Reviewed by Timothy Hatcher.
+
+ * inspector/model/parse-script-syntax-tree-expected.txt:
+ * inspector/model/parse-script-syntax-tree.html:
+
</ins><span class="cx"> 2015-02-19 Myles C. Maxfield <mmaxfield@apple.com>
</span><span class="cx">
</span><span class="cx"> Updating more tests after r177774
</span></span></pre></div>
<a id="trunkLayoutTestsinspectormodelparsescriptsyntaxtreeexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector/model/parse-script-syntax-tree-expected.txt (180387 => 180388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/model/parse-script-syntax-tree-expected.txt        2015-02-20 06:31:55 UTC (rev 180387)
+++ trunk/LayoutTests/inspector/model/parse-script-syntax-tree-expected.txt        2015-02-20 06:33:49 UTC (rev 180388)
</span><span class="lines">@@ -14,6 +14,7 @@
</span><span class="cx"> passed ExpressionStatement
</span><span class="cx"> passed ForStatement
</span><span class="cx"> passed ForInStatement
</span><ins>+passed ForOfStatement
</ins><span class="cx"> passed FunctionDeclaration
</span><span class="cx"> passed FunctionExpression
</span><span class="cx"> passed Identifier
</span></span></pre></div>
<a id="trunkLayoutTestsinspectormodelparsescriptsyntaxtreehtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector/model/parse-script-syntax-tree.html (180387 => 180388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/model/parse-script-syntax-tree.html        2015-02-20 06:31:55 UTC (rev 180387)
+++ trunk/LayoutTests/inspector/model/parse-script-syntax-tree.html        2015-02-20 06:33:49 UTC (rev 180388)
</span><span class="lines">@@ -30,6 +30,15 @@
</span><span class="cx"> InspectorTest.assert(node.right);
</span><span class="cx"> InspectorTest.assert(node.right.type === WebInspector.ScriptSyntaxTree.NodeType.Literal);
</span><span class="cx"> InspectorTest.assert(node.operator === "=");
</span><ins>+ node = makeNode("[x, y] = foo;", true);
+ InspectorTest.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.AssignmentExpression);
+ InspectorTest.assert(node.left);
+ InspectorTest.assert(node.left.type === WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern);
+ InspectorTest.assert(node.left.elements.length === 2);
+ InspectorTest.assert(node.left.elements[0].type === WebInspector.ScriptSyntaxTree.NodeType.Identifier);
+ InspectorTest.assert(node.left.elements[0].name === "x");
+ InspectorTest.assert(node.left.elements[1].type === WebInspector.ScriptSyntaxTree.NodeType.Identifier);
+ InspectorTest.assert(node.left.elements[1].name === "y");
</ins><span class="cx"> node = makeNode("x += 20;", true);
</span><span class="cx"> InspectorTest.assert(node.operator === "+=");
</span><span class="cx"> node = makeNode("x -= 20;", true);
</span><span class="lines">@@ -161,6 +170,22 @@
</span><span class="cx"> InspectorTest.assert(node.body.type === WebInspector.ScriptSyntaxTree.NodeType.EmptyStatement);
</span><span class="cx"> InspectorTest.log("passed ForInStatement");
</span><span class="cx">
</span><ins>+ node = makeNode("for(var x of {});", false);
+ InspectorTest.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.ForOfStatement);
+ InspectorTest.assert(node.left);
+ InspectorTest.assert(node.left.type === WebInspector.ScriptSyntaxTree.NodeType.VariableDeclaration);
+ InspectorTest.assert(node.right);
+ InspectorTest.assert(node.right.type === WebInspector.ScriptSyntaxTree.NodeType.ObjectExpression);
+ InspectorTest.assert(node.body);
+ InspectorTest.assert(node.body.type === WebInspector.ScriptSyntaxTree.NodeType.EmptyStatement);
+ node = makeNode("for(var {x} of {});", false);
+ InspectorTest.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.ForOfStatement);
+ InspectorTest.assert(node.left);
+ InspectorTest.assert(node.left.type === WebInspector.ScriptSyntaxTree.NodeType.VariableDeclaration);
+ InspectorTest.assert(node.left.declarations[0].id.type === WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern);
+ InspectorTest.assert(node.left.declarations[0].id.properties[0].value.name === "x");
+ InspectorTest.log("passed ForOfStatement");
+
</ins><span class="cx"> node = makeNode("function foo(x,y){}", false);
</span><span class="cx"> InspectorTest.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.FunctionDeclaration);
</span><span class="cx"> InspectorTest.assert(node.params);
</span><span class="lines">@@ -376,6 +401,31 @@
</span><span class="cx"> InspectorTest.assert(node.declarations[0].init.type === WebInspector.ScriptSyntaxTree.NodeType.Literal);
</span><span class="cx"> node = makeNode("var foo;", false);
</span><span class="cx"> InspectorTest.assert(node.declarations[0].init === null);
</span><ins>+ node = makeNode("var {x, y: foo} = bar;", false);
+ InspectorTest.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.VariableDeclaration);
+ InspectorTest.assert(node.declarations.length === 1);
+ node = node.declarations[0].id;
+ InspectorTest.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern);
+ InspectorTest.assert(node.properties.length === 2);
+ InspectorTest.assert(node.properties[0].type === WebInspector.ScriptSyntaxTree.NodeType.Property);
+ InspectorTest.assert(node.properties[0].key.type === WebInspector.ScriptSyntaxTree.NodeType.Identifier);
+ InspectorTest.assert(node.properties[0].value.type === WebInspector.ScriptSyntaxTree.NodeType.Identifier);
+ InspectorTest.assert(node.properties[0].key.name === node.properties[0].value.name && node.properties[0].key.name === "x");
+ InspectorTest.assert(node.properties[1].type === WebInspector.ScriptSyntaxTree.NodeType.Property);
+ InspectorTest.assert(node.properties[1].key.type === WebInspector.ScriptSyntaxTree.NodeType.Identifier);
+ InspectorTest.assert(node.properties[1].value.type === WebInspector.ScriptSyntaxTree.NodeType.Identifier);
+ InspectorTest.assert(node.properties[1].key.name === "y");
+ InspectorTest.assert(node.properties[1].value.name === "foo");
+ node = makeNode("var [x, y] = foo;", false);
+ InspectorTest.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.VariableDeclaration);
+ InspectorTest.assert(node.declarations.length === 1);
+ node = node.declarations[0].id;
+ InspectorTest.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern);
+ InspectorTest.assert(node.elements.length === 2);
+ InspectorTest.assert(node.elements[0].type === WebInspector.ScriptSyntaxTree.NodeType.Identifier);
+ InspectorTest.assert(node.elements[0].name === "x");
+ InspectorTest.assert(node.elements[1].type === WebInspector.ScriptSyntaxTree.NodeType.Identifier);
+ InspectorTest.assert(node.elements[1].name === "y");
</ins><span class="cx"> InspectorTest.log("passed VariableDeclarator");
</span><span class="cx">
</span><span class="cx"> node = makeNode("while(true)boo;", false);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (180387 => 180388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2015-02-20 06:31:55 UTC (rev 180387)
+++ trunk/Source/WebInspectorUI/ChangeLog        2015-02-20 06:33:49 UTC (rev 180388)
</span><span class="lines">@@ -1,3 +1,38 @@
</span><ins>+2015-02-19 Saam Barati <saambarati1@gmail.com>
+
+ Web Inspector: merge in upstream Esprima to support parsing more of ES6
+ https://bugs.webkit.org/show_bug.cgi?id=141215
+
+ Reviewed by Timothy Hatcher.
+
+ This patch merges in a new esprima that has some ES6 support.
+ Specifically, the ES6 support ScriptSyntaxTree now has is:
+ - ForOf loops
+ - Object destructuring
+ - Array destructuring
+
+ ScriptSyntaxTree now uses Symbols for identifying AST node types
+ instead of strings. This will prevent any direct usage of strings
+ for node types instead of a direct property access off the
+ ScriptSyntaxTree constructor.
+
+ This patch also does some gardening work:
+ - TypeTokenAnnotator only walks over the incoming type information
+ data once to be more efficient.
+ - TypeTokenView is now smarter about updating its associated DOM node
+ only if its display name has changed.
+
+ * UserInterface/Controllers/TypeTokenAnnotator.js:
+ (WebInspector.TypeTokenAnnotator.prototype._insertTypeTokensForEachNode):
+ * UserInterface/External/Esprima/esprima.js:
+ (.):
+ * UserInterface/Models/ScriptSyntaxTree.js:
+ (WebInspector.ScriptSyntaxTree.prototype.gatherIdentifiersInVariableDeclaration):
+ (WebInspector.ScriptSyntaxTree.prototype._recurse):
+ (WebInspector.ScriptSyntaxTree.prototype._createInternalSyntaxTree):
+ * UserInterface/Views/TypeTokenView.js:
+ (WebInspector.TypeTokenView.prototype.update):
+
</ins><span class="cx"> 2015-02-19 Joseph Pecoraro <pecoraro@apple.com>
</span><span class="cx">
</span><span class="cx"> Web Inspector: Use of Array.from for NodeList/Arguments to Array conversion
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersTypeTokenAnnotatorjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TypeTokenAnnotator.js (180387 => 180388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TypeTokenAnnotator.js        2015-02-20 06:31:55 UTC (rev 180387)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TypeTokenAnnotator.js        2015-02-20 06:33:49 UTC (rev 180388)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -68,7 +68,6 @@
</span><span class="cx"> return;
</span><span class="cx">
</span><span class="cx"> allNodesInRange.forEach(this._insertTypeTokensForEachNode, this);
</span><del>- allNodesInRange.forEach(this._updateTypeTokensForEachNode, this);
</del><span class="cx">
</span><span class="cx"> var totalTime = Date.now() - startTime;
</span><span class="cx"> var timeoutTime = Math.min(Math.max(7500, totalTime), 8 * totalTime);
</span><span class="lines">@@ -97,6 +96,9 @@
</span><span class="cx"> for (var param of node.params) {
</span><span class="cx"> if (!param.attachments.__typeToken && param.attachments.types && param.attachments.types.isValid)
</span><span class="cx"> this._insertToken(param.range[0], param, false, WebInspector.TypeTokenView.TitleType.Variable, param.name);
</span><ins>+
+ if (param.attachments.__typeToken)
+ param.attachments.__typeToken.update(param.attachments.types);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // If a function does not have an explicit return type, then don't show a return type unless we think it's a constructor.
</span><span class="lines">@@ -106,14 +108,23 @@
</span><span class="cx">
</span><span class="cx"> if (scriptSyntaxTree.containsNonEmptyReturnStatement(node.body) || !WebInspector.TypeSet.fromPayload(functionReturnType).isContainedIn(WebInspector.TypeSet.TypeBit.Undefined)) {
</span><span class="cx"> var functionName = node.id ? node.id.name : null;
</span><del>- this._insertToken(node.isGetterOrSetter ? node.getterOrSetterRange[0] : node.range[0], node,
- true, WebInspector.TypeTokenView.TitleType.ReturnStatement, functionName);
</del><ins>+ this._insertToken(node.isGetterOrSetter ? node.getterOrSetterRange[0] : node.range[0], node, true, WebInspector.TypeTokenView.TitleType.ReturnStatement, functionName);
</ins><span class="cx"> }
</span><ins>+
+ if (node.attachments.__typeToken)
+ node.attachments.__typeToken.update(node.attachments.returnTypes);
+
</ins><span class="cx"> break;
</span><span class="cx"> case WebInspector.ScriptSyntaxTree.NodeType.VariableDeclarator:
</span><del>- if (!node.attachments.__typeToken && node.attachments.types && node.attachments.types.isValid)
- this._insertToken(node.id.range[0], node, false, WebInspector.TypeTokenView.TitleType.Variable, node.id.name);
</del><ins>+ var identifiers = scriptSyntaxTree.gatherIdentifiersInVariableDeclaration(node);
+ for (identifier of identifiers) {
+ if (!identifier.attachments.__typeToken && identifier.attachments.types && identifier.attachments.types.isValid)
+ this._insertToken(identifier.range[0], identifier, false, WebInspector.TypeTokenView.TitleType.Variable, identifier.name);
</ins><span class="cx">
</span><ins>+ if (identifier.attachments.__typeToken)
+ identifier.attachments.__typeToken.update(identifier.attachments.types);
+ }
+
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> },
</span><span class="lines">@@ -143,25 +154,6 @@
</span><span class="cx"> this._typeTokenBookmarks.push(bookmark);
</span><span class="cx"> },
</span><span class="cx">
</span><del>- _updateTypeTokensForEachNode: function(node)
- {
- switch (node.type) {
- case WebInspector.ScriptSyntaxTree.NodeType.FunctionDeclaration:
- case WebInspector.ScriptSyntaxTree.NodeType.FunctionExpression:
- node.params.forEach(function(param) {
- if (param.attachments.__typeToken)
- param.attachments.__typeToken.update(param.attachments.types);
- });
- if (node.attachments.__typeToken)
- node.attachments.__typeToken.update(node.attachments.returnTypes);
- break;
- case WebInspector.ScriptSyntaxTree.NodeType.VariableDeclarator:
- if (node.attachments.__typeToken)
- node.attachments.__typeToken.update(node.attachments.types);
- break;
- }
- },
-
</del><span class="cx"> _translateToOffsetAfterFunctionParameterList: function(node, offset, sourceString)
</span><span class="cx"> {
</span><span class="cx"> // The assumption here is that we get the offset starting at the function keyword (or after the get/set keywords).
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalEsprimaesprimajs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/Esprima/esprima.js (180387 => 180388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/Esprima/esprima.js        2015-02-20 06:31:55 UTC (rev 180387)
+++ trunk/Source/WebInspectorUI/UserInterface/External/Esprima/esprima.js        2015-02-20 06:33:49 UTC (rev 180388)
</span><span class="lines">@@ -1,7 +1,6 @@
</span><span class="cx"> /*
</span><span class="cx"> Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
</span><span class="cx"> Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
</span><del>- Copyright (C) 2013 Mathias Bynens <mathias@qiwi.be>
</del><span class="cx"> Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
</span><span class="cx"> Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
</span><span class="cx"> Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
</span><span class="lines">@@ -31,17 +30,6 @@
</span><span class="cx"> THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx"> */
</span><span class="cx">
</span><del>-/*jslint bitwise:true plusplus:true */
-/*global esprima:true, define:true, exports:true, window: true,
-throwErrorTolerant: true,
-throwError: true, generateStatement: true, peek: true,
-parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
-parseFunctionDeclaration: true, parseFunctionExpression: true,
-parseFunctionSourceElements: true, parseVariableIdentifier: true,
-parseLeftHandSideExpression: true,
-parseUnaryExpression: true,
-parseStatement: true, parseSourceElement: true */
-
</del><span class="cx"> (function (root, factory) {
</span><span class="cx"> 'use strict';
</span><span class="cx">
</span><span class="lines">@@ -67,6 +55,7 @@
</span><span class="cx"> Messages,
</span><span class="cx"> Regex,
</span><span class="cx"> SyntaxTreeDelegate,
</span><ins>+ ClassPropertyType,
</ins><span class="cx"> source,
</span><span class="cx"> strict,
</span><span class="cx"> index,
</span><span class="lines">@@ -87,7 +76,8 @@
</span><span class="cx"> NumericLiteral: 6,
</span><span class="cx"> Punctuator: 7,
</span><span class="cx"> StringLiteral: 8,
</span><del>- RegularExpression: 9
</del><ins>+ RegularExpression: 9,
+ Template: 10
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> TokenName = {};
</span><span class="lines">@@ -113,37 +103,59 @@
</span><span class="cx"> '<=', '<', '>', '!=', '!=='];
</span><span class="cx">
</span><span class="cx"> Syntax = {
</span><ins>+ ArrayExpression: 'ArrayExpression',
+ ArrayPattern: 'ArrayPattern',
+ ArrowFunctionExpression: 'ArrowFunctionExpression',
</ins><span class="cx"> AssignmentExpression: 'AssignmentExpression',
</span><del>- ArrayExpression: 'ArrayExpression',
</del><ins>+ BinaryExpression: 'BinaryExpression',
</ins><span class="cx"> BlockStatement: 'BlockStatement',
</span><del>- BinaryExpression: 'BinaryExpression',
</del><span class="cx"> BreakStatement: 'BreakStatement',
</span><span class="cx"> CallExpression: 'CallExpression',
</span><span class="cx"> CatchClause: 'CatchClause',
</span><ins>+ ClassBody: 'ClassBody',
+ ClassDeclaration: 'ClassDeclaration',
+ ClassExpression: 'ClassExpression',
+ ComprehensionBlock: 'ComprehensionBlock',
+ ComprehensionExpression: 'ComprehensionExpression',
</ins><span class="cx"> ConditionalExpression: 'ConditionalExpression',
</span><span class="cx"> ContinueStatement: 'ContinueStatement',
</span><ins>+ DebuggerStatement: 'DebuggerStatement',
</ins><span class="cx"> DoWhileStatement: 'DoWhileStatement',
</span><del>- DebuggerStatement: 'DebuggerStatement',
</del><span class="cx"> EmptyStatement: 'EmptyStatement',
</span><ins>+ ExportDeclaration: 'ExportDeclaration',
+ ExportBatchSpecifier: 'ExportBatchSpecifier',
+ ExportSpecifier: 'ExportSpecifier',
</ins><span class="cx"> ExpressionStatement: 'ExpressionStatement',
</span><ins>+ ForInStatement: 'ForInStatement',
+ ForOfStatement: 'ForOfStatement',
</ins><span class="cx"> ForStatement: 'ForStatement',
</span><del>- ForInStatement: 'ForInStatement',
</del><span class="cx"> FunctionDeclaration: 'FunctionDeclaration',
</span><span class="cx"> FunctionExpression: 'FunctionExpression',
</span><span class="cx"> Identifier: 'Identifier',
</span><span class="cx"> IfStatement: 'IfStatement',
</span><ins>+ ImportDeclaration: 'ImportDeclaration',
+ ImportDefaultSpecifier: 'ImportDefaultSpecifier',
+ ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
+ ImportSpecifier: 'ImportSpecifier',
+ LabeledStatement: 'LabeledStatement',
</ins><span class="cx"> Literal: 'Literal',
</span><del>- LabeledStatement: 'LabeledStatement',
</del><span class="cx"> LogicalExpression: 'LogicalExpression',
</span><span class="cx"> MemberExpression: 'MemberExpression',
</span><ins>+ MethodDefinition: 'MethodDefinition',
+ ModuleSpecifier: 'ModuleSpecifier',
</ins><span class="cx"> NewExpression: 'NewExpression',
</span><span class="cx"> ObjectExpression: 'ObjectExpression',
</span><ins>+ ObjectPattern: 'ObjectPattern',
</ins><span class="cx"> Program: 'Program',
</span><span class="cx"> Property: 'Property',
</span><span class="cx"> ReturnStatement: 'ReturnStatement',
</span><span class="cx"> SequenceExpression: 'SequenceExpression',
</span><ins>+ SpreadElement: 'SpreadElement',
+ SwitchCase: 'SwitchCase',
</ins><span class="cx"> SwitchStatement: 'SwitchStatement',
</span><del>- SwitchCase: 'SwitchCase',
</del><ins>+ TaggedTemplateExpression: 'TaggedTemplateExpression',
+ TemplateElement: 'TemplateElement',
+ TemplateLiteral: 'TemplateLiteral',
</ins><span class="cx"> ThisExpression: 'ThisExpression',
</span><span class="cx"> ThrowStatement: 'ThrowStatement',
</span><span class="cx"> TryStatement: 'TryStatement',
</span><span class="lines">@@ -152,7 +164,8 @@
</span><span class="cx"> VariableDeclaration: 'VariableDeclaration',
</span><span class="cx"> VariableDeclarator: 'VariableDeclarator',
</span><span class="cx"> WhileStatement: 'WhileStatement',
</span><del>- WithStatement: 'WithStatement'
</del><ins>+ WithStatement: 'WithStatement',
+ YieldExpression: 'YieldExpression'
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> PropertyKind = {
</span><span class="lines">@@ -161,47 +174,72 @@
</span><span class="cx"> Set: 4
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+ ClassPropertyType = {
+ 'static': 'static',
+ prototype: 'prototype'
+ };
+
</ins><span class="cx"> // Error messages should be identical to V8.
</span><span class="cx"> Messages = {
</span><del>- UnexpectedToken: 'Unexpected token %0',
- UnexpectedNumber: 'Unexpected number',
- UnexpectedString: 'Unexpected string',
- UnexpectedIdentifier: 'Unexpected identifier',
- UnexpectedReserved: 'Unexpected reserved word',
- UnexpectedEOS: 'Unexpected end of input',
- NewlineAfterThrow: 'Illegal newline after throw',
</del><ins>+ UnexpectedToken: 'Unexpected token %0',
+ UnexpectedNumber: 'Unexpected number',
+ UnexpectedString: 'Unexpected string',
+ UnexpectedIdentifier: 'Unexpected identifier',
+ UnexpectedReserved: 'Unexpected reserved word',
+ UnexpectedTemplate: 'Unexpected quasi %0',
+ UnexpectedEOS: 'Unexpected end of input',
+ NewlineAfterThrow: 'Illegal newline after throw',
</ins><span class="cx"> InvalidRegExp: 'Invalid regular expression',
</span><del>- UnterminatedRegExp: 'Invalid regular expression: missing /',
- InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
- InvalidLHSInForIn: 'Invalid left-hand side in for-in',
</del><ins>+ UnterminatedRegExp: 'Invalid regular expression: missing /',
+ InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
+ InvalidLHSInFormalsList: 'Invalid left-hand side in formals list',
+ InvalidLHSInForIn: 'Invalid left-hand side in for-in',
</ins><span class="cx"> MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
</span><del>- NoCatchOrFinally: 'Missing catch or finally after try',
</del><ins>+ NoCatchOrFinally: 'Missing catch or finally after try',
</ins><span class="cx"> UnknownLabel: 'Undefined label \'%0\'',
</span><span class="cx"> Redeclaration: '%0 \'%1\' has already been declared',
</span><span class="cx"> IllegalContinue: 'Illegal continue statement',
</span><span class="cx"> IllegalBreak: 'Illegal break statement',
</span><ins>+ IllegalDuplicateClassProperty: 'Illegal duplicate property in class definition',
+ IllegalClassConstructorProperty: 'Illegal constructor property in class definition',
</ins><span class="cx"> IllegalReturn: 'Illegal return statement',
</span><del>- StrictModeWith: 'Strict mode code may not include a with statement',
- StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
- StrictVarName: 'Variable name may not be eval or arguments in strict mode',
- StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
</del><ins>+ IllegalYield: 'Illegal yield expression',
+ IllegalSpread: 'Illegal spread element',
+ StrictModeWith: 'Strict mode code may not include a with statement',
+ StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
+ StrictVarName: 'Variable name may not be eval or arguments in strict mode',
+ StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
</ins><span class="cx"> StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
</span><del>- StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
- StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
- StrictDelete: 'Delete of an unqualified identifier in strict mode.',
- StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
- AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
- AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
- StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
- StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
- StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
- StrictReservedWord: 'Use of future reserved word in strict mode'
</del><ins>+ ParameterAfterRestParameter: 'Rest parameter must be final parameter of an argument list',
+ DefaultRestParameter: 'Rest parameter can not have a default value',
+ ElementAfterSpreadElement: 'Spread must be the final element of an element list',
+ ObjectPatternAsRestParameter: 'Invalid rest parameter',
+ ObjectPatternAsSpread: 'Invalid spread argument',
+ StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
+ StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
+ StrictDelete: 'Delete of an unqualified identifier in strict mode.',
+ StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
+ AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
+ AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
+ StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
+ StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
+ StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
+ StrictReservedWord: 'Use of future reserved word in strict mode',
+ MissingFromClause: 'Missing from clause',
+ NoAsAfterImportNamespace: 'Missing as after import *',
+ InvalidModuleSpecifier: 'Invalid module specifier',
+ IllegalImportDeclaration: 'Illegal import declaration',
+ IllegalExportDeclaration: 'Illegal export declaration',
+ NoUnintializedConst: 'Const must be initialized',
+ ComprehensionRequiresBlock: 'Comprehension must have at least one block',
+ ComprehensionError: 'Comprehension Error',
+ EachNotAllowed: 'Each is not supported'
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> // See also tools/generate-unicode-regex.py.
</span><span class="cx"> Regex = {
</span><del>- NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32
\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u1
2B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u
2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA
6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'),
- NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A9
3-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-
\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B
0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u300
5-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F
\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]')
</del><ins>+ NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\
u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12
b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2
c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6
d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'),
+ NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a9
3-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-
\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b
0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u300
5-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f
\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> // Ensure the condition is true, otherwise throw an error.
</span><span class="lines">@@ -216,6 +254,31 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ function StringMap() {
+ this.$data = {};
+ }
+
+ StringMap.prototype.get = function (key) {
+ key = '$' + key;
+ return this.$data[key];
+ };
+
+ StringMap.prototype.set = function (key, value) {
+ key = '$' + key;
+ this.$data[key] = value;
+ return this;
+ };
+
+ StringMap.prototype.has = function (key) {
+ key = '$' + key;
+ return Object.prototype.hasOwnProperty.call(this.$data, key);
+ };
+
+ StringMap.prototype.delete = function (key) {
+ key = '$' + key;
+ return delete this.$data[key];
+ };
+
</ins><span class="cx"> function isDecimalDigit(ch) {
</span><span class="cx"> return (ch >= 48 && ch <= 57); // 0..9
</span><span class="cx"> }
</span><span class="lines">@@ -232,32 +295,36 @@
</span><span class="cx"> // 7.2 White Space
</span><span class="cx">
</span><span class="cx"> function isWhiteSpace(ch) {
</span><del>- return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
- (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
</del><ins>+ return (ch === 32) || // space
+ (ch === 9) || // tab
+ (ch === 0xB) ||
+ (ch === 0xC) ||
+ (ch === 0xA0) ||
+ (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 7.3 Line Terminators
</span><span class="cx">
</span><span class="cx"> function isLineTerminator(ch) {
</span><del>- return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
</del><ins>+ return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 7.6 Identifier Names and Identifiers
</span><span class="cx">
</span><span class="cx"> function isIdentifierStart(ch) {
</span><del>- return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
- (ch >= 0x41 && ch <= 0x5A) || // A..Z
- (ch >= 0x61 && ch <= 0x7A) || // a..z
- (ch === 0x5C) || // \ (backslash)
</del><ins>+ return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
+ (ch >= 65 && ch <= 90) || // A..Z
+ (ch >= 97 && ch <= 122) || // a..z
+ (ch === 92) || // \ (backslash)
</ins><span class="cx"> ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function isIdentifierPart(ch) {
</span><del>- return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
- (ch >= 0x41 && ch <= 0x5A) || // A..Z
- (ch >= 0x61 && ch <= 0x7A) || // a..z
- (ch >= 0x30 && ch <= 0x39) || // 0..9
- (ch === 0x5C) || // \ (backslash)
</del><ins>+ return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
+ (ch >= 65 && ch <= 90) || // A..Z
+ (ch >= 97 && ch <= 122) || // a..z
+ (ch >= 48 && ch <= 57) || // 0..9
+ (ch === 92) || // \ (backslash)
</ins><span class="cx"> ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -306,7 +373,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 'const' is specialized as Keyword in V8.
</span><del>- // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
</del><ins>+ // 'yield' is only treated as a keyword in strict mode.
+ // 'let' is for compatiblity with SpiderMonkey and ES.next.
</ins><span class="cx"> // Some others are from future reserved words.
</span><span class="cx">
</span><span class="cx"> switch (id.length) {
</span><span class="lines">@@ -320,7 +388,7 @@
</span><span class="cx"> (id === 'void') || (id === 'with') || (id === 'enum');
</span><span class="cx"> case 5:
</span><span class="cx"> return (id === 'while') || (id === 'break') || (id === 'catch') ||
</span><del>- (id === 'throw') || (id === 'const') || (id === 'yield') ||
</del><ins>+ (id === 'throw') || (id === 'const') ||
</ins><span class="cx"> (id === 'class') || (id === 'super');
</span><span class="cx"> case 6:
</span><span class="cx"> return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
</span><span class="lines">@@ -339,8 +407,7 @@
</span><span class="cx"> // 7.4 Comments
</span><span class="cx">
</span><span class="cx"> function addComment(type, value, start, end, loc) {
</span><del>- var comment, attacher;
-
</del><ins>+ var comment;
</ins><span class="cx"> assert(typeof start === 'number', 'Comment must have valid position');
</span><span class="cx">
</span><span class="cx"> // Because the way the actual token is scanned, often the comments
</span><span class="lines">@@ -369,14 +436,14 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- function skipSingleLineComment(offset) {
</del><ins>+ function skipSingleLineComment() {
</ins><span class="cx"> var start, loc, ch, comment;
</span><span class="cx">
</span><del>- start = index - offset;
</del><ins>+ start = index - 2;
</ins><span class="cx"> loc = {
</span><span class="cx"> start: {
</span><span class="cx"> line: lineNumber,
</span><del>- column: index - lineStart - offset
</del><ins>+ column: index - lineStart - 2
</ins><span class="cx"> }
</span><span class="cx"> };
</span><span class="cx">
</span><span class="lines">@@ -385,7 +452,7 @@
</span><span class="cx"> ++index;
</span><span class="cx"> if (isLineTerminator(ch)) {
</span><span class="cx"> if (extra.comments) {
</span><del>- comment = source.slice(start + offset, index - 1);
</del><ins>+ comment = source.slice(start + 2, index - 1);
</ins><span class="cx"> loc.end = {
</span><span class="cx"> line: lineNumber,
</span><span class="cx"> column: index - lineStart - 1
</span><span class="lines">@@ -402,7 +469,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (extra.comments) {
</span><del>- comment = source.slice(start + offset, index);
</del><ins>+ comment = source.slice(start + 2, index);
</ins><span class="cx"> loc.end = {
</span><span class="cx"> line: lineNumber,
</span><span class="cx"> column: index - lineStart
</span><span class="lines">@@ -427,7 +494,7 @@
</span><span class="cx"> while (index < length) {
</span><span class="cx"> ch = source.charCodeAt(index);
</span><span class="cx"> if (isLineTerminator(ch)) {
</span><del>- if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
</del><ins>+ if (ch === 13 && source.charCodeAt(index + 1) === 10) {
</ins><span class="cx"> ++index;
</span><span class="cx"> }
</span><span class="cx"> ++lineNumber;
</span><span class="lines">@@ -436,9 +503,9 @@
</span><span class="cx"> if (index >= length) {
</span><span class="cx"> throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
</span><span class="cx"> }
</span><del>- } else if (ch === 0x2A) {
- // Block comment ends with '*/'.
- if (source.charCodeAt(index + 1) === 0x2F) {
</del><ins>+ } else if (ch === 42) {
+ // Block comment ends with '*/' (char #42, char #47).
+ if (source.charCodeAt(index + 1) === 47) {
</ins><span class="cx"> ++index;
</span><span class="cx"> ++index;
</span><span class="cx"> if (extra.comments) {
</span><span class="lines">@@ -461,9 +528,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function skipComment() {
</span><del>- var ch, start;
</del><ins>+ var ch;
</ins><span class="cx">
</span><del>- start = (index === 0);
</del><span class="cx"> while (index < length) {
</span><span class="cx"> ch = source.charCodeAt(index);
</span><span class="cx">
</span><span class="lines">@@ -471,45 +537,24 @@
</span><span class="cx"> ++index;
</span><span class="cx"> } else if (isLineTerminator(ch)) {
</span><span class="cx"> ++index;
</span><del>- if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
</del><ins>+ if (ch === 13 && source.charCodeAt(index) === 10) {
</ins><span class="cx"> ++index;
</span><span class="cx"> }
</span><span class="cx"> ++lineNumber;
</span><span class="cx"> lineStart = index;
</span><del>- start = true;
- } else if (ch === 0x2F) { // U+002F is '/'
</del><ins>+ } else if (ch === 47) { // 47 is '/'
</ins><span class="cx"> ch = source.charCodeAt(index + 1);
</span><del>- if (ch === 0x2F) {
</del><ins>+ if (ch === 47) {
</ins><span class="cx"> ++index;
</span><span class="cx"> ++index;
</span><del>- skipSingleLineComment(2);
- start = true;
- } else if (ch === 0x2A) { // U+002A is '*'
</del><ins>+ skipSingleLineComment();
+ } else if (ch === 42) { // 42 is '*'
</ins><span class="cx"> ++index;
</span><span class="cx"> ++index;
</span><span class="cx"> skipMultiLineComment();
</span><span class="cx"> } else {
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- } else if (start && ch === 0x2D) { // U+002D is '-'
- // U+003E is '>'
- if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
- // '-->' is a single-line comment
- index += 3;
- skipSingleLineComment(3);
- } else {
- break;
- }
- } else if (ch === 0x3C) { // U+003C is '<'
- if (source.slice(index + 1, index + 4) === '!--') {
- ++index; // `<`
- ++index; // `!`
- ++index; // `-`
- ++index; // `-`
- skipSingleLineComment(4);
- } else {
- break;
- }
</del><span class="cx"> } else {
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -531,15 +576,47 @@
</span><span class="cx"> return String.fromCharCode(code);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ function scanUnicodeCodePointEscape() {
+ var ch, code, cu1, cu2;
+
+ ch = source[index];
+ code = 0;
+
+ // At least, one hex digit is required.
+ if (ch === '}') {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ while (index < length) {
+ ch = source[index++];
+ if (!isHexDigit(ch)) {
+ break;
+ }
+ code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+ }
+
+ if (code > 0x10FFFF || ch !== '}') {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ // UTF-16 Encoding
+ if (code <= 0xFFFF) {
+ return String.fromCharCode(code);
+ }
+ cu1 = ((code - 0x10000) >> 10) + 0xD800;
+ cu2 = ((code - 0x10000) & 1023) + 0xDC00;
+ return String.fromCharCode(cu1, cu2);
+ }
+
</ins><span class="cx"> function getEscapedIdentifier() {
</span><span class="cx"> var ch, id;
</span><span class="cx">
</span><span class="cx"> ch = source.charCodeAt(index++);
</span><span class="cx"> id = String.fromCharCode(ch);
</span><span class="cx">
</span><del>- // '\u' (U+005C, U+0075) denotes an escaped character.
- if (ch === 0x5C) {
- if (source.charCodeAt(index) !== 0x75) {
</del><ins>+ // '\u' (char #92, char #117) denotes an escaped character.
+ if (ch === 92) {
+ if (source.charCodeAt(index) !== 117) {
</ins><span class="cx"> throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
</span><span class="cx"> }
</span><span class="cx"> ++index;
</span><span class="lines">@@ -558,10 +635,10 @@
</span><span class="cx"> ++index;
</span><span class="cx"> id += String.fromCharCode(ch);
</span><span class="cx">
</span><del>- // '\u' (U+005C, U+0075) denotes an escaped character.
- if (ch === 0x5C) {
</del><ins>+ // '\u' (char #92, char #117) denotes an escaped character.
+ if (ch === 92) {
</ins><span class="cx"> id = id.substr(0, id.length - 1);
</span><del>- if (source.charCodeAt(index) !== 0x75) {
</del><ins>+ if (source.charCodeAt(index) !== 117) {
</ins><span class="cx"> throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
</span><span class="cx"> }
</span><span class="cx"> ++index;
</span><span class="lines">@@ -582,8 +659,8 @@
</span><span class="cx"> start = index++;
</span><span class="cx"> while (index < length) {
</span><span class="cx"> ch = source.charCodeAt(index);
</span><del>- if (ch === 0x5C) {
- // Blackslash (U+005C) marks Unicode escape sequence.
</del><ins>+ if (ch === 92) {
+ // Blackslash (char #92) marks Unicode escape sequence.
</ins><span class="cx"> index = start;
</span><span class="cx"> return getEscapedIdentifier();
</span><span class="cx"> }
</span><span class="lines">@@ -602,8 +679,8 @@
</span><span class="cx">
</span><span class="cx"> start = index;
</span><span class="cx">
</span><del>- // Backslash (U+005C) starts an escaped character.
- id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier();
</del><ins>+ // Backslash (char #92) starts an escaped character.
+ id = (source.charCodeAt(index) === 92) ? getEscapedIdentifier() : getIdentifier();
</ins><span class="cx">
</span><span class="cx"> // There is no keyword or literal with only one character.
</span><span class="cx"> // Thus, it must be an identifier.
</span><span class="lines">@@ -624,8 +701,7 @@
</span><span class="cx"> value: id,
</span><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -642,25 +718,23 @@
</span><span class="cx"> ch4;
</span><span class="cx">
</span><span class="cx"> switch (code) {
</span><del>-
</del><span class="cx"> // Check for most common single-character punctuators.
</span><del>- case 0x2E: // . dot
- case 0x28: // ( open bracket
- case 0x29: // ) close bracket
- case 0x3B: // ; semicolon
- case 0x2C: // , comma
- case 0x7B: // { open curly brace
- case 0x7D: // } close curly brace
- case 0x5B: // [
- case 0x5D: // ]
- case 0x3A: // :
- case 0x3F: // ?
- case 0x7E: // ~
</del><ins>+ case 40: // ( open bracket
+ case 41: // ) close bracket
+ case 59: // ; semicolon
+ case 44: // , comma
+ case 123: // { open curly brace
+ case 125: // } close curly brace
+ case 91: // [
+ case 93: // ]
+ case 58: // :
+ case 63: // ?
+ case 126: // ~
</ins><span class="cx"> ++index;
</span><span class="cx"> if (extra.tokenize) {
</span><del>- if (code === 0x28) {
</del><ins>+ if (code === 40) {
</ins><span class="cx"> extra.openParenToken = extra.tokens.length;
</span><del>- } else if (code === 0x7B) {
</del><ins>+ } else if (code === 123) {
</ins><span class="cx"> extra.openCurlyToken = extra.tokens.length;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -669,42 +743,40 @@
</span><span class="cx"> value: String.fromCharCode(code),
</span><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> default:
</span><span class="cx"> code2 = source.charCodeAt(index + 1);
</span><span class="cx">
</span><del>- // '=' (U+003D) marks an assignment or comparison operator.
- if (code2 === 0x3D) {
</del><ins>+ // '=' (char #61) marks an assignment or comparison operator.
+ if (code2 === 61) {
</ins><span class="cx"> switch (code) {
</span><del>- case 0x2B: // +
- case 0x2D: // -
- case 0x2F: // /
- case 0x3C: // <
- case 0x3E: // >
- case 0x5E: // ^
- case 0x7C: // |
- case 0x25: // %
- case 0x26: // &
- case 0x2A: // *
</del><ins>+ case 37: // %
+ case 38: // &
+ case 42: // *:
+ case 43: // +
+ case 45: // -
+ case 47: // /
+ case 60: // <
+ case 62: // >
+ case 94: // ^
+ case 124: // |
</ins><span class="cx"> index += 2;
</span><span class="cx"> return {
</span><span class="cx"> type: Token.Punctuator,
</span><span class="cx"> value: String.fromCharCode(code) + String.fromCharCode(code2),
</span><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx">
</span><del>- case 0x21: // !
- case 0x3D: // =
</del><ins>+ case 33: // !
+ case 61: // =
</ins><span class="cx"> index += 2;
</span><span class="cx">
</span><span class="cx"> // !== and ===
</span><del>- if (source.charCodeAt(index) === 0x3D) {
</del><ins>+ if (source.charCodeAt(index) === 61) {
</ins><span class="cx"> ++index;
</span><span class="cx"> }
</span><span class="cx"> return {
</span><span class="lines">@@ -712,61 +784,106 @@
</span><span class="cx"> value: source.slice(start, index),
</span><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><ins>+ default:
+ break;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><ins>+ break;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ // Peek more characters.
+
+ ch2 = source[index + 1];
+ ch3 = source[index + 2];
+ ch4 = source[index + 3];
+
</ins><span class="cx"> // 4-character punctuator: >>>=
</span><span class="cx">
</span><del>- ch4 = source.substr(index, 4);
</del><ins>+ if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
+ if (ch4 === '=') {
+ index += 4;
+ return {
+ type: Token.Punctuator,
+ value: '>>>=',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+ }
</ins><span class="cx">
</span><del>- if (ch4 === '>>>=') {
- index += 4;
</del><ins>+ // 3-character punctuators: === !== >>> <<= >>=
+
+ if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
+ index += 3;
</ins><span class="cx"> return {
</span><span class="cx"> type: Token.Punctuator,
</span><del>- value: ch4,
</del><ins>+ value: '>>>',
</ins><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><del>- // 3-character punctuators: === !== >>> <<= >>=
</del><ins>+ if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
+ index += 3;
+ return {
+ type: Token.Punctuator,
+ value: '<<=',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
</ins><span class="cx">
</span><del>- ch3 = ch4.substr(0, 3);
</del><ins>+ if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
+ index += 3;
+ return {
+ type: Token.Punctuator,
+ value: '>>=',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
</ins><span class="cx">
</span><del>- if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') {
</del><ins>+ if (ch1 === '.' && ch2 === '.' && ch3 === '.') {
</ins><span class="cx"> index += 3;
</span><span class="cx"> return {
</span><span class="cx"> type: Token.Punctuator,
</span><del>- value: ch3,
</del><ins>+ value: '...',
</ins><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Other 2-character punctuators: ++ -- << >> && ||
</span><del>- ch2 = ch3.substr(0, 2);
</del><span class="cx">
</span><del>- if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') {
</del><ins>+ if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
</ins><span class="cx"> index += 2;
</span><span class="cx"> return {
</span><span class="cx"> type: Token.Punctuator,
</span><del>- value: ch2,
</del><ins>+ value: ch1 + ch2,
</ins><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><del>- // 1-character punctuators: < > = ! + - * % & | ^ /
</del><ins>+ if (ch1 === '=' && ch2 === '>') {
+ index += 2;
+ return {
+ type: Token.Punctuator,
+ value: '=>',
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
</ins><span class="cx"> if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
</span><span class="cx"> ++index;
</span><span class="cx"> return {
</span><span class="lines">@@ -774,11 +891,21 @@
</span><span class="cx"> value: ch1,
</span><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (ch1 === '.') {
+ ++index;
+ return {
+ type: Token.Punctuator,
+ value: ch1,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
</ins><span class="cx"> throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -807,20 +934,69 @@
</span><span class="cx"> value: parseInt('0x' + number, 16),
</span><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><del>- function scanOctalLiteral(start) {
- var number = '0' + source[index++];
</del><ins>+ function scanBinaryLiteral(start) {
+ var ch, number;
+
+ number = '';
+
</ins><span class="cx"> while (index < length) {
</span><ins>+ ch = source[index];
+ if (ch !== '0' && ch !== '1') {
+ break;
+ }
+ number += source[index++];
+ }
+
+ if (number.length === 0) {
+ // only 0b or 0B
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ if (index < length) {
+ ch = source.charCodeAt(index);
+ /* istanbul ignore else */
+ if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+ }
+
+ return {
+ type: Token.NumericLiteral,
+ value: parseInt(number, 2),
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ function scanOctalLiteral(prefix, start) {
+ var number, octal;
+
+ if (isOctalDigit(prefix)) {
+ octal = true;
+ number = '0' + source[index++];
+ } else {
+ octal = false;
+ ++index;
+ number = '';
+ }
+
+ while (index < length) {
</ins><span class="cx"> if (!isOctalDigit(source[index])) {
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> number += source[index++];
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (!octal && number.length === 0) {
+ // only 0o or 0O
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
</ins><span class="cx"> if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
</span><span class="cx"> throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
</span><span class="cx"> }
</span><span class="lines">@@ -828,11 +1004,10 @@
</span><span class="cx"> return {
</span><span class="cx"> type: Token.NumericLiteral,
</span><span class="cx"> value: parseInt(number, 8),
</span><del>- octal: true,
</del><ins>+ octal: octal,
</ins><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -851,15 +1026,20 @@
</span><span class="cx">
</span><span class="cx"> // Hex number starts with '0x'.
</span><span class="cx"> // Octal number starts with '0'.
</span><ins>+ // Octal number in ES6 starts with '0o'.
+ // Binary number in ES6 starts with '0b'.
</ins><span class="cx"> if (number === '0') {
</span><span class="cx"> if (ch === 'x' || ch === 'X') {
</span><span class="cx"> ++index;
</span><span class="cx"> return scanHexLiteral(start);
</span><span class="cx"> }
</span><del>- if (isOctalDigit(ch)) {
- return scanOctalLiteral(start);
</del><ins>+ if (ch === 'b' || ch === 'B') {
+ ++index;
+ return scanBinaryLiteral(start);
</ins><span class="cx"> }
</span><del>-
</del><ins>+ if (ch === 'o' || ch === 'O' || isOctalDigit(ch)) {
+ return scanOctalLiteral(ch, start);
+ }
</ins><span class="cx"> // decimal number starts with '0' such as '09' is illegal.
</span><span class="cx"> if (ch && isDecimalDigit(ch.charCodeAt(0))) {
</span><span class="cx"> throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
</span><span class="lines">@@ -905,17 +1085,14 @@
</span><span class="cx"> value: parseFloat(number),
</span><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 7.8.4 String Literals
</span><span class="cx">
</span><span class="cx"> function scanStringLiteral() {
</span><del>- var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart;
- startLineNumber = lineNumber;
- startLineStart = lineStart;
</del><ins>+ var str = '', quote, start, ch, code, unescaped, restore, octal = false;
</ins><span class="cx">
</span><span class="cx"> quote = source[index];
</span><span class="cx"> assert((quote === '\'' || quote === '"'),
</span><span class="lines">@@ -934,17 +1111,6 @@
</span><span class="cx"> ch = source[index++];
</span><span class="cx"> if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
</span><span class="cx"> switch (ch) {
</span><del>- case 'u':
- case 'x':
- restore = index;
- unescaped = scanHexEscape(ch);
- if (unescaped) {
- str += unescaped;
- } else {
- index = restore;
- str += ch;
- }
- break;
</del><span class="cx"> case 'n':
</span><span class="cx"> str += '\n';
</span><span class="cx"> break;
</span><span class="lines">@@ -954,6 +1120,22 @@
</span><span class="cx"> case 't':
</span><span class="cx"> str += '\t';
</span><span class="cx"> break;
</span><ins>+ case 'u':
+ case 'x':
+ if (source[index] === '{') {
+ ++index;
+ str += scanUnicodeCodePointEscape();
+ } else {
+ restore = index;
+ unescaped = scanHexEscape(ch);
+ if (unescaped) {
+ str += unescaped;
+ } else {
+ index = restore;
+ str += ch;
+ }
+ }
+ break;
</ins><span class="cx"> case 'b':
</span><span class="cx"> str += '\b';
</span><span class="cx"> break;
</span><span class="lines">@@ -973,6 +1155,7 @@
</span><span class="cx"> octal = true;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ /* istanbul ignore else */
</ins><span class="cx"> if (index < length && isOctalDigit(source[index])) {
</span><span class="cx"> octal = true;
</span><span class="cx"> code = code * 8 + '01234567'.indexOf(source[index++]);
</span><span class="lines">@@ -993,7 +1176,7 @@
</span><span class="cx"> }
</span><span class="cx"> } else {
</span><span class="cx"> ++lineNumber;
</span><del>- if (ch === '\r' && source[index] === '\n') {
</del><ins>+ if (ch === '\r' && source[index] === '\n') {
</ins><span class="cx"> ++index;
</span><span class="cx"> }
</span><span class="cx"> lineStart = index;
</span><span class="lines">@@ -1013,23 +1196,195 @@
</span><span class="cx"> type: Token.StringLiteral,
</span><span class="cx"> value: str,
</span><span class="cx"> octal: octal,
</span><del>- startLineNumber: startLineNumber,
- startLineStart: startLineStart,
</del><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ function scanTemplate() {
+ var cooked = '', ch, start, terminated, tail, restore, unescaped, code, octal;
+
+ terminated = false;
+ tail = false;
+ start = index;
+
+ ++index;
+
+ while (index < length) {
+ ch = source[index++];
+ if (ch === '`') {
+ tail = true;
+ terminated = true;
+ break;
+ } else if (ch === '$') {
+ if (source[index] === '{') {
+ ++index;
+ terminated = true;
+ break;
+ }
+ cooked += ch;
+ } else if (ch === '\\') {
+ ch = source[index++];
+ if (!isLineTerminator(ch.charCodeAt(0))) {
+ switch (ch) {
+ case 'n':
+ cooked += '\n';
+ break;
+ case 'r':
+ cooked += '\r';
+ break;
+ case 't':
+ cooked += '\t';
+ break;
+ case 'u':
+ case 'x':
+ if (source[index] === '{') {
+ ++index;
+ cooked += scanUnicodeCodePointEscape();
+ } else {
+ restore = index;
+ unescaped = scanHexEscape(ch);
+ if (unescaped) {
+ cooked += unescaped;
+ } else {
+ index = restore;
+ cooked += ch;
+ }
+ }
+ break;
+ case 'b':
+ cooked += '\b';
+ break;
+ case 'f':
+ cooked += '\f';
+ break;
+ case 'v':
+ cooked += '\v';
+ break;
+
+ default:
+ if (isOctalDigit(ch)) {
+ code = '01234567'.indexOf(ch);
+
+ // \0 is not octal escape sequence
+ if (code !== 0) {
+ octal = true;
+ }
+
+ /* istanbul ignore else */
+ if (index < length && isOctalDigit(source[index])) {
+ octal = true;
+ code = code * 8 + '01234567'.indexOf(source[index++]);
+
+ // 3 digits are only allowed when string starts
+ // with 0, 1, 2, 3
+ if ('0123'.indexOf(ch) >= 0 &&
+ index < length &&
+ isOctalDigit(source[index])) {
+ code = code * 8 + '01234567'.indexOf(source[index++]);
+ }
+ }
+ cooked += String.fromCharCode(code);
+ } else {
+ cooked += ch;
+ }
+ break;
+ }
+ } else {
+ ++lineNumber;
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ lineStart = index;
+ }
+ } else if (isLineTerminator(ch.charCodeAt(0))) {
+ ++lineNumber;
+ if (ch === '\r' && source[index] === '\n') {
+ ++index;
+ }
+ lineStart = index;
+ cooked += '\n';
+ } else {
+ cooked += ch;
+ }
+ }
+
+ if (!terminated) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ return {
+ type: Token.Template,
+ value: {
+ cooked: cooked,
+ raw: source.slice(start + 1, index - ((tail) ? 1 : 2))
+ },
+ tail: tail,
+ octal: octal,
+ lineNumber: lineNumber,
+ lineStart: lineStart,
+ range: [start, index]
+ };
+ }
+
+ function scanTemplateElement(option) {
+ var startsWith, template;
+
+ lookahead = null;
+ skipComment();
+
+ startsWith = (option.head) ? '`' : '}';
+
+ if (source[index] !== startsWith) {
+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+ }
+
+ template = scanTemplate();
+
+ peek();
+
+ return template;
+ }
+
</ins><span class="cx"> function testRegExp(pattern, flags) {
</span><del>- var value;
</del><ins>+ var tmp = pattern,
+ value;
+
+ if (flags.indexOf('u') >= 0) {
+ // Replace each astral symbol and every Unicode code point
+ // escape sequence with a single ASCII symbol to avoid throwing on
+ // regular expressions that are only valid in combination with the
+ // `/u` flag.
+ // Note: replacing with the ASCII symbol `x` might cause false
+ // negatives in unlikely scenarios. For example, `[\u{61}-b]` is a
+ // perfectly valid pattern that is equivalent to `[a-b]`, but it
+ // would be replaced by `[x-b]` which throws an error.
+ tmp = tmp
+ .replace(/\\u\{([0-9a-fA-F]+)\}/g, function ($0, $1) {
+ if (parseInt($1, 16) <= 0x10FFFF) {
+ return 'x';
+ }
+ throwError({}, Messages.InvalidRegExp);
+ })
+ .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 'x');
+ }
+
+ // First, detect invalid regular expressions.
</ins><span class="cx"> try {
</span><del>- value = new RegExp(pattern, flags);
</del><ins>+ value = new RegExp(tmp);
</ins><span class="cx"> } catch (e) {
</span><span class="cx"> throwError({}, Messages.InvalidRegExp);
</span><span class="cx"> }
</span><del>- return value;
</del><ins>+
+ // Return a regular expression object for this pattern-flag pair, or
+ // `null` in case the current environment doesn't support the flags it
+ // uses.
+ try {
+ return new RegExp(pattern, flags);
+ } catch (exception) {
+ return null;
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function scanRegExpBody() {
</span><span class="lines">@@ -1125,7 +1480,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function scanRegExp() {
</span><del>- var start, body, flags, pattern, value;
</del><ins>+ var start, body, flags, value;
</ins><span class="cx">
</span><span class="cx"> lookahead = null;
</span><span class="cx"> skipComment();
</span><span class="lines">@@ -1139,63 +1494,27 @@
</span><span class="cx"> return {
</span><span class="cx"> type: Token.RegularExpression,
</span><span class="cx"> value: value,
</span><ins>+ regex: {
+ pattern: body.value,
+ flags: flags.value
+ },
</ins><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: start,
- end: index
</del><ins>+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return {
</span><span class="cx"> literal: body.literal + flags.literal,
</span><span class="cx"> value: value,
</span><del>- start: start,
- end: index
</del><ins>+ regex: {
+ pattern: body.value,
+ flags: flags.value
+ },
+ range: [start, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><del>- function collectRegex() {
- var pos, loc, regex, token;
-
- skipComment();
-
- pos = index;
- loc = {
- start: {
- line: lineNumber,
- column: index - lineStart
- }
- };
-
- regex = scanRegExp();
- loc.end = {
- line: lineNumber,
- column: index - lineStart
- };
-
- /* istanbul ignore next */
- if (!extra.tokenize) {
- // Pop the previous token, which is likely '/' or '/='
- if (extra.tokens.length > 0) {
- token = extra.tokens[extra.tokens.length - 1];
- if (token.range[0] === pos && token.type === 'Punctuator') {
- if (token.value === '/' || token.value === '/=') {
- extra.tokens.pop();
- }
- }
- }
-
- extra.tokens.push({
- type: 'RegularExpression',
- value: regex.literal,
- range: [pos, index],
- loc: loc
- });
- }
-
- return regex;
- }
-
</del><span class="cx"> function isIdentifierName(token) {
</span><span class="cx"> return token.type === Token.Identifier ||
</span><span class="cx"> token.type === Token.Keyword ||
</span><span class="lines">@@ -1211,12 +1530,9 @@
</span><span class="cx"> prevToken = extra.tokens[extra.tokens.length - 1];
</span><span class="cx"> if (!prevToken) {
</span><span class="cx"> // Nothing before that: it cannot be a division.
</span><del>- return collectRegex();
</del><ins>+ return scanRegExp();
</ins><span class="cx"> }
</span><span class="cx"> if (prevToken.type === 'Punctuator') {
</span><del>- if (prevToken.value === ']') {
- return scanPunctuator();
- }
</del><span class="cx"> if (prevToken.value === ')') {
</span><span class="cx"> checkToken = extra.tokens[extra.openParenToken - 1];
</span><span class="cx"> if (checkToken &&
</span><span class="lines">@@ -1225,7 +1541,7 @@
</span><span class="cx"> checkToken.value === 'while' ||
</span><span class="cx"> checkToken.value === 'for' ||
</span><span class="cx"> checkToken.value === 'with')) {
</span><del>- return collectRegex();
</del><ins>+ return scanRegExp();
</ins><span class="cx"> }
</span><span class="cx"> return scanPunctuator();
</span><span class="cx"> }
</span><span class="lines">@@ -1244,7 +1560,7 @@
</span><span class="cx"> // Named function.
</span><span class="cx"> checkToken = extra.tokens[extra.openCurlyToken - 5];
</span><span class="cx"> if (!checkToken) {
</span><del>- return collectRegex();
</del><ins>+ return scanRegExp();
</ins><span class="cx"> }
</span><span class="cx"> } else {
</span><span class="cx"> return scanPunctuator();
</span><span class="lines">@@ -1256,12 +1572,12 @@
</span><span class="cx"> return scanPunctuator();
</span><span class="cx"> }
</span><span class="cx"> // It is a declaration.
</span><del>- return collectRegex();
</del><ins>+ return scanRegExp();
</ins><span class="cx"> }
</span><del>- return collectRegex();
</del><ins>+ return scanRegExp();
</ins><span class="cx"> }
</span><del>- if (prevToken.type === 'Keyword') {
- return collectRegex();
</del><ins>+ if (prevToken.type === 'Keyword' && prevToken.value !== 'this') {
+ return scanRegExp();
</ins><span class="cx"> }
</span><span class="cx"> return scanPunctuator();
</span><span class="cx"> }
</span><span class="lines">@@ -1276,31 +1592,32 @@
</span><span class="cx"> type: Token.EOF,
</span><span class="cx"> lineNumber: lineNumber,
</span><span class="cx"> lineStart: lineStart,
</span><del>- start: index,
- end: index
</del><ins>+ range: [index, index]
</ins><span class="cx"> };
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> ch = source.charCodeAt(index);
</span><span class="cx">
</span><del>- if (isIdentifierStart(ch)) {
- return scanIdentifier();
- }
-
</del><span class="cx"> // Very common: ( and ) and ;
</span><del>- if (ch === 0x28 || ch === 0x29 || ch === 0x3B) {
</del><ins>+ if (ch === 40 || ch === 41 || ch === 58) {
</ins><span class="cx"> return scanPunctuator();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- // String literal starts with single quote (U+0027) or double quote (U+0022).
- if (ch === 0x27 || ch === 0x22) {
</del><ins>+ // String literal starts with single quote (#39) or double quote (#34).
+ if (ch === 39 || ch === 34) {
</ins><span class="cx"> return scanStringLiteral();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (ch === 96) {
+ return scanTemplate();
+ }
+ if (isIdentifierStart(ch)) {
+ return scanIdentifier();
+ }
</ins><span class="cx">
</span><del>- // Dot (.) U+002E can also start a floating-point number, hence the need
</del><ins>+ // Dot (.) char #46 can also start a floating-point number, hence the need
</ins><span class="cx"> // to check the next character.
</span><del>- if (ch === 0x2E) {
</del><ins>+ if (ch === 46) {
</ins><span class="cx"> if (isDecimalDigit(source.charCodeAt(index + 1))) {
</span><span class="cx"> return scanNumericLiteral();
</span><span class="cx"> }
</span><span class="lines">@@ -1311,55 +1628,25 @@
</span><span class="cx"> return scanNumericLiteral();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- // Slash (/) U+002F can also start a regex.
- if (extra.tokenize && ch === 0x2F) {
</del><ins>+ // Slash (/) char #47 can also start a regex.
+ if (extra.tokenize && ch === 47) {
</ins><span class="cx"> return advanceSlash();
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return scanPunctuator();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- function collectToken() {
- var loc, token, range, value;
-
- skipComment();
- loc = {
- start: {
- line: lineNumber,
- column: index - lineStart
- }
- };
-
- token = advance();
- loc.end = {
- line: lineNumber,
- column: index - lineStart
- };
-
- if (token.type !== Token.EOF) {
- value = source.slice(token.start, token.end);
- extra.tokens.push({
- type: TokenName[token.type],
- value: value,
- range: [token.start, token.end],
- loc: loc
- });
- }
-
- return token;
- }
-
</del><span class="cx"> function lex() {
</span><span class="cx"> var token;
</span><span class="cx">
</span><span class="cx"> token = lookahead;
</span><del>- index = token.end;
</del><ins>+ index = token.range[1];
</ins><span class="cx"> lineNumber = token.lineNumber;
</span><span class="cx"> lineStart = token.lineStart;
</span><span class="cx">
</span><del>- lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
</del><ins>+ lookahead = advance();
</ins><span class="cx">
</span><del>- index = token.end;
</del><ins>+ index = token.range[1];
</ins><span class="cx"> lineNumber = token.lineNumber;
</span><span class="cx"> lineStart = token.lineStart;
</span><span class="cx">
</span><span class="lines">@@ -1372,98 +1659,129 @@
</span><span class="cx"> pos = index;
</span><span class="cx"> line = lineNumber;
</span><span class="cx"> start = lineStart;
</span><del>- lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
</del><ins>+ lookahead = advance();
</ins><span class="cx"> index = pos;
</span><span class="cx"> lineNumber = line;
</span><span class="cx"> lineStart = start;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- function Position(line, column) {
- this.line = line;
- this.column = column;
</del><ins>+ function lookahead2() {
+ var adv, pos, line, start, result;
+
+ // If we are collecting the tokens, don't grab the next one yet.
+ /* istanbul ignore next */
+ adv = (typeof extra.advance === 'function') ? extra.advance : advance;
+
+ pos = index;
+ line = lineNumber;
+ start = lineStart;
+
+ // Scan for the next immediate token.
+ /* istanbul ignore if */
+ if (lookahead === null) {
+ lookahead = adv();
+ }
+ index = lookahead.range[1];
+ lineNumber = lookahead.lineNumber;
+ lineStart = lookahead.lineStart;
+
+ // Grab the token right after.
+ result = adv();
+ index = pos;
+ lineNumber = line;
+ lineStart = start;
+
+ return result;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- function SourceLocation(startLine, startColumn, line, column) {
- this.start = new Position(startLine, startColumn);
- this.end = new Position(line, column);
</del><ins>+ function markerCreate() {
+ if (!extra.loc && !extra.range) {
+ return undefined;
+ }
+ skipComment();
+ return {offset: index, line: lineNumber, col: index - lineStart};
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- SyntaxTreeDelegate = {
</del><ins>+ function processComment(node) {
+ var lastChild,
+ trailingComments,
+ bottomRight = extra.bottomRightStack,
+ last = bottomRight[bottomRight.length - 1];
</ins><span class="cx">
</span><del>- name: 'SyntaxTree',
-
- processComment: function (node) {
- var lastChild, trailingComments;
-
- if (node.type === Syntax.Program) {
- if (node.body.length > 0) {
- return;
- }
</del><ins>+ if (node.type === Syntax.Program) {
+ /* istanbul ignore else */
+ if (node.body.length > 0) {
+ return;
</ins><span class="cx"> }
</span><ins>+ }
</ins><span class="cx">
</span><del>- if (extra.trailingComments.length > 0) {
- if (extra.trailingComments[0].range[0] >= node.range[1]) {
- trailingComments = extra.trailingComments;
- extra.trailingComments = [];
- } else {
- extra.trailingComments.length = 0;
- }
</del><ins>+ if (extra.trailingComments.length > 0) {
+ if (extra.trailingComments[0].range[0] >= node.range[1]) {
+ trailingComments = extra.trailingComments;
+ extra.trailingComments = [];
</ins><span class="cx"> } else {
</span><del>- if (extra.bottomRightStack.length > 0 &&
- extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments &&
- extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) {
- trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
- delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
- }
</del><ins>+ extra.trailingComments.length = 0;
</ins><span class="cx"> }
</span><ins>+ } else {
+ if (last && last.trailingComments && last.trailingComments[0].range[0] >= node.range[1]) {
+ trailingComments = last.trailingComments;
+ delete last.trailingComments;
+ }
+ }
</ins><span class="cx">
</span><del>- // Eating the stack.
- while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) {
- lastChild = extra.bottomRightStack.pop();
</del><ins>+ // Eating the stack.
+ if (last) {
+ while (last && last.range[0] >= node.range[0]) {
+ lastChild = last;
+ last = bottomRight.pop();
</ins><span class="cx"> }
</span><ins>+ }
</ins><span class="cx">
</span><del>- if (lastChild) {
- if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) {
- node.leadingComments = lastChild.leadingComments;
- delete lastChild.leadingComments;
- }
- } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) {
- node.leadingComments = extra.leadingComments;
- extra.leadingComments = [];
</del><ins>+ if (lastChild) {
+ if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) {
+ node.leadingComments = lastChild.leadingComments;
+ delete lastChild.leadingComments;
</ins><span class="cx"> }
</span><ins>+ } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) {
+ node.leadingComments = extra.leadingComments;
+ extra.leadingComments = [];
+ }
</ins><span class="cx">
</span><ins>+ if (trailingComments) {
+ node.trailingComments = trailingComments;
+ }
</ins><span class="cx">
</span><del>- if (trailingComments) {
- node.trailingComments = trailingComments;
- }
</del><ins>+ bottomRight.push(node);
+ }
</ins><span class="cx">
</span><del>- extra.bottomRightStack.push(node);
- },
</del><ins>+ function markerApply(marker, node) {
+ if (extra.range) {
+ node.range = [marker.offset, index];
+ }
+ if (extra.loc) {
+ node.loc = {
+ start: {
+ line: marker.line,
+ column: marker.col
+ },
+ end: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
+ node = delegate.postProcess(node);
+ }
+ if (extra.attachComment) {
+ processComment(node);
+ }
+ return node;
+ }
</ins><span class="cx">
</span><del>- markEnd: function (node, startToken) {
- if (extra.range) {
- node.range = [startToken.start, index];
- }
- if (extra.loc) {
- node.loc = new SourceLocation(
- startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber,
- startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart),
- lineNumber,
- index - lineStart
- );
- this.postProcess(node);
- }
</del><ins>+ SyntaxTreeDelegate = {
</ins><span class="cx">
</span><del>- if (extra.attachComment) {
- this.processComment(node);
- }
- return node;
- },
</del><ins>+ name: 'SyntaxTree',
</ins><span class="cx">
</span><span class="cx"> postProcess: function (node) {
</span><del>- if (extra.source) {
- node.loc.source = extra.source;
- }
</del><span class="cx"> return node;
</span><span class="cx"> },
</span><span class="cx">
</span><span class="lines">@@ -1587,29 +1905,38 @@
</span><span class="cx"> };
</span><span class="cx"> },
</span><span class="cx">
</span><del>- createFunctionDeclaration: function (id, params, defaults, body) {
</del><ins>+ createForOfStatement: function (left, right, body) {
</ins><span class="cx"> return {
</span><ins>+ type: Syntax.ForOfStatement,
+ left: left,
+ right: right,
+ body: body
+ };
+ },
+
+ createFunctionDeclaration: function (id, params, defaults, body, rest, generator, expression) {
+ return {
</ins><span class="cx"> type: Syntax.FunctionDeclaration,
</span><span class="cx"> id: id,
</span><span class="cx"> params: params,
</span><span class="cx"> defaults: defaults,
</span><span class="cx"> body: body,
</span><del>- rest: null,
- generator: false,
- expression: false
</del><ins>+ rest: rest,
+ generator: generator,
+ expression: expression
</ins><span class="cx"> };
</span><span class="cx"> },
</span><span class="cx">
</span><del>- createFunctionExpression: function (id, params, defaults, body) {
</del><ins>+ createFunctionExpression: function (id, params, defaults, body, rest, generator, expression) {
</ins><span class="cx"> return {
</span><span class="cx"> type: Syntax.FunctionExpression,
</span><span class="cx"> id: id,
</span><span class="cx"> params: params,
</span><span class="cx"> defaults: defaults,
</span><span class="cx"> body: body,
</span><del>- rest: null,
- generator: false,
- expression: false
</del><ins>+ rest: rest,
+ generator: generator,
+ expression: expression
</ins><span class="cx"> };
</span><span class="cx"> },
</span><span class="cx">
</span><span class="lines">@@ -1638,11 +1965,15 @@
</span><span class="cx"> },
</span><span class="cx">
</span><span class="cx"> createLiteral: function (token) {
</span><del>- return {
</del><ins>+ var object = {
</ins><span class="cx"> type: Syntax.Literal,
</span><span class="cx"> value: token.value,
</span><del>- raw: source.slice(token.start, token.end)
</del><ins>+ raw: source.slice(token.range[0], token.range[1])
</ins><span class="cx"> };
</span><ins>+ if (token.regex) {
+ object.regex = token.regex;
+ }
+ return object;
</ins><span class="cx"> },
</span><span class="cx">
</span><span class="cx"> createMemberExpression: function (accessor, object, property) {
</span><span class="lines">@@ -1685,12 +2016,15 @@
</span><span class="cx"> };
</span><span class="cx"> },
</span><span class="cx">
</span><del>- createProperty: function (kind, key, value) {
</del><ins>+ createProperty: function (kind, key, value, method, shorthand, computed) {
</ins><span class="cx"> return {
</span><span class="cx"> type: Syntax.Property,
</span><span class="cx"> key: key,
</span><span class="cx"> value: value,
</span><del>- kind: kind
</del><ins>+ kind: kind,
+ method: method,
+ shorthand: shorthand,
+ computed: computed
</ins><span class="cx"> };
</span><span class="cx"> },
</span><span class="cx">
</span><span class="lines">@@ -1794,7 +2128,167 @@
</span><span class="cx"> object: object,
</span><span class="cx"> body: body
</span><span class="cx"> };
</span><ins>+ },
+
+ createTemplateElement: function (value, tail) {
+ return {
+ type: Syntax.TemplateElement,
+ value: value,
+ tail: tail
+ };
+ },
+
+ createTemplateLiteral: function (quasis, expressions) {
+ return {
+ type: Syntax.TemplateLiteral,
+ quasis: quasis,
+ expressions: expressions
+ };
+ },
+
+ createSpreadElement: function (argument) {
+ return {
+ type: Syntax.SpreadElement,
+ argument: argument
+ };
+ },
+
+ createTaggedTemplateExpression: function (tag, quasi) {
+ return {
+ type: Syntax.TaggedTemplateExpression,
+ tag: tag,
+ quasi: quasi
+ };
+ },
+
+ createArrowFunctionExpression: function (params, defaults, body, rest, expression) {
+ return {
+ type: Syntax.ArrowFunctionExpression,
+ id: null,
+ params: params,
+ defaults: defaults,
+ body: body,
+ rest: rest,
+ generator: false,
+ expression: expression
+ };
+ },
+
+ createMethodDefinition: function (propertyType, kind, key, value, computed) {
+ return {
+ type: Syntax.MethodDefinition,
+ key: key,
+ value: value,
+ kind: kind,
+ 'static': propertyType === ClassPropertyType.static,
+ computed: computed
+ };
+ },
+
+ createClassBody: function (body) {
+ return {
+ type: Syntax.ClassBody,
+ body: body
+ };
+ },
+
+ createClassExpression: function (id, superClass, body) {
+ return {
+ type: Syntax.ClassExpression,
+ id: id,
+ superClass: superClass,
+ body: body
+ };
+ },
+
+ createClassDeclaration: function (id, superClass, body) {
+ return {
+ type: Syntax.ClassDeclaration,
+ id: id,
+ superClass: superClass,
+ body: body
+ };
+ },
+
+ createModuleSpecifier: function (token) {
+ return {
+ type: Syntax.ModuleSpecifier,
+ value: token.value,
+ raw: source.slice(token.range[0], token.range[1])
+ };
+ },
+
+ createExportSpecifier: function (id, name) {
+ return {
+ type: Syntax.ExportSpecifier,
+ id: id,
+ name: name
+ };
+ },
+
+ createExportBatchSpecifier: function () {
+ return {
+ type: Syntax.ExportBatchSpecifier
+ };
+ },
+
+ createImportDefaultSpecifier: function (id) {
+ return {
+ type: Syntax.ImportDefaultSpecifier,
+ id: id
+ };
+ },
+
+ createImportNamespaceSpecifier: function (id) {
+ return {
+ type: Syntax.ImportNamespaceSpecifier,
+ id: id
+ };
+ },
+
+ createExportDeclaration: function (isDefault, declaration, specifiers, src) {
+ return {
+ type: Syntax.ExportDeclaration,
+ 'default': !!isDefault,
+ declaration: declaration,
+ specifiers: specifiers,
+ source: src
+ };
+ },
+
+ createImportSpecifier: function (id, name) {
+ return {
+ type: Syntax.ImportSpecifier,
+ id: id,
+ name: name
+ };
+ },
+
+ createImportDeclaration: function (specifiers, src) {
+ return {
+ type: Syntax.ImportDeclaration,
+ specifiers: specifiers,
+ source: src
+ };
+ },
+
+ createYieldExpression: function (argument, dlg) {
+ return {
+ type: Syntax.YieldExpression,
+ argument: argument,
+ delegate: dlg
+ };
+ },
+
+ createComprehensionExpression: function (filter, blocks, body) {
+ return {
+ type: Syntax.ComprehensionExpression,
+ filter: filter,
+ blocks: blocks,
+ body: body
+ };
</ins><span class="cx"> }
</span><ins>+
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> // Return true if there is a line terminator before the next token.
</span><span class="lines">@@ -1821,17 +2315,17 @@
</span><span class="cx"> args = Array.prototype.slice.call(arguments, 2),
</span><span class="cx"> msg = messageFormat.replace(
</span><span class="cx"> /%(\d)/g,
</span><del>- function (whole, index) {
- assert(index < args.length, 'Message reference must be in range');
- return args[index];
</del><ins>+ function (whole, idx) {
+ assert(idx < args.length, 'Message reference must be in range');
+ return args[idx];
</ins><span class="cx"> }
</span><span class="cx"> );
</span><span class="cx">
</span><span class="cx"> if (typeof token.lineNumber === 'number') {
</span><span class="cx"> error = new Error('Line ' + token.lineNumber + ': ' + msg);
</span><del>- error.index = token.start;
</del><ins>+ error.index = token.range[0];
</ins><span class="cx"> error.lineNumber = token.lineNumber;
</span><del>- error.column = token.start - lineStart + 1;
</del><ins>+ error.column = token.range[0] - lineStart + 1;
</ins><span class="cx"> } else {
</span><span class="cx"> error = new Error('Line ' + lineNumber + ': ' + msg);
</span><span class="cx"> error.index = index;
</span><span class="lines">@@ -1885,6 +2379,10 @@
</span><span class="cx"> throwError(token, Messages.UnexpectedToken, token.value);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (token.type === Token.Template) {
+ throwError(token, Messages.UnexpectedTemplate, token.value.raw);
+ }
+
</ins><span class="cx"> // BooleanLiteral, NullLiteral, or Punctuator.
</span><span class="cx"> throwError(token, Messages.UnexpectedToken, token.value);
</span><span class="cx"> }
</span><span class="lines">@@ -1921,6 +2419,13 @@
</span><span class="cx"> return lookahead.type === Token.Keyword && lookahead.value === keyword;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+
+ // Return true if the next token matches the specified contextual keyword
+
+ function matchContextualKeyword(keyword) {
+ return lookahead.type === Token.Identifier && lookahead.value === keyword;
+ }
+
</ins><span class="cx"> // Return true if the next token is an assignment operator
</span><span class="cx">
</span><span class="cx"> function matchAssign() {
</span><span class="lines">@@ -1945,10 +2450,11 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function consumeSemicolon() {
</span><del>- var line;
</del><ins>+ var line, oldIndex = index, oldLineNumber = lineNumber,
+ oldLineStart = lineStart, oldLookahead = lookahead;
</ins><span class="cx">
</span><del>- // Catch the very common case first: immediately a semicolon (U+003B).
- if (source.charCodeAt(index) === 0x3B || match(';')) {
</del><ins>+ // Catch the very common case first: immediately a semicolon (char #59).
+ if (source.charCodeAt(index) === 59) {
</ins><span class="cx"> lex();
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -1956,9 +2462,18 @@
</span><span class="cx"> line = lineNumber;
</span><span class="cx"> skipComment();
</span><span class="cx"> if (lineNumber !== line) {
</span><ins>+ index = oldIndex;
+ lineNumber = oldLineNumber;
+ lineStart = oldLineStart;
+ lookahead = oldLookahead;
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (match(';')) {
+ lex();
+ return;
+ }
+
</ins><span class="cx"> if (lookahead.type !== Token.EOF && !match('}')) {
</span><span class="cx"> throwUnexpected(lookahead);
</span><span class="cx"> }
</span><span class="lines">@@ -1970,53 +2485,137 @@
</span><span class="cx"> return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ function isAssignableLeftHandSide(expr) {
+ return isLeftHandSide(expr) || expr.type === Syntax.ObjectPattern || expr.type === Syntax.ArrayPattern;
+ }
+
</ins><span class="cx"> // 11.1.4 Array Initialiser
</span><span class="cx">
</span><span class="cx"> function parseArrayInitialiser() {
</span><del>- var elements = [], startToken;
</del><ins>+ var elements = [], blocks = [], filter = null, tmp, possiblecomprehension = true,
+ marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
</del><span class="cx"> expect('[');
</span><del>-
</del><span class="cx"> while (!match(']')) {
</span><del>- if (match(',')) {
</del><ins>+ if (lookahead.value === 'for' &&
+ lookahead.type === Token.Keyword) {
+ if (!possiblecomprehension) {
+ throwError({}, Messages.ComprehensionError);
+ }
+ matchKeyword('for');
+ tmp = parseForStatement({ignoreBody: true});
+ tmp.of = tmp.type === Syntax.ForOfStatement;
+ tmp.type = Syntax.ComprehensionBlock;
+ if (tmp.left.kind) { // can't be let or const
+ throwError({}, Messages.ComprehensionError);
+ }
+ blocks.push(tmp);
+ } else if (lookahead.value === 'if' &&
+ lookahead.type === Token.Keyword) {
+ if (!possiblecomprehension) {
+ throwError({}, Messages.ComprehensionError);
+ }
+ expectKeyword('if');
+ expect('(');
+ filter = parseExpression();
+ expect(')');
+ } else if (lookahead.value === ',' &&
+ lookahead.type === Token.Punctuator) {
+ possiblecomprehension = false; // no longer allowed.
</ins><span class="cx"> lex();
</span><span class="cx"> elements.push(null);
</span><span class="cx"> } else {
</span><del>- elements.push(parseAssignmentExpression());
-
- if (!match(']')) {
- expect(',');
</del><ins>+ tmp = parseSpreadOrAssignmentExpression();
+ elements.push(tmp);
+ if (tmp && tmp.type === Syntax.SpreadElement) {
+ if (!match(']')) {
+ throwError({}, Messages.ElementAfterSpreadElement);
+ }
+ } else if (!(match(']') || matchKeyword('for') || matchKeyword('if'))) {
+ expect(','); // this lexes.
+ possiblecomprehension = false;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- lex();
</del><ins>+ expect(']');
</ins><span class="cx">
</span><del>- return delegate.markEnd(delegate.createArrayExpression(elements), startToken);
</del><ins>+ if (filter && !blocks.length) {
+ throwError({}, Messages.ComprehensionRequiresBlock);
+ }
+
+ if (blocks.length) {
+ if (elements.length !== 1) {
+ throwError({}, Messages.ComprehensionError);
+ }
+ return markerApply(marker, delegate.createComprehensionExpression(filter, blocks, elements[0]));
+ }
+ return markerApply(marker, delegate.createArrayExpression(elements));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 11.1.5 Object Initialiser
</span><span class="cx">
</span><del>- function parsePropertyFunction(param, first) {
- var previousStrict, body, startToken;
</del><ins>+ function parsePropertyFunction(options) {
+ var previousStrict, previousYieldAllowed, params, defaults, body,
+ marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> previousStrict = strict;
</span><del>- startToken = lookahead;
- body = parseFunctionSourceElements();
- if (first && strict && isRestrictedWord(param[0].name)) {
- throwErrorTolerant(first, Messages.StrictParamName);
</del><ins>+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = options.generator;
+ params = options.params || [];
+ defaults = options.defaults || [];
+
+ body = parseConciseBody();
+ if (options.name && strict && isRestrictedWord(params[0].name)) {
+ throwErrorTolerant(options.name, Messages.StrictParamName);
</ins><span class="cx"> }
</span><span class="cx"> strict = previousStrict;
</span><del>- return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken);
</del><ins>+ state.yieldAllowed = previousYieldAllowed;
+
+ return markerApply(marker, delegate.createFunctionExpression(
+ null,
+ params,
+ defaults,
+ body,
+ options.rest || null,
+ options.generator,
+ body.type !== Syntax.BlockStatement
+ ));
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+
+ function parsePropertyMethodFunction(options) {
+ var previousStrict, tmp, method;
+
+ previousStrict = strict;
+ strict = true;
+
+ tmp = parseParams();
+
+ if (tmp.stricted) {
+ throwErrorTolerant(tmp.stricted, tmp.message);
+ }
+
+
+ method = parsePropertyFunction({
+ params: tmp.params,
+ defaults: tmp.defaults,
+ rest: tmp.rest,
+ generator: options.generator
+ });
+
+ strict = previousStrict;
+
+ return method;
+ }
+
+
</ins><span class="cx"> function parseObjectPropertyKey() {
</span><del>- var token, startToken;
</del><ins>+ var marker = markerCreate(),
+ token = lex(),
+ propertyKey,
+ result;
</ins><span class="cx">
</span><del>- startToken = lookahead;
- token = lex();
-
</del><span class="cx"> // Note: This function is called only from parseObjectProperty(), where
</span><span class="cx"> // EOF and Punctuator tokens are already filtered out.
</span><span class="cx">
</span><span class="lines">@@ -2024,95 +2623,131 @@
</span><span class="cx"> if (strict && token.octal) {
</span><span class="cx"> throwErrorTolerant(token, Messages.StrictOctalLiteral);
</span><span class="cx"> }
</span><del>- return delegate.markEnd(delegate.createLiteral(token), startToken);
</del><ins>+ return markerApply(marker, delegate.createLiteral(token));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
</del><ins>+ if (token.type === Token.Punctuator && token.value === '[') {
+ // For computed properties we should skip the [ and ], and
+ // capture in marker only the assignment expression itself.
+ marker = markerCreate();
+ propertyKey = parseAssignmentExpression();
+ result = markerApply(marker, propertyKey);
+ expect(']');
+ return result;
+ }
+
+ return markerApply(marker, delegate.createIdentifier(token.value));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseObjectProperty() {
</span><del>- var token, key, id, value, param, startToken;
</del><ins>+ var token, key, id, param, computed,
+ marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> token = lookahead;
</span><del>- startToken = lookahead;
</del><ins>+ computed = (token.value === '[' && token.type === Token.Punctuator);
</ins><span class="cx">
</span><del>- if (token.type === Token.Identifier) {
</del><ins>+ if (token.type === Token.Identifier || computed) {
</ins><span class="cx">
</span><span class="cx"> id = parseObjectPropertyKey();
</span><span class="cx">
</span><span class="cx"> // Property Assignment: Getter and Setter.
</span><span class="cx">
</span><del>- if (token.value === 'get' && !match(':')) {
</del><ins>+ if (token.value === 'get' && !(match(':') || match('('))) {
+ computed = (lookahead.value === '[');
</ins><span class="cx"> key = parseObjectPropertyKey();
</span><span class="cx"> expect('(');
</span><span class="cx"> expect(')');
</span><del>- value = parsePropertyFunction([]);
- return delegate.markEnd(delegate.createProperty('get', key, value), startToken);
</del><ins>+ return markerApply(marker, delegate.createProperty('get', key, parsePropertyFunction({ generator: false }), false, false, computed));
</ins><span class="cx"> }
</span><del>- if (token.value === 'set' && !match(':')) {
</del><ins>+ if (token.value === 'set' && !(match(':') || match('('))) {
+ computed = (lookahead.value === '[');
</ins><span class="cx"> key = parseObjectPropertyKey();
</span><span class="cx"> expect('(');
</span><span class="cx"> token = lookahead;
</span><del>- if (token.type !== Token.Identifier) {
- expect(')');
- throwErrorTolerant(token, Messages.UnexpectedToken, token.value);
- value = parsePropertyFunction([]);
- } else {
- param = [ parseVariableIdentifier() ];
- expect(')');
- value = parsePropertyFunction(param, token);
- }
- return delegate.markEnd(delegate.createProperty('set', key, value), startToken);
</del><ins>+ param = [ parseVariableIdentifier() ];
+ expect(')');
+ return markerApply(marker, delegate.createProperty('set', key, parsePropertyFunction({ params: param, generator: false, name: token }), false, false, computed));
</ins><span class="cx"> }
</span><del>- expect(':');
- value = parseAssignmentExpression();
- return delegate.markEnd(delegate.createProperty('init', id, value), startToken);
</del><ins>+ if (match(':')) {
+ lex();
+ return markerApply(marker, delegate.createProperty('init', id, parseAssignmentExpression(), false, false, computed));
+ }
+ if (match('(')) {
+ return markerApply(marker, delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: false }), true, false, computed));
+ }
+ if (computed) {
+ // Computed properties can only be used with full notation.
+ throwUnexpected(lookahead);
+ }
+ return markerApply(marker, delegate.createProperty('init', id, id, false, true, false));
</ins><span class="cx"> }
</span><span class="cx"> if (token.type === Token.EOF || token.type === Token.Punctuator) {
</span><del>- throwUnexpected(token);
- } else {
- key = parseObjectPropertyKey();
- expect(':');
- value = parseAssignmentExpression();
- return delegate.markEnd(delegate.createProperty('init', key, value), startToken);
</del><ins>+ if (!match('*')) {
+ throwUnexpected(token);
+ }
+ lex();
+
+ computed = (lookahead.type === Token.Punctuator && lookahead.value === '[');
+
+ id = parseObjectPropertyKey();
+
+ if (!match('(')) {
+ throwUnexpected(lex());
+ }
+
+ return markerApply(marker, delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: true }), true, false, computed));
</ins><span class="cx"> }
</span><ins>+ key = parseObjectPropertyKey();
+ if (match(':')) {
+ lex();
+ return markerApply(marker, delegate.createProperty('init', key, parseAssignmentExpression(), false, false, false));
+ }
+ if (match('(')) {
+ return markerApply(marker, delegate.createProperty('init', key, parsePropertyMethodFunction({ generator: false }), true, false, false));
+ }
+ throwUnexpected(lex());
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ function getFieldName(key) {
+ var toString = String;
+ if (key.type === Syntax.Identifier) {
+ return key.name;
+ }
+ return toString(key.value);
+ }
+
</ins><span class="cx"> function parseObjectInitialiser() {
</span><del>- var properties = [], property, name, key, kind, map = {}, toString = String, startToken;
</del><ins>+ var properties = [], property, name, kind, storedKind, map = new StringMap(),
+ marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
-
</del><span class="cx"> expect('{');
</span><span class="cx">
</span><span class="cx"> while (!match('}')) {
</span><span class="cx"> property = parseObjectProperty();
</span><span class="cx">
</span><del>- if (property.key.type === Syntax.Identifier) {
- name = property.key.name;
- } else {
- name = toString(property.key.value);
- }
- kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
</del><ins>+ if (!property.computed) {
+ name = getFieldName(property.key);
+ kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
</ins><span class="cx">
</span><del>- key = '$' + name;
- if (Object.prototype.hasOwnProperty.call(map, key)) {
- if (map[key] === PropertyKind.Data) {
- if (strict && kind === PropertyKind.Data) {
- throwErrorTolerant({}, Messages.StrictDuplicateProperty);
- } else if (kind !== PropertyKind.Data) {
- throwErrorTolerant({}, Messages.AccessorDataProperty);
</del><ins>+ if (map.has(name)) {
+ storedKind = map.get(name);
+ if (storedKind === PropertyKind.Data) {
+ if (strict && kind === PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.StrictDuplicateProperty);
+ } else if (kind !== PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.AccessorDataProperty);
+ }
+ } else {
+ if (kind === PropertyKind.Data) {
+ throwErrorTolerant({}, Messages.AccessorDataProperty);
+ } else if (storedKind & kind) {
+ throwErrorTolerant({}, Messages.AccessorGetSet);
+ }
</ins><span class="cx"> }
</span><ins>+ map.set(name, storedKind | kind);
</ins><span class="cx"> } else {
</span><del>- if (kind === PropertyKind.Data) {
- throwErrorTolerant({}, Messages.AccessorDataProperty);
- } else if (map[key] & kind) {
- throwErrorTolerant({}, Messages.AccessorGetSet);
- }
</del><ins>+ map.set(name, kind);
</ins><span class="cx"> }
</span><del>- map[key] |= kind;
- } else {
- map[key] = kind;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> properties.push(property);
</span><span class="lines">@@ -2124,9 +2759,34 @@
</span><span class="cx">
</span><span class="cx"> expect('}');
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createObjectExpression(properties), startToken);
</del><ins>+ return markerApply(marker, delegate.createObjectExpression(properties));
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ function parseTemplateElement(option) {
+ var marker = markerCreate(),
+ token = scanTemplateElement(option);
+ if (strict && token.octal) {
+ throwError(token, Messages.StrictOctalLiteral);
+ }
+ return markerApply(marker, delegate.createTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail));
+ }
+
+ function parseTemplateLiteral() {
+ var quasi, quasis, expressions, marker = markerCreate();
+
+ quasi = parseTemplateElement({ head: true });
+ quasis = [ quasi ];
+ expressions = [];
+
+ while (!quasi.tail) {
+ expressions.push(parseExpression());
+ quasi = parseTemplateElement({ head: false });
+ quasis.push(quasi);
+ }
+
+ return markerApply(marker, delegate.createTemplateLiteral(quasis, expressions));
+ }
+
</ins><span class="cx"> // 11.1.6 The Grouping Operator
</span><span class="cx">
</span><span class="cx"> function parseGroupExpression() {
</span><span class="lines">@@ -2134,6 +2794,8 @@
</span><span class="cx">
</span><span class="cx"> expect('(');
</span><span class="cx">
</span><ins>+ ++state.parenthesizedCount;
+
</ins><span class="cx"> expr = parseExpression();
</span><span class="cx">
</span><span class="cx"> expect(')');
</span><span class="lines">@@ -2145,75 +2807,103 @@
</span><span class="cx"> // 11.1 Primary Expressions
</span><span class="cx">
</span><span class="cx"> function parsePrimaryExpression() {
</span><del>- var type, token, expr, startToken;
</del><ins>+ var marker, type, token, expr;
</ins><span class="cx">
</span><del>- if (match('(')) {
- return parseGroupExpression();
- }
</del><ins>+ type = lookahead.type;
</ins><span class="cx">
</span><del>- if (match('[')) {
- return parseArrayInitialiser();
</del><ins>+ if (type === Token.Identifier) {
+ marker = markerCreate();
+ return markerApply(marker, delegate.createIdentifier(lex().value));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- if (match('{')) {
- return parseObjectInitialiser();
</del><ins>+ if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+ if (strict && lookahead.octal) {
+ throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
+ }
+ marker = markerCreate();
+ return markerApply(marker, delegate.createLiteral(lex()));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- type = lookahead.type;
- startToken = lookahead;
</del><ins>+ if (type === Token.Keyword) {
+ if (matchKeyword('this')) {
+ marker = markerCreate();
+ lex();
+ return markerApply(marker, delegate.createThisExpression());
+ }
</ins><span class="cx">
</span><del>- if (type === Token.Identifier) {
- expr = delegate.createIdentifier(lex().value);
- } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
- if (strict && lookahead.octal) {
- throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
- }
- expr = delegate.createLiteral(lex());
- } else if (type === Token.Keyword) {
</del><span class="cx"> if (matchKeyword('function')) {
</span><span class="cx"> return parseFunctionExpression();
</span><span class="cx"> }
</span><del>- if (matchKeyword('this')) {
</del><ins>+
+ if (matchKeyword('class')) {
+ return parseClassExpression();
+ }
+
+ if (matchKeyword('super')) {
+ marker = markerCreate();
</ins><span class="cx"> lex();
</span><del>- expr = delegate.createThisExpression();
- } else {
- throwUnexpected(lex());
</del><ins>+ return markerApply(marker, delegate.createIdentifier('super'));
</ins><span class="cx"> }
</span><del>- } else if (type === Token.BooleanLiteral) {
</del><ins>+ }
+
+ if (type === Token.BooleanLiteral) {
+ marker = markerCreate();
</ins><span class="cx"> token = lex();
</span><span class="cx"> token.value = (token.value === 'true');
</span><del>- expr = delegate.createLiteral(token);
- } else if (type === Token.NullLiteral) {
</del><ins>+ return markerApply(marker, delegate.createLiteral(token));
+ }
+
+ if (type === Token.NullLiteral) {
+ marker = markerCreate();
</ins><span class="cx"> token = lex();
</span><span class="cx"> token.value = null;
</span><del>- expr = delegate.createLiteral(token);
- } else if (match('/') || match('/=')) {
- if (typeof extra.tokens !== 'undefined') {
- expr = delegate.createLiteral(collectRegex());
- } else {
- expr = delegate.createLiteral(scanRegExp());
- }
</del><ins>+ return markerApply(marker, delegate.createLiteral(token));
+ }
+
+ if (match('[')) {
+ return parseArrayInitialiser();
+ }
+
+ if (match('{')) {
+ return parseObjectInitialiser();
+ }
+
+ if (match('(')) {
+ return parseGroupExpression();
+ }
+
+ if (match('/') || match('/=')) {
+ marker = markerCreate();
+ expr = delegate.createLiteral(scanRegExp());
</ins><span class="cx"> peek();
</span><del>- } else {
- throwUnexpected(lex());
</del><ins>+ return markerApply(marker, expr);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.markEnd(expr, startToken);
</del><ins>+ if (type === Token.Template) {
+ return parseTemplateLiteral();
+ }
+
+ throwUnexpected(lex());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 11.2 Left-Hand-Side Expressions
</span><span class="cx">
</span><span class="cx"> function parseArguments() {
</span><del>- var args = [];
</del><ins>+ var args = [], arg;
</ins><span class="cx">
</span><span class="cx"> expect('(');
</span><span class="cx">
</span><span class="cx"> if (!match(')')) {
</span><span class="cx"> while (index < length) {
</span><del>- args.push(parseAssignmentExpression());
</del><ins>+ arg = parseSpreadOrAssignmentExpression();
+ args.push(arg);
+
</ins><span class="cx"> if (match(')')) {
</span><span class="cx"> break;
</span><ins>+ } else if (arg.type === Syntax.SpreadElement) {
+ throwError({}, Messages.ElementAfterSpreadElement);
</ins><span class="cx"> }
</span><ins>+
</ins><span class="cx"> expect(',');
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -2223,17 +2913,24 @@
</span><span class="cx"> return args;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ function parseSpreadOrAssignmentExpression() {
+ if (match('...')) {
+ var marker = markerCreate();
+ lex();
+ return markerApply(marker, delegate.createSpreadElement(parseAssignmentExpression()));
+ }
+ return parseAssignmentExpression();
+ }
+
</ins><span class="cx"> function parseNonComputedProperty() {
</span><del>- var token, startToken;
</del><ins>+ var marker = markerCreate(),
+ token = lex();
</ins><span class="cx">
</span><del>- startToken = lookahead;
- token = lex();
-
</del><span class="cx"> if (!isIdentifierName(token)) {
</span><span class="cx"> throwUnexpected(token);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
</del><ins>+ return markerApply(marker, delegate.createIdentifier(token.value));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseNonComputedMember() {
</span><span class="lines">@@ -2255,63 +2952,49 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseNewExpression() {
</span><del>- var callee, args, startToken;
</del><ins>+ var callee, args, marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
</del><span class="cx"> expectKeyword('new');
</span><span class="cx"> callee = parseLeftHandSideExpression();
</span><span class="cx"> args = match('(') ? parseArguments() : [];
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createNewExpression(callee, args), startToken);
</del><ins>+ return markerApply(marker, delegate.createNewExpression(callee, args));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseLeftHandSideExpressionAllowCall() {
</span><del>- var previousAllowIn, expr, args, property, startToken;
</del><ins>+ var expr, args, marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
-
- previousAllowIn = state.allowIn;
- state.allowIn = true;
</del><span class="cx"> expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
</span><del>- state.allowIn = previousAllowIn;
</del><span class="cx">
</span><del>- for (;;) {
- if (match('.')) {
- property = parseNonComputedMember();
- expr = delegate.createMemberExpression('.', expr, property);
- } else if (match('(')) {
</del><ins>+ while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) {
+ if (match('(')) {
</ins><span class="cx"> args = parseArguments();
</span><del>- expr = delegate.createCallExpression(expr, args);
</del><ins>+ expr = markerApply(marker, delegate.createCallExpression(expr, args));
</ins><span class="cx"> } else if (match('[')) {
</span><del>- property = parseComputedMember();
- expr = delegate.createMemberExpression('[', expr, property);
</del><ins>+ expr = markerApply(marker, delegate.createMemberExpression('[', expr, parseComputedMember()));
+ } else if (match('.')) {
+ expr = markerApply(marker, delegate.createMemberExpression('.', expr, parseNonComputedMember()));
</ins><span class="cx"> } else {
</span><del>- break;
</del><ins>+ expr = markerApply(marker, delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()));
</ins><span class="cx"> }
</span><del>- delegate.markEnd(expr, startToken);
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return expr;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseLeftHandSideExpression() {
</span><del>- var previousAllowIn, expr, property, startToken;
</del><ins>+ var expr, marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
-
- previousAllowIn = state.allowIn;
</del><span class="cx"> expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
</span><del>- state.allowIn = previousAllowIn;
</del><span class="cx">
</span><del>- while (match('.') || match('[')) {
</del><ins>+ while (match('.') || match('[') || lookahead.type === Token.Template) {
</ins><span class="cx"> if (match('[')) {
</span><del>- property = parseComputedMember();
- expr = delegate.createMemberExpression('[', expr, property);
</del><ins>+ expr = markerApply(marker, delegate.createMemberExpression('[', expr, parseComputedMember()));
+ } else if (match('.')) {
+ expr = markerApply(marker, delegate.createMemberExpression('.', expr, parseNonComputedMember()));
</ins><span class="cx"> } else {
</span><del>- property = parseNonComputedMember();
- expr = delegate.createMemberExpression('.', expr, property);
</del><ins>+ expr = markerApply(marker, delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()));
</ins><span class="cx"> }
</span><del>- delegate.markEnd(expr, startToken);
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return expr;
</span><span class="lines">@@ -2320,24 +3003,26 @@
</span><span class="cx"> // 11.3 Postfix Expressions
</span><span class="cx">
</span><span class="cx"> function parsePostfixExpression() {
</span><del>- var expr, token, startToken = lookahead;
</del><ins>+ var marker = markerCreate(),
+ expr = parseLeftHandSideExpressionAllowCall(),
+ token;
</ins><span class="cx">
</span><del>- expr = parseLeftHandSideExpressionAllowCall();
</del><ins>+ if (lookahead.type !== Token.Punctuator) {
+ return expr;
+ }
</ins><span class="cx">
</span><del>- if (lookahead.type === Token.Punctuator) {
- if ((match('++') || match('--')) && !peekLineTerminator()) {
- // 11.3.1, 11.3.2
- if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
- throwErrorTolerant({}, Messages.StrictLHSPostfix);
- }
</del><ins>+ if ((match('++') || match('--')) && !peekLineTerminator()) {
+ // 11.3.1, 11.3.2
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ throwErrorTolerant({}, Messages.StrictLHSPostfix);
+ }
</ins><span class="cx">
</span><del>- if (!isLeftHandSide(expr)) {
- throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
- }
</del><ins>+ if (!isLeftHandSide(expr)) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
</ins><span class="cx">
</span><del>- token = lex();
- expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken);
- }
</del><ins>+ token = lex();
+ expr = markerApply(marker, delegate.createPostfixExpression(token.value, expr));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return expr;
</span><span class="lines">@@ -2346,12 +3031,14 @@
</span><span class="cx"> // 11.4 Unary Operators
</span><span class="cx">
</span><span class="cx"> function parseUnaryExpression() {
</span><del>- var token, expr, startToken;
</del><ins>+ var marker, token, expr;
</ins><span class="cx">
</span><span class="cx"> if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
</span><del>- expr = parsePostfixExpression();
- } else if (match('++') || match('--')) {
- startToken = lookahead;
</del><ins>+ return parsePostfixExpression();
+ }
+
+ if (match('++') || match('--')) {
+ marker = markerCreate();
</ins><span class="cx"> token = lex();
</span><span class="cx"> expr = parseUnaryExpression();
</span><span class="cx"> // 11.4.4, 11.4.5
</span><span class="lines">@@ -2360,31 +3047,31 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (!isLeftHandSide(expr)) {
</span><del>- throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
</del><ins>+ throwError({}, Messages.InvalidLHSInAssignment);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- expr = delegate.createUnaryExpression(token.value, expr);
- expr = delegate.markEnd(expr, startToken);
- } else if (match('+') || match('-') || match('~') || match('!')) {
- startToken = lookahead;
</del><ins>+ return markerApply(marker, delegate.createUnaryExpression(token.value, expr));
+ }
+
+ if (match('+') || match('-') || match('~') || match('!')) {
+ marker = markerCreate();
</ins><span class="cx"> token = lex();
</span><span class="cx"> expr = parseUnaryExpression();
</span><del>- expr = delegate.createUnaryExpression(token.value, expr);
- expr = delegate.markEnd(expr, startToken);
- } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
- startToken = lookahead;
</del><ins>+ return markerApply(marker, delegate.createUnaryExpression(token.value, expr));
+ }
+
+ if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
+ marker = markerCreate();
</ins><span class="cx"> token = lex();
</span><span class="cx"> expr = parseUnaryExpression();
</span><del>- expr = delegate.createUnaryExpression(token.value, expr);
- expr = delegate.markEnd(expr, startToken);
</del><ins>+ expr = markerApply(marker, delegate.createUnaryExpression(token.value, expr));
</ins><span class="cx"> if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
</span><span class="cx"> throwErrorTolerant({}, Messages.StrictDelete);
</span><span class="cx"> }
</span><del>- } else {
- expr = parsePostfixExpression();
</del><ins>+ return expr;
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return expr;
</del><ins>+ return parsePostfixExpression();
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function binaryPrecedence(token, allowIn) {
</span><span class="lines">@@ -2467,25 +3154,29 @@
</span><span class="cx"> // 11.11 Binary Logical Operators
</span><span class="cx">
</span><span class="cx"> function parseBinaryExpression() {
</span><del>- var marker, markers, expr, token, prec, stack, right, operator, left, i;
</del><ins>+ var expr, token, prec, previousAllowIn, stack, right, operator, left, i,
+ marker, markers;
</ins><span class="cx">
</span><del>- marker = lookahead;
</del><ins>+ previousAllowIn = state.allowIn;
+ state.allowIn = true;
+
+ marker = markerCreate();
</ins><span class="cx"> left = parseUnaryExpression();
</span><span class="cx">
</span><span class="cx"> token = lookahead;
</span><del>- prec = binaryPrecedence(token, state.allowIn);
</del><ins>+ prec = binaryPrecedence(token, previousAllowIn);
</ins><span class="cx"> if (prec === 0) {
</span><span class="cx"> return left;
</span><span class="cx"> }
</span><span class="cx"> token.prec = prec;
</span><span class="cx"> lex();
</span><span class="cx">
</span><del>- markers = [marker, lookahead];
</del><ins>+ markers = [marker, markerCreate()];
</ins><span class="cx"> right = parseUnaryExpression();
</span><span class="cx">
</span><span class="cx"> stack = [left, token, right];
</span><span class="cx">
</span><del>- while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
</del><ins>+ while ((prec = binaryPrecedence(lookahead, previousAllowIn)) > 0) {
</ins><span class="cx">
</span><span class="cx"> // Reduce: make a binary expression from the three topmost entries.
</span><span class="cx"> while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
</span><span class="lines">@@ -2494,20 +3185,23 @@
</span><span class="cx"> left = stack.pop();
</span><span class="cx"> expr = delegate.createBinaryExpression(operator, left, right);
</span><span class="cx"> markers.pop();
</span><del>- marker = markers[markers.length - 1];
- delegate.markEnd(expr, marker);
</del><ins>+ marker = markers.pop();
+ markerApply(marker, expr);
</ins><span class="cx"> stack.push(expr);
</span><ins>+ markers.push(marker);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Shift.
</span><span class="cx"> token = lex();
</span><span class="cx"> token.prec = prec;
</span><span class="cx"> stack.push(token);
</span><del>- markers.push(lookahead);
</del><ins>+ markers.push(markerCreate());
</ins><span class="cx"> expr = parseUnaryExpression();
</span><span class="cx"> stack.push(expr);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ state.allowIn = previousAllowIn;
+
</ins><span class="cx"> // Final reduce to clean-up the stack.
</span><span class="cx"> i = stack.length - 1;
</span><span class="cx"> expr = stack[i];
</span><span class="lines">@@ -2516,7 +3210,7 @@
</span><span class="cx"> expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
</span><span class="cx"> i -= 2;
</span><span class="cx"> marker = markers.pop();
</span><del>- delegate.markEnd(expr, marker);
</del><ins>+ markerApply(marker, expr);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return expr;
</span><span class="lines">@@ -2526,10 +3220,7 @@
</span><span class="cx"> // 11.12 Conditional Operator
</span><span class="cx">
</span><span class="cx"> function parseConditionalExpression() {
</span><del>- var expr, previousAllowIn, consequent, alternate, startToken;
-
- startToken = lookahead;
-
</del><ins>+ var expr, previousAllowIn, consequent, alternate, marker = markerCreate();
</ins><span class="cx"> expr = parseBinaryExpression();
</span><span class="cx">
</span><span class="cx"> if (match('?')) {
</span><span class="lines">@@ -2541,8 +3232,7 @@
</span><span class="cx"> expect(':');
</span><span class="cx"> alternate = parseAssignmentExpression();
</span><span class="cx">
</span><del>- expr = delegate.createConditionalExpression(expr, consequent, alternate);
- delegate.markEnd(expr, startToken);
</del><ins>+ expr = markerApply(marker, delegate.createConditionalExpression(expr, consequent, alternate));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return expr;
</span><span class="lines">@@ -2550,55 +3240,274 @@
</span><span class="cx">
</span><span class="cx"> // 11.13 Assignment Operators
</span><span class="cx">
</span><ins>+ // 12.14.5 AssignmentPattern
+
+ function reinterpretAsAssignmentBindingPattern(expr) {
+ var i, len, property, element;
+
+ if (expr.type === Syntax.ObjectExpression) {
+ expr.type = Syntax.ObjectPattern;
+ for (i = 0, len = expr.properties.length; i < len; i += 1) {
+ property = expr.properties[i];
+ if (property.kind !== 'init') {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ reinterpretAsAssignmentBindingPattern(property.value);
+ }
+ } else if (expr.type === Syntax.ArrayExpression) {
+ expr.type = Syntax.ArrayPattern;
+ for (i = 0, len = expr.elements.length; i < len; i += 1) {
+ element = expr.elements[i];
+ /* istanbul ignore else */
+ if (element) {
+ reinterpretAsAssignmentBindingPattern(element);
+ }
+ }
+ } else if (expr.type === Syntax.Identifier) {
+ if (isRestrictedWord(expr.name)) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ } else if (expr.type === Syntax.SpreadElement) {
+ reinterpretAsAssignmentBindingPattern(expr.argument);
+ if (expr.argument.type === Syntax.ObjectPattern) {
+ throwError({}, Messages.ObjectPatternAsSpread);
+ }
+ } else {
+ /* istanbul ignore else */
+ if (expr.type !== Syntax.MemberExpression && expr.type !== Syntax.CallExpression && expr.type !== Syntax.NewExpression) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+ }
+ }
+
+ // 13.2.3 BindingPattern
+
+ function reinterpretAsDestructuredParameter(options, expr) {
+ var i, len, property, element;
+
+ if (expr.type === Syntax.ObjectExpression) {
+ expr.type = Syntax.ObjectPattern;
+ for (i = 0, len = expr.properties.length; i < len; i += 1) {
+ property = expr.properties[i];
+ if (property.kind !== 'init') {
+ throwError({}, Messages.InvalidLHSInFormalsList);
+ }
+ reinterpretAsDestructuredParameter(options, property.value);
+ }
+ } else if (expr.type === Syntax.ArrayExpression) {
+ expr.type = Syntax.ArrayPattern;
+ for (i = 0, len = expr.elements.length; i < len; i += 1) {
+ element = expr.elements[i];
+ if (element) {
+ reinterpretAsDestructuredParameter(options, element);
+ }
+ }
+ } else if (expr.type === Syntax.Identifier) {
+ validateParam(options, expr, expr.name);
+ } else if (expr.type === Syntax.SpreadElement) {
+ // BindingRestElement only allows BindingIdentifier
+ if (expr.argument.type !== Syntax.Identifier) {
+ throwError({}, Messages.InvalidLHSInFormalsList);
+ }
+ validateParam(options, expr.argument, expr.argument.name);
+ } else {
+ throwError({}, Messages.InvalidLHSInFormalsList);
+ }
+ }
+
+ function reinterpretAsCoverFormalsList(expressions) {
+ var i, len, param, params, defaults, defaultCount, options, rest;
+
+ params = [];
+ defaults = [];
+ defaultCount = 0;
+ rest = null;
+ options = {
+ paramSet: new StringMap()
+ };
+
+ for (i = 0, len = expressions.length; i < len; i += 1) {
+ param = expressions[i];
+ if (param.type === Syntax.Identifier) {
+ params.push(param);
+ defaults.push(null);
+ validateParam(options, param, param.name);
+ } else if (param.type === Syntax.ObjectExpression || param.type === Syntax.ArrayExpression) {
+ reinterpretAsDestructuredParameter(options, param);
+ params.push(param);
+ defaults.push(null);
+ } else if (param.type === Syntax.SpreadElement) {
+ assert(i === len - 1, 'It is guaranteed that SpreadElement is last element by parseExpression');
+ if (param.argument.type !== Syntax.Identifier) {
+ throwError({}, Messages.InvalidLHSInFormalsList);
+ }
+ reinterpretAsDestructuredParameter(options, param.argument);
+ rest = param.argument;
+ } else if (param.type === Syntax.AssignmentExpression) {
+ params.push(param.left);
+ defaults.push(param.right);
+ ++defaultCount;
+ validateParam(options, param.left, param.left.name);
+ } else {
+ return null;
+ }
+ }
+
+ if (options.message === Messages.StrictParamDupe) {
+ throwError(
+ strict ? options.stricted : options.firstRestricted,
+ options.message
+ );
+ }
+
+ if (defaultCount === 0) {
+ defaults = [];
+ }
+
+ return {
+ params: params,
+ defaults: defaults,
+ rest: rest,
+ stricted: options.stricted,
+ firstRestricted: options.firstRestricted,
+ message: options.message
+ };
+ }
+
+ function parseArrowFunctionExpression(options, marker) {
+ var previousStrict, previousYieldAllowed, body;
+
+ expect('=>');
+
+ previousStrict = strict;
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = false;
+ body = parseConciseBody();
+
+ if (strict && options.firstRestricted) {
+ throwError(options.firstRestricted, options.message);
+ }
+ if (strict && options.stricted) {
+ throwErrorTolerant(options.stricted, options.message);
+ }
+
+ strict = previousStrict;
+ state.yieldAllowed = previousYieldAllowed;
+
+ return markerApply(marker, delegate.createArrowFunctionExpression(
+ options.params,
+ options.defaults,
+ body,
+ options.rest,
+ body.type !== Syntax.BlockStatement
+ ));
+ }
+
</ins><span class="cx"> function parseAssignmentExpression() {
</span><del>- var token, left, right, node, startToken;
</del><ins>+ var marker, expr, token, params, oldParenthesizedCount,
+ startsWithParen = false;
</ins><span class="cx">
</span><ins>+ // Note that 'yield' is treated as a keyword in strict mode, but a
+ // contextual keyword (identifier) in non-strict mode, so we need
+ // to use matchKeyword and matchContextualKeyword appropriately.
+ if ((state.yieldAllowed && matchContextualKeyword('yield')) || (strict && matchKeyword('yield'))) {
+ return parseYieldExpression();
+ }
+
+ oldParenthesizedCount = state.parenthesizedCount;
+
+ marker = markerCreate();
+
+ if (match('(')) {
+ token = lookahead2();
+ if ((token.type === Token.Punctuator && token.value === ')') || token.value === '...') {
+ params = parseParams();
+ if (!match('=>')) {
+ throwUnexpected(lex());
+ }
+ return parseArrowFunctionExpression(params, marker);
+ }
+ startsWithParen = true;
+ }
+
</ins><span class="cx"> token = lookahead;
</span><del>- startToken = lookahead;
</del><ins>+ expr = parseConditionalExpression();
</ins><span class="cx">
</span><del>- node = left = parseConditionalExpression();
</del><ins>+ if (match('=>') &&
+ (state.parenthesizedCount === oldParenthesizedCount ||
+ state.parenthesizedCount === (oldParenthesizedCount + 1))) {
+ if (expr.type === Syntax.Identifier) {
+ params = reinterpretAsCoverFormalsList([ expr ]);
+ } else if (expr.type === Syntax.AssignmentExpression ||
+ expr.type === Syntax.ArrayExpression ||
+ expr.type === Syntax.ObjectExpression) {
+ if (!startsWithParen) {
+ throwUnexpected(lex());
+ }
+ params = reinterpretAsCoverFormalsList([ expr ]);
+ } else if (expr.type === Syntax.SequenceExpression) {
+ params = reinterpretAsCoverFormalsList(expr.expressions);
+ }
+ if (params) {
+ return parseArrowFunctionExpression(params, marker);
+ }
+ }
</ins><span class="cx">
</span><span class="cx"> if (matchAssign()) {
</span><del>- // LeftHandSideExpression
- if (!isLeftHandSide(left)) {
- throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
- }
-
</del><span class="cx"> // 11.13.1
</span><del>- if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) {
</del><ins>+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
</ins><span class="cx"> throwErrorTolerant(token, Messages.StrictLHSAssignment);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- token = lex();
- right = parseAssignmentExpression();
- node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken);
</del><ins>+ // ES.next draf 11.13 Runtime Semantics step 1
+ if (match('=') && (expr.type === Syntax.ObjectExpression || expr.type === Syntax.ArrayExpression)) {
+ reinterpretAsAssignmentBindingPattern(expr);
+ } else if (!isLeftHandSide(expr)) {
+ throwError({}, Messages.InvalidLHSInAssignment);
+ }
+
+ expr = markerApply(marker, delegate.createAssignmentExpression(lex().value, expr, parseAssignmentExpression()));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return node;
</del><ins>+ return expr;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 11.14 Comma Operator
</span><span class="cx">
</span><span class="cx"> function parseExpression() {
</span><del>- var expr, startToken = lookahead;
</del><ins>+ var marker, expr, expressions, sequence, spreadFound;
</ins><span class="cx">
</span><ins>+ marker = markerCreate();
</ins><span class="cx"> expr = parseAssignmentExpression();
</span><ins>+ expressions = [ expr ];
</ins><span class="cx">
</span><span class="cx"> if (match(',')) {
</span><del>- expr = delegate.createSequenceExpression([ expr ]);
-
</del><span class="cx"> while (index < length) {
</span><span class="cx"> if (!match(',')) {
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> lex();
</span><del>- expr.expressions.push(parseAssignmentExpression());
</del><ins>+ expr = parseSpreadOrAssignmentExpression();
+ expressions.push(expr);
+
+ if (expr.type === Syntax.SpreadElement) {
+ spreadFound = true;
+ if (!match(')')) {
+ throwError({}, Messages.ElementAfterSpreadElement);
+ }
+ break;
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- delegate.markEnd(expr, startToken);
</del><ins>+ sequence = markerApply(marker, delegate.createSequenceExpression(expressions));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return expr;
</del><ins>+ if (spreadFound && lookahead2().value !== '=>') {
+ throwError({}, Messages.IllegalSpread);
+ }
+
+ return sequence || expr;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.1 Block
</span><span class="lines">@@ -2622,45 +3531,53 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseBlock() {
</span><del>- var block, startToken;
</del><ins>+ var block, marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
</del><span class="cx"> expect('{');
</span><span class="cx">
</span><span class="cx"> block = parseStatementList();
</span><span class="cx">
</span><span class="cx"> expect('}');
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createBlockStatement(block), startToken);
</del><ins>+ return markerApply(marker, delegate.createBlockStatement(block));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.2 Variable Statement
</span><span class="cx">
</span><span class="cx"> function parseVariableIdentifier() {
</span><del>- var token, startToken;
</del><ins>+ var marker = markerCreate(),
+ token = lex();
</ins><span class="cx">
</span><del>- startToken = lookahead;
- token = lex();
-
</del><span class="cx"> if (token.type !== Token.Identifier) {
</span><span class="cx"> throwUnexpected(token);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
</del><ins>+ return markerApply(marker, delegate.createIdentifier(token.value));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseVariableDeclaration(kind) {
</span><del>- var init = null, id, startToken;
-
- startToken = lookahead;
- id = parseVariableIdentifier();
-
- // 12.2.1
- if (strict && isRestrictedWord(id.name)) {
- throwErrorTolerant({}, Messages.StrictVarName);
</del><ins>+ var id,
+ marker = markerCreate(),
+ init = null;
+ if (match('{')) {
+ id = parseObjectInitialiser();
+ reinterpretAsAssignmentBindingPattern(id);
+ } else if (match('[')) {
+ id = parseArrayInitialiser();
+ reinterpretAsAssignmentBindingPattern(id);
+ } else {
+ /* istanbul ignore next */
+ id = state.allowKeyword ? parseNonComputedProperty() : parseVariableIdentifier();
+ // 12.2.1
+ if (strict && isRestrictedWord(id.name)) {
+ throwErrorTolerant({}, Messages.StrictVarName);
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (kind === 'const') {
</span><ins>+ if (!match('=')) {
+ throwError({}, Messages.NoUnintializedConst);
+ }
</ins><span class="cx"> expect('=');
</span><span class="cx"> init = parseAssignmentExpression();
</span><span class="cx"> } else if (match('=')) {
</span><span class="lines">@@ -2668,7 +3585,7 @@
</span><span class="cx"> init = parseAssignmentExpression();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken);
</del><ins>+ return markerApply(marker, delegate.createVariableDeclarator(id, init));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseVariableDeclarationList(kind) {
</span><span class="lines">@@ -2686,7 +3603,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseVariableStatement() {
</span><del>- var declarations;
</del><ins>+ var declarations, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('var');
</span><span class="cx">
</span><span class="lines">@@ -2694,7 +3611,7 @@
</span><span class="cx">
</span><span class="cx"> consumeSemicolon();
</span><span class="cx">
</span><del>- return delegate.createVariableDeclaration(declarations, 'var');
</del><ins>+ return markerApply(marker, delegate.createVariableDeclaration(declarations, 'var'));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // kind may be `const` or `let`
</span><span class="lines">@@ -2702,38 +3619,289 @@
</span><span class="cx"> // see http://wiki.ecmascript.org/doku.php?id=harmony:const
</span><span class="cx"> // and http://wiki.ecmascript.org/doku.php?id=harmony:let
</span><span class="cx"> function parseConstLetDeclaration(kind) {
</span><del>- var declarations, startToken;
</del><ins>+ var declarations, marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
-
</del><span class="cx"> expectKeyword(kind);
</span><span class="cx">
</span><span class="cx"> declarations = parseVariableDeclarationList(kind);
</span><span class="cx">
</span><span class="cx"> consumeSemicolon();
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken);
</del><ins>+ return markerApply(marker, delegate.createVariableDeclaration(declarations, kind));
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ // people.mozilla.org/~jorendorff/es6-draft.html
+
+ function parseModuleSpecifier() {
+ var marker = markerCreate(),
+ specifier;
+
+ if (lookahead.type !== Token.StringLiteral) {
+ throwError({}, Messages.InvalidModuleSpecifier);
+ }
+ specifier = delegate.createModuleSpecifier(lookahead);
+ lex();
+ return markerApply(marker, specifier);
+ }
+
+ function parseExportBatchSpecifier() {
+ var marker = markerCreate();
+ expect('*');
+ return markerApply(marker, delegate.createExportBatchSpecifier());
+ }
+
+ function parseExportSpecifier() {
+ var id, name = null, marker = markerCreate(), from;
+ if (matchKeyword('default')) {
+ lex();
+ id = markerApply(marker, delegate.createIdentifier('default'));
+ // export {default} from "something";
+ } else {
+ id = parseVariableIdentifier();
+ }
+ if (matchContextualKeyword('as')) {
+ lex();
+ name = parseNonComputedProperty();
+ }
+
+ return markerApply(marker, delegate.createExportSpecifier(id, name));
+ }
+
+ function parseExportDeclaration() {
+ var backtrackToken, id, declaration = null,
+ isExportFromIdentifier,
+ src = null, specifiers = [],
+ marker = markerCreate();
+
+ function rewind(token) {
+ index = token.range[0];
+ lineNumber = token.lineNumber;
+ lineStart = token.lineStart;
+ lookahead = token;
+ }
+
+ expectKeyword('export');
+
+ if (matchKeyword('default')) {
+ // covers:
+ // export default ...
+ lex();
+ if (matchKeyword('function') || matchKeyword('class')) {
+ backtrackToken = lookahead;
+ lex();
+ if (isIdentifierName(lookahead)) {
+ // covers:
+ // export default function foo () {}
+ // export default class foo {}
+ id = parseNonComputedProperty();
+ rewind(backtrackToken);
+ return markerApply(marker, delegate.createExportDeclaration(true, parseSourceElement(), [id], null));
+ }
+ // covers:
+ // export default function () {}
+ // export default class {}
+ rewind(backtrackToken);
+ switch (lookahead.value) {
+ case 'class':
+ return markerApply(marker, delegate.createExportDeclaration(true, parseClassExpression(), [], null));
+ case 'function':
+ return markerApply(marker, delegate.createExportDeclaration(true, parseFunctionExpression(), [], null));
+ }
+ }
+
+ if (matchContextualKeyword('from')) {
+ throwError({}, Messages.UnexpectedToken, lookahead.value);
+ }
+
+ // covers:
+ // export default {};
+ // export default [];
+ if (match('{')) {
+ declaration = parseObjectInitialiser();
+ } else if (match('[')) {
+ declaration = parseArrayInitialiser();
+ } else {
+ declaration = parseAssignmentExpression();
+ }
+ consumeSemicolon();
+ return markerApply(marker, delegate.createExportDeclaration(true, declaration, [], null));
+ }
+
+ // non-default export
+ if (lookahead.type === Token.Keyword) {
+ // covers:
+ // export var f = 1;
+ switch (lookahead.value) {
+ case 'let':
+ case 'const':
+ case 'var':
+ case 'class':
+ case 'function':
+ return markerApply(marker, delegate.createExportDeclaration(false, parseSourceElement(), specifiers, null));
+ }
+ }
+
+ if (match('*')) {
+ // covers:
+ // export * from "foo";
+ specifiers.push(parseExportBatchSpecifier());
+
+ if (!matchContextualKeyword('from')) {
+ throwError({}, lookahead.value ?
+ Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
+ }
+ lex();
+ src = parseModuleSpecifier();
+ consumeSemicolon();
+
+ return markerApply(marker, delegate.createExportDeclaration(false, null, specifiers, src));
+ }
+
+ expect('{');
+ if (!match('}')) {
+ do {
+ isExportFromIdentifier = isExportFromIdentifier || matchKeyword('default');
+ specifiers.push(parseExportSpecifier());
+ } while (match(',') && lex());
+ }
+ expect('}');
+
+ if (matchContextualKeyword('from')) {
+ // covering:
+ // export {default} from "foo";
+ // export {foo} from "foo";
+ lex();
+ src = parseModuleSpecifier();
+ consumeSemicolon();
+ } else if (isExportFromIdentifier) {
+ // covering:
+ // export {default}; // missing fromClause
+ throwError({}, lookahead.value ?
+ Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
+ } else {
+ // cover
+ // export {foo};
+ consumeSemicolon();
+ }
+ return markerApply(marker, delegate.createExportDeclaration(false, declaration, specifiers, src));
+ }
+
+
+ function parseImportSpecifier() {
+ // import {<foo as bar>} ...;
+ var id, name = null, marker = markerCreate();
+
+ id = parseNonComputedProperty();
+ if (matchContextualKeyword('as')) {
+ lex();
+ name = parseVariableIdentifier();
+ }
+
+ return markerApply(marker, delegate.createImportSpecifier(id, name));
+ }
+
+ function parseNamedImports() {
+ var specifiers = [];
+ // {foo, bar as bas}
+ expect('{');
+ if (!match('}')) {
+ do {
+ specifiers.push(parseImportSpecifier());
+ } while (match(',') && lex());
+ }
+ expect('}');
+ return specifiers;
+ }
+
+ function parseImportDefaultSpecifier() {
+ // import <foo> ...;
+ var id, marker = markerCreate();
+
+ id = parseNonComputedProperty();
+
+ return markerApply(marker, delegate.createImportDefaultSpecifier(id));
+ }
+
+ function parseImportNamespaceSpecifier() {
+ // import <* as foo> ...;
+ var id, marker = markerCreate();
+
+ expect('*');
+ if (!matchContextualKeyword('as')) {
+ throwError({}, Messages.NoAsAfterImportNamespace);
+ }
+ lex();
+ id = parseNonComputedProperty();
+
+ return markerApply(marker, delegate.createImportNamespaceSpecifier(id));
+ }
+
+ function parseImportDeclaration() {
+ var specifiers, src, marker = markerCreate();
+
+ expectKeyword('import');
+ specifiers = [];
+
+ if (lookahead.type === Token.StringLiteral) {
+ // covers:
+ // import "foo";
+ src = parseModuleSpecifier();
+ consumeSemicolon();
+ return markerApply(marker, delegate.createImportDeclaration(specifiers, src));
+ }
+
+ if (!matchKeyword('default') && isIdentifierName(lookahead)) {
+ // covers:
+ // import foo
+ // import foo, ...
+ specifiers.push(parseImportDefaultSpecifier());
+ if (match(',')) {
+ lex();
+ }
+ }
+ if (match('*')) {
+ // covers:
+ // import foo, * as foo
+ // import * as foo
+ specifiers.push(parseImportNamespaceSpecifier());
+ } else if (match('{')) {
+ // covers:
+ // import foo, {bar}
+ // import {bar}
+ specifiers = specifiers.concat(parseNamedImports());
+ }
+
+ if (!matchContextualKeyword('from')) {
+ throwError({}, lookahead.value ?
+ Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
+ }
+ lex();
+ src = parseModuleSpecifier();
+ consumeSemicolon();
+
+ return markerApply(marker, delegate.createImportDeclaration(specifiers, src));
+ }
+
</ins><span class="cx"> // 12.3 Empty Statement
</span><span class="cx">
</span><span class="cx"> function parseEmptyStatement() {
</span><ins>+ var marker = markerCreate();
</ins><span class="cx"> expect(';');
</span><del>- return delegate.createEmptyStatement();
</del><ins>+ return markerApply(marker, delegate.createEmptyStatement());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.4 Expression Statement
</span><span class="cx">
</span><span class="cx"> function parseExpressionStatement() {
</span><del>- var expr = parseExpression();
</del><ins>+ var marker = markerCreate(), expr = parseExpression();
</ins><span class="cx"> consumeSemicolon();
</span><del>- return delegate.createExpressionStatement(expr);
</del><ins>+ return markerApply(marker, delegate.createExpressionStatement(expr));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.5 If statement
</span><span class="cx">
</span><span class="cx"> function parseIfStatement() {
</span><del>- var test, consequent, alternate;
</del><ins>+ var test, consequent, alternate, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('if');
</span><span class="cx">
</span><span class="lines">@@ -2752,13 +3920,13 @@
</span><span class="cx"> alternate = null;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createIfStatement(test, consequent, alternate);
</del><ins>+ return markerApply(marker, delegate.createIfStatement(test, consequent, alternate));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.6 Iteration Statements
</span><span class="cx">
</span><span class="cx"> function parseDoWhileStatement() {
</span><del>- var body, test, oldInIteration;
</del><ins>+ var body, test, oldInIteration, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('do');
</span><span class="cx">
</span><span class="lines">@@ -2781,11 +3949,11 @@
</span><span class="cx"> lex();
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createDoWhileStatement(body, test);
</del><ins>+ return markerApply(marker, delegate.createDoWhileStatement(body, test));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseWhileStatement() {
</span><del>- var test, body, oldInIteration;
</del><ins>+ var test, body, oldInIteration, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('while');
</span><span class="cx">
</span><span class="lines">@@ -2802,54 +3970,65 @@
</span><span class="cx">
</span><span class="cx"> state.inIteration = oldInIteration;
</span><span class="cx">
</span><del>- return delegate.createWhileStatement(test, body);
</del><ins>+ return markerApply(marker, delegate.createWhileStatement(test, body));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseForVariableDeclaration() {
</span><del>- var token, declarations, startToken;
</del><ins>+ var marker = markerCreate(),
+ token = lex(),
+ declarations = parseVariableDeclarationList();
</ins><span class="cx">
</span><del>- startToken = lookahead;
- token = lex();
- declarations = parseVariableDeclarationList();
-
- return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken);
</del><ins>+ return markerApply(marker, delegate.createVariableDeclaration(declarations, token.value));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- function parseForStatement() {
- var init, test, update, left, right, body, oldInIteration;
-
</del><ins>+ function parseForStatement(opts) {
+ var init, test, update, left, right, body, operator, oldInIteration,
+ marker = markerCreate();
</ins><span class="cx"> init = test = update = null;
</span><del>-
</del><span class="cx"> expectKeyword('for');
</span><span class="cx">
</span><ins>+ // http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators&s=each
+ if (matchContextualKeyword('each')) {
+ throwError({}, Messages.EachNotAllowed);
+ }
+
</ins><span class="cx"> expect('(');
</span><span class="cx">
</span><span class="cx"> if (match(';')) {
</span><span class="cx"> lex();
</span><span class="cx"> } else {
</span><del>- if (matchKeyword('var') || matchKeyword('let')) {
</del><ins>+ if (matchKeyword('var') || matchKeyword('let') || matchKeyword('const')) {
</ins><span class="cx"> state.allowIn = false;
</span><span class="cx"> init = parseForVariableDeclaration();
</span><span class="cx"> state.allowIn = true;
</span><span class="cx">
</span><del>- if (init.declarations.length === 1 && matchKeyword('in')) {
- lex();
- left = init;
- right = parseExpression();
- init = null;
</del><ins>+ if (init.declarations.length === 1) {
+ if (matchKeyword('in') || matchContextualKeyword('of')) {
+ operator = lookahead;
+ if (!((operator.value === 'in' || init.kind !== 'var') && init.declarations[0].init)) {
+ lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ }
+ }
</ins><span class="cx"> }
</span><span class="cx"> } else {
</span><span class="cx"> state.allowIn = false;
</span><span class="cx"> init = parseExpression();
</span><span class="cx"> state.allowIn = true;
</span><span class="cx">
</span><del>- if (matchKeyword('in')) {
</del><ins>+ if (matchContextualKeyword('of')) {
+ operator = lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ } else if (matchKeyword('in')) {
</ins><span class="cx"> // LeftHandSideExpression
</span><del>- if (!isLeftHandSide(init)) {
- throwErrorTolerant({}, Messages.InvalidLHSInForIn);
</del><ins>+ if (!isAssignableLeftHandSide(init)) {
+ throwError({}, Messages.InvalidLHSInForIn);
</ins><span class="cx"> }
</span><del>-
- lex();
</del><ins>+ operator = lex();
</ins><span class="cx"> left = init;
</span><span class="cx"> right = parseExpression();
</span><span class="cx"> init = null;
</span><span class="lines">@@ -2878,31 +4057,38 @@
</span><span class="cx"> oldInIteration = state.inIteration;
</span><span class="cx"> state.inIteration = true;
</span><span class="cx">
</span><del>- body = parseStatement();
</del><ins>+ if (!(opts !== undefined && opts.ignoreBody)) {
+ body = parseStatement();
+ }
</ins><span class="cx">
</span><span class="cx"> state.inIteration = oldInIteration;
</span><span class="cx">
</span><del>- return (typeof left === 'undefined') ?
- delegate.createForStatement(init, test, update, body) :
- delegate.createForInStatement(left, right, body);
</del><ins>+ if (typeof left === 'undefined') {
+ return markerApply(marker, delegate.createForStatement(init, test, update, body));
+ }
+
+ if (operator.value === 'in') {
+ return markerApply(marker, delegate.createForInStatement(left, right, body));
+ }
+ return markerApply(marker, delegate.createForOfStatement(left, right, body));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.7 The continue statement
</span><span class="cx">
</span><span class="cx"> function parseContinueStatement() {
</span><del>- var label = null, key;
</del><ins>+ var label = null, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('continue');
</span><span class="cx">
</span><span class="cx"> // Optimize the most common form: 'continue;'.
</span><del>- if (source.charCodeAt(index) === 0x3B) {
</del><ins>+ if (source.charCodeAt(index) === 59) {
</ins><span class="cx"> lex();
</span><span class="cx">
</span><span class="cx"> if (!state.inIteration) {
</span><span class="cx"> throwError({}, Messages.IllegalContinue);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createContinueStatement(null);
</del><ins>+ return markerApply(marker, delegate.createContinueStatement(null));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (peekLineTerminator()) {
</span><span class="lines">@@ -2910,14 +4096,13 @@
</span><span class="cx"> throwError({}, Messages.IllegalContinue);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createContinueStatement(null);
</del><ins>+ return markerApply(marker, delegate.createContinueStatement(null));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (lookahead.type === Token.Identifier) {
</span><span class="cx"> label = parseVariableIdentifier();
</span><span class="cx">
</span><del>- key = '$' + label.name;
- if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
</del><ins>+ if (!state.labelSet.has(label.name)) {
</ins><span class="cx"> throwError({}, Messages.UnknownLabel, label.name);
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -2928,25 +4113,25 @@
</span><span class="cx"> throwError({}, Messages.IllegalContinue);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createContinueStatement(label);
</del><ins>+ return markerApply(marker, delegate.createContinueStatement(label));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.8 The break statement
</span><span class="cx">
</span><span class="cx"> function parseBreakStatement() {
</span><del>- var label = null, key;
</del><ins>+ var label = null, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('break');
</span><span class="cx">
</span><del>- // Catch the very common case first: immediately a semicolon (U+003B).
- if (source.charCodeAt(index) === 0x3B) {
</del><ins>+ // Catch the very common case first: immediately a semicolon (char #59).
+ if (source.charCodeAt(index) === 59) {
</ins><span class="cx"> lex();
</span><span class="cx">
</span><span class="cx"> if (!(state.inIteration || state.inSwitch)) {
</span><span class="cx"> throwError({}, Messages.IllegalBreak);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createBreakStatement(null);
</del><ins>+ return markerApply(marker, delegate.createBreakStatement(null));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (peekLineTerminator()) {
</span><span class="lines">@@ -2954,14 +4139,13 @@
</span><span class="cx"> throwError({}, Messages.IllegalBreak);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createBreakStatement(null);
</del><ins>+ return markerApply(marker, delegate.createBreakStatement(null));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (lookahead.type === Token.Identifier) {
</span><span class="cx"> label = parseVariableIdentifier();
</span><span class="cx">
</span><del>- key = '$' + label.name;
- if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
</del><ins>+ if (!state.labelSet.has(label.name)) {
</ins><span class="cx"> throwError({}, Messages.UnknownLabel, label.name);
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -2972,13 +4156,13 @@
</span><span class="cx"> throwError({}, Messages.IllegalBreak);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createBreakStatement(label);
</del><ins>+ return markerApply(marker, delegate.createBreakStatement(label));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.9 The return statement
</span><span class="cx">
</span><span class="cx"> function parseReturnStatement() {
</span><del>- var argument = null;
</del><ins>+ var argument = null, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('return');
</span><span class="cx">
</span><span class="lines">@@ -2987,16 +4171,16 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 'return' followed by a space and an identifier is very common.
</span><del>- if (source.charCodeAt(index) === 0x20) {
</del><ins>+ if (source.charCodeAt(index) === 32) {
</ins><span class="cx"> if (isIdentifierStart(source.charCodeAt(index + 1))) {
</span><span class="cx"> argument = parseExpression();
</span><span class="cx"> consumeSemicolon();
</span><del>- return delegate.createReturnStatement(argument);
</del><ins>+ return markerApply(marker, delegate.createReturnStatement(argument));
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (peekLineTerminator()) {
</span><del>- return delegate.createReturnStatement(null);
</del><ins>+ return markerApply(marker, delegate.createReturnStatement(null));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (!match(';')) {
</span><span class="lines">@@ -3007,17 +4191,15 @@
</span><span class="cx">
</span><span class="cx"> consumeSemicolon();
</span><span class="cx">
</span><del>- return delegate.createReturnStatement(argument);
</del><ins>+ return markerApply(marker, delegate.createReturnStatement(argument));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.10 The with statement
</span><span class="cx">
</span><span class="cx"> function parseWithStatement() {
</span><del>- var object, body;
</del><ins>+ var object, body, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> if (strict) {
</span><del>- // TODO(ikarienator): Should we update the test cases instead?
- skipComment();
</del><span class="cx"> throwErrorTolerant({}, Messages.StrictModeWith);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -3031,15 +4213,17 @@
</span><span class="cx">
</span><span class="cx"> body = parseStatement();
</span><span class="cx">
</span><del>- return delegate.createWithStatement(object, body);
</del><ins>+ return markerApply(marker, delegate.createWithStatement(object, body));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.10 The swith statement
</span><span class="cx">
</span><span class="cx"> function parseSwitchCase() {
</span><del>- var test, consequent = [], statement, startToken;
</del><ins>+ var test,
+ consequent = [],
+ sourceElement,
+ marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
</del><span class="cx"> if (matchKeyword('default')) {
</span><span class="cx"> lex();
</span><span class="cx"> test = null;
</span><span class="lines">@@ -3053,15 +4237,18 @@
</span><span class="cx"> if (match('}') || matchKeyword('default') || matchKeyword('case')) {
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- statement = parseStatement();
- consequent.push(statement);
</del><ins>+ sourceElement = parseSourceElement();
+ if (typeof sourceElement === 'undefined') {
+ break;
+ }
+ consequent.push(sourceElement);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken);
</del><ins>+ return markerApply(marker, delegate.createSwitchCase(test, consequent));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseSwitchStatement() {
</span><del>- var discriminant, cases, clause, oldInSwitch, defaultFound;
</del><ins>+ var discriminant, cases, clause, oldInSwitch, defaultFound, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('switch');
</span><span class="cx">
</span><span class="lines">@@ -3077,7 +4264,7 @@
</span><span class="cx">
</span><span class="cx"> if (match('}')) {
</span><span class="cx"> lex();
</span><del>- return delegate.createSwitchStatement(discriminant, cases);
</del><ins>+ return markerApply(marker, delegate.createSwitchStatement(discriminant, cases));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> oldInSwitch = state.inSwitch;
</span><span class="lines">@@ -3102,13 +4289,13 @@
</span><span class="cx">
</span><span class="cx"> expect('}');
</span><span class="cx">
</span><del>- return delegate.createSwitchStatement(discriminant, cases);
</del><ins>+ return markerApply(marker, delegate.createSwitchStatement(discriminant, cases));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.13 The throw statement
</span><span class="cx">
</span><span class="cx"> function parseThrowStatement() {
</span><del>- var argument;
</del><ins>+ var argument, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('throw');
</span><span class="cx">
</span><span class="lines">@@ -3120,15 +4307,14 @@
</span><span class="cx">
</span><span class="cx"> consumeSemicolon();
</span><span class="cx">
</span><del>- return delegate.createThrowStatement(argument);
</del><ins>+ return markerApply(marker, delegate.createThrowStatement(argument));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.14 The try statement
</span><span class="cx">
</span><span class="cx"> function parseCatchClause() {
</span><del>- var param, body, startToken;
</del><ins>+ var param, body, marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
</del><span class="cx"> expectKeyword('catch');
</span><span class="cx">
</span><span class="cx"> expect('(');
</span><span class="lines">@@ -3136,19 +4322,19 @@
</span><span class="cx"> throwUnexpected(lookahead);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- param = parseVariableIdentifier();
</del><ins>+ param = parseExpression();
</ins><span class="cx"> // 12.14.1
</span><del>- if (strict && isRestrictedWord(param.name)) {
</del><ins>+ if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
</ins><span class="cx"> throwErrorTolerant({}, Messages.StrictCatchVariable);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> expect(')');
</span><span class="cx"> body = parseBlock();
</span><del>- return delegate.markEnd(delegate.createCatchClause(param, body), startToken);
</del><ins>+ return markerApply(marker, delegate.createCatchClause(param, body));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseTryStatement() {
</span><del>- var block, handlers = [], finalizer = null;
</del><ins>+ var block, handlers = [], finalizer = null, marker = markerCreate();
</ins><span class="cx">
</span><span class="cx"> expectKeyword('try');
</span><span class="cx">
</span><span class="lines">@@ -3167,44 +4353,40 @@
</span><span class="cx"> throwError({}, Messages.NoCatchOrFinally);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return delegate.createTryStatement(block, [], handlers, finalizer);
</del><ins>+ return markerApply(marker, delegate.createTryStatement(block, [], handlers, finalizer));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12.15 The debugger statement
</span><span class="cx">
</span><span class="cx"> function parseDebuggerStatement() {
</span><ins>+ var marker = markerCreate();
</ins><span class="cx"> expectKeyword('debugger');
</span><span class="cx">
</span><span class="cx"> consumeSemicolon();
</span><span class="cx">
</span><del>- return delegate.createDebuggerStatement();
</del><ins>+ return markerApply(marker, delegate.createDebuggerStatement());
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 12 Statements
</span><span class="cx">
</span><span class="cx"> function parseStatement() {
</span><span class="cx"> var type = lookahead.type,
</span><ins>+ marker,
</ins><span class="cx"> expr,
</span><del>- labeledBody,
- key,
- startToken;
</del><ins>+ labeledBody;
</ins><span class="cx">
</span><span class="cx"> if (type === Token.EOF) {
</span><span class="cx"> throwUnexpected(lookahead);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- if (type === Token.Punctuator && lookahead.value === '{') {
- return parseBlock();
- }
-
- startToken = lookahead;
-
</del><span class="cx"> if (type === Token.Punctuator) {
</span><span class="cx"> switch (lookahead.value) {
</span><span class="cx"> case ';':
</span><del>- return delegate.markEnd(parseEmptyStatement(), startToken);
</del><ins>+ return parseEmptyStatement();
+ case '{':
+ return parseBlock();
</ins><span class="cx"> case '(':
</span><del>- return delegate.markEnd(parseExpressionStatement(), startToken);
</del><ins>+ return parseExpressionStatement();
</ins><span class="cx"> default:
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -3213,67 +4395,76 @@
</span><span class="cx"> if (type === Token.Keyword) {
</span><span class="cx"> switch (lookahead.value) {
</span><span class="cx"> case 'break':
</span><del>- return delegate.markEnd(parseBreakStatement(), startToken);
</del><ins>+ return parseBreakStatement();
</ins><span class="cx"> case 'continue':
</span><del>- return delegate.markEnd(parseContinueStatement(), startToken);
</del><ins>+ return parseContinueStatement();
</ins><span class="cx"> case 'debugger':
</span><del>- return delegate.markEnd(parseDebuggerStatement(), startToken);
</del><ins>+ return parseDebuggerStatement();
</ins><span class="cx"> case 'do':
</span><del>- return delegate.markEnd(parseDoWhileStatement(), startToken);
</del><ins>+ return parseDoWhileStatement();
</ins><span class="cx"> case 'for':
</span><del>- return delegate.markEnd(parseForStatement(), startToken);
</del><ins>+ return parseForStatement();
</ins><span class="cx"> case 'function':
</span><del>- return delegate.markEnd(parseFunctionDeclaration(), startToken);
</del><ins>+ return parseFunctionDeclaration();
+ case 'class':
+ return parseClassDeclaration();
</ins><span class="cx"> case 'if':
</span><del>- return delegate.markEnd(parseIfStatement(), startToken);
</del><ins>+ return parseIfStatement();
</ins><span class="cx"> case 'return':
</span><del>- return delegate.markEnd(parseReturnStatement(), startToken);
</del><ins>+ return parseReturnStatement();
</ins><span class="cx"> case 'switch':
</span><del>- return delegate.markEnd(parseSwitchStatement(), startToken);
</del><ins>+ return parseSwitchStatement();
</ins><span class="cx"> case 'throw':
</span><del>- return delegate.markEnd(parseThrowStatement(), startToken);
</del><ins>+ return parseThrowStatement();
</ins><span class="cx"> case 'try':
</span><del>- return delegate.markEnd(parseTryStatement(), startToken);
</del><ins>+ return parseTryStatement();
</ins><span class="cx"> case 'var':
</span><del>- return delegate.markEnd(parseVariableStatement(), startToken);
</del><ins>+ return parseVariableStatement();
</ins><span class="cx"> case 'while':
</span><del>- return delegate.markEnd(parseWhileStatement(), startToken);
</del><ins>+ return parseWhileStatement();
</ins><span class="cx"> case 'with':
</span><del>- return delegate.markEnd(parseWithStatement(), startToken);
</del><ins>+ return parseWithStatement();
</ins><span class="cx"> default:
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ marker = markerCreate();
</ins><span class="cx"> expr = parseExpression();
</span><span class="cx">
</span><span class="cx"> // 12.12 Labelled Statements
</span><span class="cx"> if ((expr.type === Syntax.Identifier) && match(':')) {
</span><span class="cx"> lex();
</span><span class="cx">
</span><del>- key = '$' + expr.name;
- if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
</del><ins>+ if (state.labelSet.has(expr.name)) {
</ins><span class="cx"> throwError({}, Messages.Redeclaration, 'Label', expr.name);
</span><span class="cx"> }
</span><span class="cx">
</span><del>- state.labelSet[key] = true;
</del><ins>+ state.labelSet.set(expr.name, true);
</ins><span class="cx"> labeledBody = parseStatement();
</span><del>- delete state.labelSet[key];
- return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken);
</del><ins>+ state.labelSet.delete(expr.name);
+ return markerApply(marker, delegate.createLabeledStatement(expr, labeledBody));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> consumeSemicolon();
</span><span class="cx">
</span><del>- return delegate.markEnd(delegate.createExpressionStatement(expr), startToken);
</del><ins>+ return markerApply(marker, delegate.createExpressionStatement(expr));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // 13 Function Definition
</span><span class="cx">
</span><ins>+ function parseConciseBody() {
+ if (match('{')) {
+ return parseFunctionSourceElements();
+ }
+ return parseAssignmentExpression();
+ }
+
</ins><span class="cx"> function parseFunctionSourceElements() {
</span><span class="cx"> var sourceElement, sourceElements = [], token, directive, firstRestricted,
</span><del>- oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken;
</del><ins>+ oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesizedCount,
+ marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
</del><span class="cx"> expect('{');
</span><span class="cx">
</span><span class="cx"> while (index < length) {
</span><span class="lines">@@ -3288,7 +4479,7 @@
</span><span class="cx"> // this is not directive
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- directive = source.slice(token.start + 1, token.end - 1);
</del><ins>+ directive = source.slice(token.range[0] + 1, token.range[1] - 1);
</ins><span class="cx"> if (directive === 'use strict') {
</span><span class="cx"> strict = true;
</span><span class="cx"> if (firstRestricted) {
</span><span class="lines">@@ -3305,11 +4496,13 @@
</span><span class="cx"> oldInIteration = state.inIteration;
</span><span class="cx"> oldInSwitch = state.inSwitch;
</span><span class="cx"> oldInFunctionBody = state.inFunctionBody;
</span><ins>+ oldParenthesizedCount = state.parenthesizedCount;
</ins><span class="cx">
</span><del>- state.labelSet = {};
</del><ins>+ state.labelSet = new StringMap();
</ins><span class="cx"> state.inIteration = false;
</span><span class="cx"> state.inSwitch = false;
</span><span class="cx"> state.inFunctionBody = true;
</span><ins>+ state.parenthesizedCount = 0;
</ins><span class="cx">
</span><span class="cx"> while (index < length) {
</span><span class="cx"> if (match('}')) {
</span><span class="lines">@@ -3328,44 +4521,98 @@
</span><span class="cx"> state.inIteration = oldInIteration;
</span><span class="cx"> state.inSwitch = oldInSwitch;
</span><span class="cx"> state.inFunctionBody = oldInFunctionBody;
</span><ins>+ state.parenthesizedCount = oldParenthesizedCount;
</ins><span class="cx">
</span><del>- return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken);
</del><ins>+ return markerApply(marker, delegate.createBlockStatement(sourceElements));
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ function validateParam(options, param, name) {
+ if (strict) {
+ if (isRestrictedWord(name)) {
+ options.stricted = param;
+ options.message = Messages.StrictParamName;
+ }
+ if (options.paramSet.has(name)) {
+ options.stricted = param;
+ options.message = Messages.StrictParamDupe;
+ }
+ } else if (!options.firstRestricted) {
+ if (isRestrictedWord(name)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictParamName;
+ } else if (isStrictModeReservedWord(name)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictReservedWord;
+ } else if (options.paramSet.has(name)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictParamDupe;
+ }
+ }
+ options.paramSet.set(name, true);
+ }
+
+ function parseParam(options) {
+ var token, rest, param, def;
+
+ token = lookahead;
+ if (token.value === '...') {
+ token = lex();
+ rest = true;
+ }
+
+ if (match('[')) {
+ param = parseArrayInitialiser();
+ reinterpretAsDestructuredParameter(options, param);
+ } else if (match('{')) {
+ if (rest) {
+ throwError({}, Messages.ObjectPatternAsRestParameter);
+ }
+ param = parseObjectInitialiser();
+ reinterpretAsDestructuredParameter(options, param);
+ } else {
+ param = parseVariableIdentifier();
+ validateParam(options, token, token.value);
+ }
+
+ if (match('=')) {
+ if (rest) {
+ throwErrorTolerant(lookahead, Messages.DefaultRestParameter);
+ }
+ lex();
+ def = parseAssignmentExpression();
+ ++options.defaultCount;
+ }
+
+ if (rest) {
+ if (!match(')')) {
+ throwError({}, Messages.ParameterAfterRestParameter);
+ }
+ options.rest = param;
+ return false;
+ }
+
+ options.params.push(param);
+ options.defaults.push(def);
+ return !match(')');
+ }
+
</ins><span class="cx"> function parseParams(firstRestricted) {
</span><del>- var param, params = [], token, stricted, paramSet, key, message;
</del><ins>+ var options, marker = markerCreate();
+
+ options = {
+ params: [],
+ defaultCount: 0,
+ defaults: [],
+ rest: null,
+ firstRestricted: firstRestricted
+ };
+
</ins><span class="cx"> expect('(');
</span><span class="cx">
</span><span class="cx"> if (!match(')')) {
</span><del>- paramSet = {};
</del><ins>+ options.paramSet = new StringMap();
</ins><span class="cx"> while (index < length) {
</span><del>- token = lookahead;
- param = parseVariableIdentifier();
- key = '$' + token.value;
- if (strict) {
- if (isRestrictedWord(token.value)) {
- stricted = token;
- message = Messages.StrictParamName;
- }
- if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
- stricted = token;
- message = Messages.StrictParamDupe;
- }
- } else if (!firstRestricted) {
- if (isRestrictedWord(token.value)) {
- firstRestricted = token;
- message = Messages.StrictParamName;
- } else if (isStrictModeReservedWord(token.value)) {
- firstRestricted = token;
- message = Messages.StrictReservedWord;
- } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
- firstRestricted = token;
- message = Messages.StrictParamDupe;
- }
- }
- params.push(param);
- paramSet[key] = true;
- if (match(')')) {
</del><ins>+ if (!parseParam(options)) {
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> expect(',');
</span><span class="lines">@@ -3374,22 +4621,29 @@
</span><span class="cx">
</span><span class="cx"> expect(')');
</span><span class="cx">
</span><del>- return {
- params: params,
- stricted: stricted,
- firstRestricted: firstRestricted,
- message: message
- };
</del><ins>+ if (options.defaultCount === 0) {
+ options.defaults = [];
+ }
+
+ return markerApply(marker, options);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseFunctionDeclaration() {
</span><del>- var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken;
</del><ins>+ var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator,
+ marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
</del><ins>+ expectKeyword('function');
</ins><span class="cx">
</span><del>- expectKeyword('function');
</del><ins>+ generator = false;
+ if (match('*')) {
+ lex();
+ generator = true;
+ }
+
</ins><span class="cx"> token = lookahead;
</span><ins>+
</ins><span class="cx"> id = parseVariableIdentifier();
</span><ins>+
</ins><span class="cx"> if (strict) {
</span><span class="cx"> if (isRestrictedWord(token.value)) {
</span><span class="cx"> throwErrorTolerant(token, Messages.StrictFunctionName);
</span><span class="lines">@@ -3405,32 +4659,42 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> tmp = parseParams(firstRestricted);
</span><del>- params = tmp.params;
- stricted = tmp.stricted;
</del><span class="cx"> firstRestricted = tmp.firstRestricted;
</span><span class="cx"> if (tmp.message) {
</span><span class="cx"> message = tmp.message;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> previousStrict = strict;
</span><ins>+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = generator;
+
</ins><span class="cx"> body = parseFunctionSourceElements();
</span><ins>+
</ins><span class="cx"> if (strict && firstRestricted) {
</span><span class="cx"> throwError(firstRestricted, message);
</span><span class="cx"> }
</span><del>- if (strict && stricted) {
- throwErrorTolerant(stricted, message);
</del><ins>+ if (strict && tmp.stricted) {
+ throwErrorTolerant(tmp.stricted, message);
</ins><span class="cx"> }
</span><span class="cx"> strict = previousStrict;
</span><ins>+ state.yieldAllowed = previousYieldAllowed;
</ins><span class="cx">
</span><del>- return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken);
</del><ins>+ return markerApply(marker, delegate.createFunctionDeclaration(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseFunctionExpression() {
</span><del>- var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken;
</del><ins>+ var token, id = null, firstRestricted, message, tmp, body, previousStrict, previousYieldAllowed, generator,
+ marker = markerCreate();
</ins><span class="cx">
</span><del>- startToken = lookahead;
</del><span class="cx"> expectKeyword('function');
</span><span class="cx">
</span><ins>+ generator = false;
+
+ if (match('*')) {
+ lex();
+ generator = true;
+ }
+
</ins><span class="cx"> if (!match('(')) {
</span><span class="cx"> token = lookahead;
</span><span class="cx"> id = parseVariableIdentifier();
</span><span class="lines">@@ -3450,28 +4714,223 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> tmp = parseParams(firstRestricted);
</span><del>- params = tmp.params;
- stricted = tmp.stricted;
</del><span class="cx"> firstRestricted = tmp.firstRestricted;
</span><span class="cx"> if (tmp.message) {
</span><span class="cx"> message = tmp.message;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> previousStrict = strict;
</span><ins>+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = generator;
+
</ins><span class="cx"> body = parseFunctionSourceElements();
</span><ins>+
</ins><span class="cx"> if (strict && firstRestricted) {
</span><span class="cx"> throwError(firstRestricted, message);
</span><span class="cx"> }
</span><del>- if (strict && stricted) {
- throwErrorTolerant(stricted, message);
</del><ins>+ if (strict && tmp.stricted) {
+ throwErrorTolerant(tmp.stricted, message);
</ins><span class="cx"> }
</span><span class="cx"> strict = previousStrict;
</span><ins>+ state.yieldAllowed = previousYieldAllowed;
</ins><span class="cx">
</span><del>- return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken);
</del><ins>+ return markerApply(marker, delegate.createFunctionExpression(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false));
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- // 14 Program
</del><ins>+ function parseYieldExpression() {
+ var yieldToken, delegateFlag, expr, marker = markerCreate();
</ins><span class="cx">
</span><ins>+ yieldToken = lex();
+ assert(yieldToken.value === 'yield', 'Called parseYieldExpression with non-yield lookahead.');
+
+ if (!state.yieldAllowed) {
+ throwErrorTolerant({}, Messages.IllegalYield);
+ }
+
+ delegateFlag = false;
+ if (match('*')) {
+ lex();
+ delegateFlag = true;
+ }
+
+ expr = parseAssignmentExpression();
+
+ return markerApply(marker, delegate.createYieldExpression(expr, delegateFlag));
+ }
+
+ // 14 Functions and classes
+
+ // 14.1 Functions is defined above (13 in ES5)
+ // 14.2 Arrow Functions Definitions is defined in (7.3 assignments)
+
+ // 14.3 Method Definitions
+ // 14.3.7
+ function specialMethod(methodDefinition) {
+ return methodDefinition.kind === 'get' ||
+ methodDefinition.kind === 'set' ||
+ methodDefinition.value.generator;
+ }
+
+ function parseMethodDefinition() {
+ var token, key, param, propType, computed,
+ marker = markerCreate();
+
+ if (lookahead.value === 'static') {
+ propType = ClassPropertyType.static;
+ lex();
+ } else {
+ propType = ClassPropertyType.prototype;
+ }
+
+ if (match('*')) {
+ lex();
+ computed = (lookahead.value === '[');
+ return markerApply(marker, delegate.createMethodDefinition(
+ propType,
+ '',
+ parseObjectPropertyKey(),
+ parsePropertyMethodFunction({ generator: true }),
+ computed
+ ));
+ }
+
+ token = lookahead;
+ key = parseObjectPropertyKey();
+
+ if (token.value === 'get' && !match('(')) {
+ computed = (lookahead.value === '[');
+ key = parseObjectPropertyKey();
+
+ expect('(');
+ expect(')');
+ return markerApply(marker, delegate.createMethodDefinition(
+ propType,
+ 'get',
+ key,
+ parsePropertyFunction({ generator: false }),
+ computed
+ ));
+ }
+ if (token.value === 'set' && !match('(')) {
+ computed = (lookahead.value === '[');
+ key = parseObjectPropertyKey();
+
+ expect('(');
+ token = lookahead;
+ param = [ parseVariableIdentifier() ];
+ expect(')');
+ return markerApply(marker, delegate.createMethodDefinition(
+ propType,
+ 'set',
+ key,
+ parsePropertyFunction({ params: param, generator: false, name: token }),
+ computed
+ ));
+ }
+
+ computed = (token.value === '[');
+
+ return markerApply(marker, delegate.createMethodDefinition(
+ propType,
+ '',
+ key,
+ parsePropertyMethodFunction({ generator: false }),
+ computed
+ ));
+ }
+
+ // 14.5 Class Definitions
+
+ function parseClassElement() {
+ if (match(';')) {
+ lex();
+ } else {
+ return parseMethodDefinition();
+ }
+ }
+
+ function parseClassBody() {
+ var classElement, classElements = [], existingProps = {},
+ marker = markerCreate(), propName, propType;
+
+ existingProps[ClassPropertyType.static] = new StringMap();
+ existingProps[ClassPropertyType.prototype] = new StringMap();
+
+ expect('{');
+
+ while (index < length) {
+ if (match('}')) {
+ break;
+ }
+ classElement = parseClassElement(existingProps);
+
+ if (typeof classElement !== 'undefined') {
+ classElements.push(classElement);
+
+ propName = !classElement.computed && getFieldName(classElement.key);
+ if (propName !== false) {
+ propType = classElement.static ?
+ ClassPropertyType.static :
+ ClassPropertyType.prototype;
+
+ if (propName === 'constructor' && !classElement.static) {
+ if (specialMethod(classElement)) {
+ throwError(classElement, Messages.IllegalClassConstructorProperty);
+ }
+ if (existingProps[ClassPropertyType.prototype].has('constructor')) {
+ throwError(classElement.key, Messages.IllegalDuplicateClassProperty);
+ }
+ }
+ existingProps[propType].set(propName, true);
+ }
+ }
+ }
+
+ expect('}');
+
+ return markerApply(marker, delegate.createClassBody(classElements));
+ }
+
+ function parseClassExpression() {
+ var id, previousYieldAllowed, superClass = null, marker = markerCreate();
+
+ expectKeyword('class');
+
+ if (!matchKeyword('extends') && !match('{')) {
+ id = parseVariableIdentifier();
+ }
+
+ if (matchKeyword('extends')) {
+ expectKeyword('extends');
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = false;
+ superClass = parseAssignmentExpression();
+ state.yieldAllowed = previousYieldAllowed;
+ }
+
+ return markerApply(marker, delegate.createClassExpression(id, superClass, parseClassBody()));
+ }
+
+ function parseClassDeclaration() {
+ var id, previousYieldAllowed, superClass = null, marker = markerCreate();
+
+ expectKeyword('class');
+
+ id = parseVariableIdentifier();
+
+ if (matchKeyword('extends')) {
+ expectKeyword('extends');
+ previousYieldAllowed = state.yieldAllowed;
+ state.yieldAllowed = false;
+ superClass = parseAssignmentExpression();
+ state.yieldAllowed = previousYieldAllowed;
+ }
+
+ return markerApply(marker, delegate.createClassDeclaration(id, superClass, parseClassBody()));
+ }
+
+ // 15 Program
+
</ins><span class="cx"> function parseSourceElement() {
</span><span class="cx"> if (lookahead.type === Token.Keyword) {
</span><span class="cx"> switch (lookahead.value) {
</span><span class="lines">@@ -3480,6 +4939,12 @@
</span><span class="cx"> return parseConstLetDeclaration(lookahead.value);
</span><span class="cx"> case 'function':
</span><span class="cx"> return parseFunctionDeclaration();
</span><ins>+ case 'export':
+ throwErrorTolerant({}, Messages.IllegalExportDeclaration);
+ return parseExportDeclaration();
+ case 'import':
+ throwErrorTolerant({}, Messages.IllegalImportDeclaration);
+ return parseImportDeclaration();
</ins><span class="cx"> default:
</span><span class="cx"> return parseStatement();
</span><span class="cx"> }
</span><span class="lines">@@ -3490,7 +4955,20 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- function parseSourceElements() {
</del><ins>+ function parseProgramElement() {
+ if (extra.isModule && lookahead.type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'export':
+ return parseExportDeclaration();
+ case 'import':
+ return parseImportDeclaration();
+ }
+ }
+
+ return parseSourceElement();
+ }
+
+ function parseProgramElements() {
</ins><span class="cx"> var sourceElement, sourceElements = [], token, directive, firstRestricted;
</span><span class="cx">
</span><span class="cx"> while (index < length) {
</span><span class="lines">@@ -3499,13 +4977,13 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- sourceElement = parseSourceElement();
</del><ins>+ sourceElement = parseProgramElement();
</ins><span class="cx"> sourceElements.push(sourceElement);
</span><span class="cx"> if (sourceElement.expression.type !== Syntax.Literal) {
</span><span class="cx"> // this is not directive
</span><span class="cx"> break;
</span><span class="cx"> }
</span><del>- directive = source.slice(token.start + 1, token.end - 1);
</del><ins>+ directive = source.slice(token.range[0] + 1, token.range[1] - 1);
</ins><span class="cx"> if (directive === 'use strict') {
</span><span class="cx"> strict = true;
</span><span class="cx"> if (firstRestricted) {
</span><span class="lines">@@ -3519,8 +4997,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> while (index < length) {
</span><del>- sourceElement = parseSourceElement();
- /* istanbul ignore if */
</del><ins>+ sourceElement = parseProgramElement();
</ins><span class="cx"> if (typeof sourceElement === 'undefined') {
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -3530,17 +5007,94 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> function parseProgram() {
</span><del>- var body, startToken;
</del><ins>+ var body, marker = markerCreate();
+ strict = !!extra.isModule;
+ peek();
+ body = parseProgramElements();
+ return markerApply(marker, delegate.createProgram(body));
+ }
</ins><span class="cx">
</span><ins>+ function collectToken() {
+ var loc, token, range, value, entry;
+
</ins><span class="cx"> skipComment();
</span><del>- peek();
- startToken = lookahead;
- strict = false;
</del><ins>+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
</ins><span class="cx">
</span><del>- body = parseSourceElements();
- return delegate.markEnd(delegate.createProgram(body), startToken);
</del><ins>+ token = extra.advance();
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+
+ if (token.type !== Token.EOF) {
+ range = [token.range[0], token.range[1]];
+ value = source.slice(token.range[0], token.range[1]);
+ entry = {
+ type: TokenName[token.type],
+ value: value,
+ range: range,
+ loc: loc
+ };
+ if (token.regex) {
+ entry.regex = {
+ pattern: token.regex.pattern,
+ flags: token.regex.flags
+ };
+ }
+ extra.tokens.push(entry);
+ }
+
+ return token;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ function collectRegex() {
+ var pos, loc, regex, token;
+
+ skipComment();
+
+ pos = index;
+ loc = {
+ start: {
+ line: lineNumber,
+ column: index - lineStart
+ }
+ };
+
+ regex = extra.scanRegExp();
+ loc.end = {
+ line: lineNumber,
+ column: index - lineStart
+ };
+
+ if (!extra.tokenize) {
+ /* istanbul ignore next */
+ // Pop the previous token, which is likely '/' or '/='
+ if (extra.tokens.length > 0) {
+ token = extra.tokens[extra.tokens.length - 1];
+ if (token.range[0] === pos && token.type === 'Punctuator') {
+ if (token.value === '/' || token.value === '/=') {
+ extra.tokens.pop();
+ }
+ }
+ }
+
+ extra.tokens.push({
+ type: 'RegularExpression',
+ value: regex.literal,
+ regex: regex.regex,
+ range: [pos, index],
+ loc: loc
+ });
+ }
+
+ return regex;
+ }
+
</ins><span class="cx"> function filterTokenLocation() {
</span><span class="cx"> var i, entry, token, tokens = [];
</span><span class="cx">
</span><span class="lines">@@ -3550,6 +5104,12 @@
</span><span class="cx"> type: entry.type,
</span><span class="cx"> value: entry.value
</span><span class="cx"> };
</span><ins>+ if (entry.regex) {
+ token.regex = {
+ pattern: entry.regex.pattern,
+ flags: entry.regex.flags
+ };
+ }
</ins><span class="cx"> if (extra.range) {
</span><span class="cx"> token.range = entry.range;
</span><span class="cx"> }
</span><span class="lines">@@ -3562,6 +5122,45 @@
</span><span class="cx"> extra.tokens = tokens;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ function patch() {
+ if (typeof extra.tokens !== 'undefined') {
+ extra.advance = advance;
+ extra.scanRegExp = scanRegExp;
+
+ advance = collectToken;
+ scanRegExp = collectRegex;
+ }
+ }
+
+ function unpatch() {
+ if (typeof extra.scanRegExp === 'function') {
+ advance = extra.advance;
+ scanRegExp = extra.scanRegExp;
+ }
+ }
+
+ // This is used to modify the delegate.
+
+ function extend(object, properties) {
+ var entry, result = {};
+
+ for (entry in object) {
+ /* istanbul ignore else */
+ if (object.hasOwnProperty(entry)) {
+ result[entry] = object[entry];
+ }
+ }
+
+ for (entry in properties) {
+ /* istanbul ignore else */
+ if (properties.hasOwnProperty(entry)) {
+ result[entry] = properties[entry];
+ }
+ }
+
+ return result;
+ }
+
</ins><span class="cx"> function tokenize(code, options) {
</span><span class="cx"> var toString,
</span><span class="cx"> token,
</span><span class="lines">@@ -3580,8 +5179,9 @@
</span><span class="cx"> length = source.length;
</span><span class="cx"> lookahead = null;
</span><span class="cx"> state = {
</span><ins>+ allowKeyword: true,
</ins><span class="cx"> allowIn: true,
</span><del>- labelSet: {},
</del><ins>+ labelSet: new StringMap(),
</ins><span class="cx"> inFunctionBody: false,
</span><span class="cx"> inIteration: false,
</span><span class="cx"> inSwitch: false,
</span><span class="lines">@@ -3611,6 +5211,8 @@
</span><span class="cx"> extra.errors = [];
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ patch();
+
</ins><span class="cx"> try {
</span><span class="cx"> peek();
</span><span class="cx"> if (lookahead.type === Token.EOF) {
</span><span class="lines">@@ -3645,6 +5247,7 @@
</span><span class="cx"> } catch (e) {
</span><span class="cx"> throw e;
</span><span class="cx"> } finally {
</span><ins>+ unpatch();
</ins><span class="cx"> extra = {};
</span><span class="cx"> }
</span><span class="cx"> return tokens;
</span><span class="lines">@@ -3666,12 +5269,15 @@
</span><span class="cx"> length = source.length;
</span><span class="cx"> lookahead = null;
</span><span class="cx"> state = {
</span><ins>+ allowKeyword: false,
</ins><span class="cx"> allowIn: true,
</span><del>- labelSet: {},
</del><ins>+ labelSet: new StringMap(),
+ parenthesizedCount: 0,
</ins><span class="cx"> inFunctionBody: false,
</span><span class="cx"> inIteration: false,
</span><span class="cx"> inSwitch: false,
</span><del>- lastCommentStart: -1
</del><ins>+ lastCommentStart: -1,
+ yieldAllowed: false
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> extra = {};
</span><span class="lines">@@ -3681,9 +5287,17 @@
</span><span class="cx"> extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
</span><span class="cx">
</span><span class="cx"> if (extra.loc && options.source !== null && options.source !== undefined) {
</span><del>- extra.source = toString(options.source);
</del><ins>+ delegate = extend(delegate, {
+ 'postProcess': function (node) {
+ node.loc.source = toString(options.source);
+ return node;
+ }
+ });
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ if (options.sourceType === 'module') {
+ extra.isModule = true;
+ }
</ins><span class="cx"> if (typeof options.tokens === 'boolean' && options.tokens) {
</span><span class="cx"> extra.tokens = [];
</span><span class="cx"> }
</span><span class="lines">@@ -3702,6 +5316,7 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ patch();
</ins><span class="cx"> try {
</span><span class="cx"> program = parseProgram();
</span><span class="cx"> if (typeof extra.comments !== 'undefined') {
</span><span class="lines">@@ -3717,6 +5332,7 @@
</span><span class="cx"> } catch (e) {
</span><span class="cx"> throw e;
</span><span class="cx"> } finally {
</span><ins>+ unpatch();
</ins><span class="cx"> extra = {};
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -3724,7 +5340,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Sync with *.json manifests.
</span><del>- exports.version = '1.2.2';
</del><ins>+ exports.version = '1.1.0-dev-harmony';
</ins><span class="cx">
</span><span class="cx"> exports.tokenize = tokenize;
</span><span class="cx">
</span><span class="lines">@@ -3753,4 +5369,3 @@
</span><span class="cx"> }());
</span><span class="cx">
</span><span class="cx"> }));
</span><del>-/* vim: set sw=4 ts=4 et tw=80 : */
</del></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsScriptSyntaxTreejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/ScriptSyntaxTree.js (180387 => 180388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/ScriptSyntaxTree.js        2015-02-20 06:31:55 UTC (rev 180387)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/ScriptSyntaxTree.js        2015-02-20 06:33:49 UTC (rev 180388)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -48,46 +48,49 @@
</span><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> WebInspector.ScriptSyntaxTree.NodeType = {
</span><del>- AssignmentExpression: "assignment-expression",
- ArrayExpression: "expression",
- BlockStatement: "block-statement",
- BinaryExpression: "binary-expression",
- BreakStatement: "break-statement",
- CallExpression: "call-expression",
- CatchClause: "catch-clause",
- ConditionalExpression: "conditional-expression",
- ContinueStatement: "continue-statement",
- DoWhileStatement: "do-while-statement",
- DebuggerStatement: "debugger-statement",
- EmptyStatement: "empty-statement",
- ExpressionStatement: "expression-statement",
- ForStatement: "for-statement",
- ForInStatement: "for-in-statement",
- FunctionDeclaration: "function-declaration",
- FunctionExpression: "function-expression",
- Identifier: "identifier",
- IfStatement: "if-statement",
- Literal: "literal",
- LabeledStatement: "labeled-statement",
- LogicalExpression: "logical-expression",
- MemberExpression: "member-expression",
- NewExpression: "new-expression",
- ObjectExpression: "objectExpression",
- Program: "program",
- Property: "property",
- ReturnStatement: "return-statement",
- SequenceExpression: "sequence-expression",
- SwitchStatement: "switch-statement",
- SwitchCase: "switch-case",
- ThisExpression: "this-expression",
- ThrowStatement: "throw-statement",
- TryStatement: "try-statement",
- UnaryExpression: "unary-expression",
- UpdateExpression: "update-expression",
- VariableDeclaration: "variable-declaration",
- VariableDeclarator: "variable-declarator",
- WhileStatement: "while-statement",
- WithStatement: "with-statement"
</del><ins>+ AssignmentExpression: Symbol("assignment-expression"),
+ ArrayExpression: Symbol("array-expression"),
+ ArrayPattern: Symbol("array-pattern"),
+ BlockStatement: Symbol("block-statement"),
+ BinaryExpression: Symbol("binary-expression"),
+ BreakStatement: Symbol("break-statement"),
+ CallExpression: Symbol("call-expression"),
+ CatchClause: Symbol("catch-clause"),
+ ConditionalExpression: Symbol("conditional-expression"),
+ ContinueStatement: Symbol("continue-statement"),
+ DoWhileStatement: Symbol("do-while-statement"),
+ DebuggerStatement: Symbol("debugger-statement"),
+ EmptyStatement: Symbol("empty-statement"),
+ ExpressionStatement: Symbol("expression-statement"),
+ ForStatement: Symbol("for-statement"),
+ ForInStatement: Symbol("for-in-statement"),
+ ForOfStatement: Symbol("for-of-statement"),
+ FunctionDeclaration: Symbol("function-declaration"),
+ FunctionExpression: Symbol("function-expression"),
+ Identifier: Symbol("identifier"),
+ IfStatement: Symbol("if-statement"),
+ Literal: Symbol("literal"),
+ LabeledStatement: Symbol("labeled-statement"),
+ LogicalExpression: Symbol("logical-expression"),
+ MemberExpression: Symbol("member-expression"),
+ NewExpression: Symbol("new-expression"),
+ ObjectExpression: Symbol("object-expression"),
+ ObjectPattern: Symbol("object-pattern"),
+ Program: Symbol("program"),
+ Property: Symbol("property"),
+ ReturnStatement: Symbol("return-statement"),
+ SequenceExpression: Symbol("sequence-expression"),
+ SwitchStatement: Symbol("switch-statement"),
+ SwitchCase: Symbol("switch-case"),
+ ThisExpression: Symbol("this-expression"),
+ ThrowStatement: Symbol("throw-statement"),
+ TryStatement: Symbol("try-statement"),
+ UnaryExpression: Symbol("unary-expression"),
+ UpdateExpression: Symbol("update-expression"),
+ VariableDeclaration: Symbol("variable-declaration"),
+ VariableDeclarator: Symbol("variable-declarator"),
+ WhileStatement: Symbol("while-statement"),
+ WithStatement: Symbol("with-statement")
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> WebInspector.ScriptSyntaxTree.prototype = {
</span><span class="lines">@@ -229,12 +232,14 @@
</span><span class="cx"> allRequestNodes.push(node);
</span><span class="cx"> break;
</span><span class="cx"> case WebInspector.ScriptSyntaxTree.NodeType.VariableDeclarator:
</span><del>- allRequests.push({
- typeInformationDescriptor: WebInspector.ScriptSyntaxTree.TypeProfilerSearchDescriptor.NormalExpression,
- sourceID: sourceID,
- divot: node.id.range[0]
- });
- allRequestNodes.push(node);
</del><ins>+ for (var identifier of this.gatherIdentifiersInVariableDeclaration(node)) {
+ allRequests.push({
+ typeInformationDescriptor: WebInspector.ScriptSyntaxTree.TypeProfilerSearchDescriptor.NormalExpression,
+ sourceID: sourceID,
+ divot: identifier.range[0]
+ });
+ allRequestNodes.push(identifier);
+ }
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -263,6 +268,38 @@
</span><span class="cx"> RuntimeAgent.getRuntimeTypesForVariablesAtOffsets(allRequests, handleTypes);
</span><span class="cx"> },
</span><span class="cx">
</span><ins>+ gatherIdentifiersInVariableDeclaration: function (node) {
+ function gatherIdentifiers(node)
+ {
+ switch (node.type) {
+ case WebInspector.ScriptSyntaxTree.NodeType.Identifier:
+ return [node];
+ case WebInspector.ScriptSyntaxTree.NodeType.Property:
+ return gatherIdentifiers(node.value);
+ case WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern:
+ var identifiers = [];
+ for (var property of node.properties) {
+ for (var identifier of gatherIdentifiers(property))
+ identifiers.push(identifier);
+ }
+ return identifiers;
+ case WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern:
+ var identifiers = [];
+ for (var element of node.elements) {
+ for (var identifier of gatherIdentifiers(element))
+ identifiers.push(identifier);
+ }
+ return identifiers;
+ default:
+ console.assert(false, "Unexecpted node type in variable declarator: " + node.type);
+ return [];
+ }
+ }
+
+ console.assert(node.type === WebInspector.ScriptSyntaxTree.NodeType.VariableDeclarator);
+ return gatherIdentifiers(node.id);
+ },
+
</ins><span class="cx"> // Private
</span><span class="cx">
</span><span class="cx"> _defaultParserState: function()
</span><span class="lines">@@ -288,6 +325,7 @@
</span><span class="cx"> this._recurse(node.right, callback, state);
</span><span class="cx"> break;
</span><span class="cx"> case WebInspector.ScriptSyntaxTree.NodeType.ArrayExpression:
</span><ins>+ case WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern:
</ins><span class="cx"> callback(node, state);
</span><span class="cx"> this._recurseArray(node.elements, callback, state);
</span><span class="cx"> break;
</span><span class="lines">@@ -341,6 +379,7 @@
</span><span class="cx"> this._recurse(node.body, callback, state);
</span><span class="cx"> break;
</span><span class="cx"> case WebInspector.ScriptSyntaxTree.NodeType.ForInStatement:
</span><ins>+ case WebInspector.ScriptSyntaxTree.NodeType.ForOfStatement:
</ins><span class="cx"> callback(node, state);
</span><span class="cx"> this._recurse(node.left, callback, state);
</span><span class="cx"> this._recurse(node.right, callback, state);
</span><span class="lines">@@ -391,6 +430,7 @@
</span><span class="cx"> this._recurseArray(node.arguments, callback, state);
</span><span class="cx"> break;
</span><span class="cx"> case WebInspector.ScriptSyntaxTree.NodeType.ObjectExpression:
</span><ins>+ case WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern:
</ins><span class="cx"> callback(node, state);
</span><span class="cx"> this._recurseArray(node.properties, callback, state);
</span><span class="cx"> break;
</span><span class="lines">@@ -504,6 +544,12 @@
</span><span class="cx"> elements: node.elements.map(this._createInternalSyntaxTree.bind(this))
</span><span class="cx"> };
</span><span class="cx"> break;
</span><ins>+ case "ArrayPattern":
+ result = {
+ type: WebInspector.ScriptSyntaxTree.NodeType.ArrayPattern,
+ elements: node.elements.map(this._createInternalSyntaxTree.bind(this))
+ };
+ break;
</ins><span class="cx"> case "BlockStatement":
</span><span class="cx"> result = {
</span><span class="cx"> type: WebInspector.ScriptSyntaxTree.NodeType.BlockStatement,
</span><span class="lines">@@ -592,6 +638,14 @@
</span><span class="cx"> body: this._createInternalSyntaxTree(node.body)
</span><span class="cx"> };
</span><span class="cx"> break;
</span><ins>+ case "ForOfStatement":
+ result = {
+ type: WebInspector.ScriptSyntaxTree.NodeType.ForOfStatement,
+ left: this._createInternalSyntaxTree(node.left),
+ right: this._createInternalSyntaxTree(node.right),
+ body: this._createInternalSyntaxTree(node.body)
+ };
+ break;
</ins><span class="cx"> case "FunctionDeclaration":
</span><span class="cx"> result = {
</span><span class="cx"> type: WebInspector.ScriptSyntaxTree.NodeType.FunctionDeclaration,
</span><span class="lines">@@ -667,6 +721,12 @@
</span><span class="cx"> properties: node.properties.map(this._createInternalSyntaxTree.bind(this))
</span><span class="cx"> };
</span><span class="cx"> break;
</span><ins>+ case "ObjectPattern":
+ result = {
+ type: WebInspector.ScriptSyntaxTree.NodeType.ObjectPattern,
+ properties: node.properties.map(this._createInternalSyntaxTree.bind(this))
+ };
+ break;
</ins><span class="cx"> case "Program":
</span><span class="cx"> result = {
</span><span class="cx"> type: WebInspector.ScriptSyntaxTree.NodeType.Program,
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTypeTokenViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/TypeTokenView.js (180387 => 180388)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TypeTokenView.js        2015-02-20 06:31:55 UTC (rev 180387)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TypeTokenView.js        2015-02-20 06:33:49 UTC (rev 180388)
</span><span class="lines">@@ -93,6 +93,9 @@
</span><span class="cx"> this._typeSet = WebInspector.TypeSet.fromPayload(this._types);
</span><span class="cx">
</span><span class="cx"> var title = this._displayTypeName();
</span><ins>+ if (title === this.element.textContent)
+ return;
+
</ins><span class="cx"> this.element.textContent = title;
</span><span class="cx"> var hashString = title[title.length - 1] === "?" ? title.slice(0, title.length - 1) : title;
</span><span class="cx">
</span></span></pre>
</div>
</div>
</body>
</html>