[Pkg-javascript-commits] [node-acorn-jsx] 405/484: Improve spread element parsing (fix allowed contexts and error locations).

Bastien Roucariès rouca at moszumanska.debian.org
Sat Aug 19 14:21:03 UTC 2017


This is an automated email from the git hooks/post-receive script.

rouca pushed a commit to branch master
in repository node-acorn-jsx.

commit caa5da6ce19794b5b93ec6881e2c3ced5675f829
Author: Ingvar Stepanyan <me at rreverser.com>
Date:   Wed Jan 21 23:51:40 2015 +0200

    Improve spread element parsing (fix allowed contexts and error locations).
---
 acorn.js              | 158 +++++++++++++++++++++++++++++++-------------------
 acorn_loose.js        |  16 +++--
 test/tests-harmony.js |  10 ++--
 3 files changed, 109 insertions(+), 75 deletions(-)

diff --git a/acorn.js b/acorn.js
index 58d0d41..10cac96 100644
--- a/acorn.js
+++ b/acorn.js
@@ -315,11 +315,6 @@
 
   var inFunction, inGenerator, labels, strict;
 
-  // This counter is used for checking that arrow expressions did
-  // not contain nested parentheses in argument list.
-
-  var metParenL;
-
   function initParserState() {
     lastStart = lastEnd = tokPos;
     if (options.locations) lastEndLoc = curPosition();
@@ -422,7 +417,7 @@
   var _comma = {type: ",", beforeExpr: true}, _semi = {type: ";", beforeExpr: true};
   var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _question = {type: "?", beforeExpr: true};
   var _arrow = {type: "=>", beforeExpr: true}, _template = {type: "template"};
-  var _ellipsis = {type: "...", prefix: true, beforeExpr: true};
+  var _ellipsis = {type: "...", beforeExpr: true};
   var _backQuote = {type: "`"}, _dollarBraceL = {type: "${", beforeExpr: true};
 
   // Operators. These carry several kinds of properties to help the
@@ -624,7 +619,6 @@
     tokType = _eof;
     tokContext = [];
     tokExprAllowed = true;
-    metParenL = 0;
     if (tokPos === 0 && options.allowHashBang && input.slice(0, 2) === '#!') {
       skipLineComment(2);
     }
@@ -1380,6 +1374,17 @@
     return node;
   }
 
+  // Finish node at given position
+
+  function finishNodeAt(node, type, pos) {
+    if (options.locations) { node.loc.end = pos[1]; pos = pos[0]; }
+    node.type = type;
+    node.end = pos;
+    if (options.ranges)
+      node.range[1] = pos;
+    return node;
+  }
+
   // Test whether a statement node is the string literal `"use strict"`.
 
   function isUseStrict(stmt) {
@@ -1440,6 +1445,9 @@
       switch (node.type) {
         case "Identifier":
         case "MemberExpression":
+        case "ObjectPattern":
+        case "ArrayPattern":
+        case "AssignmentPattern":
           break;
 
         case "ObjectExpression":
@@ -1482,6 +1490,21 @@
     return node;
   }
 
+  // Parses spread element.
+
+  function parseSpread(isBinding) {
+    var spread = startNode();
+    next();
+    if (isBinding) {
+      var arg = parseAssignableAtom();
+      checkSpreadAssign(arg);
+      spread.argument = arg;
+    } else {
+      spread.argument = parseMaybeAssign();
+    }
+    return finishNode(spread, "SpreadElement");
+  }
+
   // Parses lvalue (assignable) atom.
 
   function parseAssignableAtom() {
@@ -1497,11 +1520,7 @@
         while (!eat(_bracketR)) {
           first ? first = false : expect(_comma);
           if (tokType === _ellipsis) {
-            var spread = startNode();
-            next();
-            spread.argument = parseAssignableAtom();
-            checkSpreadAssign(spread.argument);
-            elts.push(finishNode(spread, "SpreadElement"));
+            elts.push(parseSpread(true));
             expect(_bracketR);
             break;
           }
@@ -2088,21 +2107,16 @@
 
   function parseMaybeUnary() {
     if (tokType.prefix) {
-      var node = startNode(), update = tokType.isUpdate, nodeType;
-      if (tokType === _ellipsis) {
-        nodeType = "SpreadElement";
-      } else {
-        nodeType = update ? "UpdateExpression" : "UnaryExpression";
-        node.operator = tokVal;
-        node.prefix = true;
-      }
+      var node = startNode(), update = tokType.isUpdate;
+      node.operator = tokVal;
+      node.prefix = true;
       next();
       node.argument = parseMaybeUnary();
       if (update) checkLVal(node.argument);
       else if (strict && node.operator === "delete" &&
                node.argument.type === "Identifier")
         raise(node.start, "Deleting local variable in strict mode");
-      return finishNode(node, nodeType);
+      return finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
     }
     var start = storeCurrentPos();
     var expr = parseExprSubscripts();
@@ -2198,42 +2212,7 @@
       return finishNode(node, "Literal");
 
     case _parenL:
-      var start = storeCurrentPos();
-      var val, exprList;
-      next();
-      // check whether this is generator comprehension or regular expression
-      if (options.ecmaVersion >= 7 && tokType === _for) {
-        val = parseComprehension(startNodeAt(start), true);
-      } else {
-        var oldParenL = ++metParenL;
-        if (tokType !== _parenR) {
-          val = parseExpression();
-          exprList = val.type === "SequenceExpression" ? val.expressions : [val];
-        } else {
-          exprList = [];
-        }
-        expect(_parenR);
-        // if '=>' follows '(...)', convert contents to arguments
-        if (metParenL === oldParenL && eat(_arrow)) {
-          val = parseArrowExpression(startNodeAt(start), exprList);
-        } else {
-          // forbid '()' before everything but '=>'
-          if (!val) unexpected(lastStart);
-          // forbid '...' in sequence expressions
-          if (options.ecmaVersion >= 6) {
-            for (var i = 0; i < exprList.length; i++) {
-              if (exprList[i].type === "SpreadElement") unexpected();
-            }
-          }
-
-          if (options.preserveParens) {
-            var par = startNodeAt(start);
-            par.expression = val;
-            val = finishNode(par, "ParenthesizedExpression");
-          }
-        }
-      }
-      return val;
+      return parseParenAndDistinguishExpression();
 
     case _bracketL:
       var node = startNode();
@@ -2267,6 +2246,60 @@
     }
   }
 
+  function parseParenAndDistinguishExpression() {
+    var start = storeCurrentPos(), val;
+    if (options.ecmaVersion >= 6) {
+      next();
+
+      if (options.ecmaVersion >= 7 && tokType === _for) {
+        return parseComprehension(startNodeAt(start), true);
+      }
+
+      var innerStart = storeCurrentPos(), exprList = [], first = true, spreadStart, innerParenStart;
+      while (tokType !== _parenR) {
+        first ? first = false : expect(_comma);
+        if (tokType === _ellipsis) {
+          spreadStart = tokStart;
+          exprList.push(parseSpread(true));
+          break;
+        } else {
+          if (tokType === _parenL && !innerParenStart) {
+            innerParenStart = tokStart;
+          }
+          exprList.push(parseMaybeAssign());
+        }
+      }
+      var innerEnd = storeCurrentPos();
+      expect(_parenR);
+
+      if (eat(_arrow)) {
+        if (innerParenStart) unexpected(innerParenStart);
+        return parseArrowExpression(startNodeAt(start), exprList);
+      }
+
+      if (!exprList.length) unexpected(lastStart);
+      if (spreadStart) unexpected(spreadStart);
+
+      if (exprList.length > 1) {
+        val = startNodeAt(innerStart);
+        val.expressions = exprList;
+        finishNodeAt(val, "SequenceExpression", innerEnd);
+      } else {
+        val = exprList[0];
+      }
+    } else {
+      val = parseParenExpression();
+    }
+
+    if (options.preserveParens) {
+      var par = startNodeAt(start);
+      par.expression = val;
+      return finishNode(par, "ParenthesizedExpression");
+    } else {
+      return val;
+    }
+  }
+
   // New's precedence is slightly tricky. It must allow its argument
   // to be a `[]` or dot subscript expression, but not a call — at
   // least, not without wrapping it in parentheses. Thus, it uses the
@@ -2310,7 +2343,7 @@
     return finishNode(node, "TemplateLiteral");
   }
 
-  // Parse an object literal.
+  // Parse an object literal or binding pattern.
 
   function parseObj(isPattern) {
     var node = startNode(), first = true, propHash = {};
@@ -2460,7 +2493,7 @@
     for (;;) {
       if (eat(_parenR)) {
         break;
-      } else if (options.ecmaVersion >= 6 && eat(_ellipsis)) {
+      } else if (eat(_ellipsis)) {
         node.rest = parseAssignableAtom();
         checkSpreadAssign(node.rest);
         expect(_parenR);
@@ -2571,8 +2604,11 @@
         if (allowTrailingComma && options.allowTrailingCommas && eat(close)) break;
       } else first = false;
 
-      if (allowEmpty && tokType === _comma) elts.push(null);
-      else elts.push(parseExpression(true));
+      if (allowEmpty && tokType === _comma) {
+        elts.push(null);
+      } else {
+        elts.push(tokType === _ellipsis ? parseSpread() : parseMaybeAssign());
+      }
     }
     return elts;
   }
diff --git a/acorn_loose.js b/acorn_loose.js
index a6542ee..27e8b65 100644
--- a/acorn_loose.js
+++ b/acorn_loose.js
@@ -622,20 +622,18 @@
 
   function parseMaybeUnary(noIn) {
     if (token.type.prefix) {
-      var node = startNode(), update = token.type.isUpdate, nodeType;
-      if (token.type === tt.ellipsis) {
-        nodeType = "SpreadElement";
-      } else {
-        nodeType = update ? "UpdateExpression" : "UnaryExpression";
-        node.operator = token.value;
-        node.prefix = true;
-      }
+      var node = startNode(), update = token.type.isUpdate;
       node.operator = token.value;
       node.prefix = true;
       next();
       node.argument = parseMaybeUnary(noIn);
       if (update) node.argument = checkLVal(node.argument);
-      return finishNode(node, nodeType);
+      return finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
+    } else if (token.type === tt.ellipsis) {
+      var node = startNode();
+      next();
+      node.argument = parseMaybeUnary(noIn);
+      return finishNode(node, "SpreadElement");
     }
     var start = storeCurrentPos();
     var expr = parseExprSubscripts();
diff --git a/test/tests-harmony.js b/test/tests-harmony.js
index 0ea8758..07bf912 100644
--- a/test/tests-harmony.js
+++ b/test/tests-harmony.js
@@ -13891,9 +13891,9 @@ testFail("import { foo, bar }", "Unexpected token (1:19)", {ecmaVersion: 6});
 
 testFail("import foo from bar", "Unexpected token (1:16)", {ecmaVersion: 6});
 
-testFail("((a)) => 42", "Unexpected token (1:6)", {ecmaVersion: 6});
+testFail("((a)) => 42", "Unexpected token (1:1)", {ecmaVersion: 6});
 
-testFail("(a, (b)) => 42", "Unexpected token (1:9)", {ecmaVersion: 6});
+testFail("(a, (b)) => 42", "Unexpected token (1:4)", {ecmaVersion: 6});
 
 testFail("\"use strict\"; (eval = 10) => 42", "Assigning to eval in strict mode (1:15)", {ecmaVersion: 6});
 
@@ -14151,7 +14151,7 @@ testFail("\"use strict\"; function x({ b: { a } }, [{ b: { a } }]){}", "Argument
 
 testFail("\"use strict\"; function x(a, ...[a]){}", "Argument name clash in strict mode (1:32)", {ecmaVersion: 6});
 
-testFail("(...a, b) => {}", "Unexpected token (1:1)", {ecmaVersion: 6});
+testFail("(...a, b) => {}", "Unexpected token (1:5)", {ecmaVersion: 6});
 
 testFail("([ 5 ]) => {}", "Unexpected token (1:3)", {ecmaVersion: 6});
 
@@ -14226,9 +14226,9 @@ test("[...a, ] = b", {
   locations: true
 });
 
-testFail("if (b,...a, );", "Unexpected token (1:12)", {ecmaVersion: 6});
+testFail("if (b,...a, );", "Unexpected token (1:6)", {ecmaVersion: 6});
 
-testFail("(b, ...a)", "Unexpected token (1:9)", {ecmaVersion: 6});
+testFail("(b, ...a)", "Unexpected token (1:4)", {ecmaVersion: 6});
 
 testFail("switch (cond) { case 10: let a = 20; ", "Unexpected token (1:37)", {ecmaVersion: 6});
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-acorn-jsx.git



More information about the Pkg-javascript-commits mailing list