diff --git a/README.md b/README.md index 245b71bccd..32ee0b7d76 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,9 @@ object referring to that same position. trailing commas in array and object literals. Default is `true`. - **forbidReserved**: If `true`, using a reserved word will generate - an error. Defaults to `false`. + an error. Defaults to `false`. When given the value `"everywhere"`, + reserved words and keywords can also not be used as property names + (as in Internet Explorer's old parser). - **allowReturnOutsideFunction**: By default, a return statement at the top level raises an error. Set this to `true` to accept such diff --git a/acorn.js b/acorn.js index b58f1dab92..0f11931752 100644 --- a/acorn.js +++ b/acorn.js @@ -62,7 +62,9 @@ // trailing commas in array and object literals. allowTrailingCommas: true, // By default, reserved words are not enforced. Enable - // `forbidReserved` to enforce them. + // `forbidReserved` to enforce them. When this option has the + // value "everywhere", reserved words and keywords can also not be + // used as property names. forbidReserved: false, // When enabled, a return at the top level is not considered an // error. @@ -941,13 +943,8 @@ function readWord() { var word = readWord1(); var type = _name; - if (!containsEsc) { - if (isKeyword(word)) type = keywordTypes[word]; - else if (options.forbidReserved && - (options.ecmaVersion === 3 ? isReservedWord3 : isReservedWord5)(word) || - strict && isStrictReservedWord(word)) - raise(tokStart, "The keyword '" + word + "' is reserved"); - } + if (!containsEsc && isKeyword(word)) + type = keywordTypes[word]; return finishToken(type, word); } @@ -1763,7 +1760,20 @@ function parseIdent(liberal) { var node = startNode(); - node.name = tokType === _name ? tokVal : (liberal && !options.forbidReserved && tokType.keyword) || unexpected(); + if (liberal && options.forbidReserved == "everywhere") liberal = false; + if (tokType === _name) { + if (!liberal && + (options.forbidReserved && + (options.ecmaVersion === 3 ? isReservedWord3 : isReservedWord5)(tokVal) || + strict && isStrictReservedWord(tokVal)) && + input.slice(tokStart, tokEnd).indexOf("\\") == -1) + raise(tokStart, "The keyword '" + tokVal + "' is reserved"); + node.name = tokVal; + } else if (liberal && tokType.keyword) { + node.name = tokType.keyword; + } else { + unexpected(); + } tokRegexpAllowed = false; next(); return finishNode(node, "Identifier"); diff --git a/index.html b/index.html index 74e39e6a5b..f189721410 100644 --- a/index.html +++ b/index.html @@ -39,7 +39,9 @@ influences support for strict mode, the set of reserved words, and support for getters and setter.

    ecmaVersion: 5,

Turn on strictSemicolons to prevent the parser from doing automatic semicolon insertion.

    strictSemicolons: false,

When allowTrailingCommas is false, the parser will not allow trailing commas in array and object literals.

    allowTrailingCommas: true,

By default, reserved words are not enforced. Enable -forbidReserved to enforce them.

    forbidReserved: false,

When enabled, a return at the top level is not considered an +forbidReserved to enforce them. When this option has the +value "everywhere", reserved words and keywords can also not be +used as property names.

    forbidReserved: false,

When enabled, a return at the top level is not considered an error.

    allowReturnOutsideFunction: false,

When locations is on, loc properties holding objects with start and end properties in {line, column} form (with line being 1-based and column 0-based) will be attached to the @@ -676,13 +678,8 @@ containeds an escape, as a micro-optimization.

words when necessary.

  function readWord() {
     var word = readWord1();
     var type = _name;
-    if (!containsEsc) {
-      if (isKeyword(word)) type = keywordTypes[word];
-      else if (options.forbidReserved &&
-               (options.ecmaVersion === 3 ? isReservedWord3 : isReservedWord5)(word) ||
-               strict && isStrictReservedWord(word))
-        raise(tokStart, "The keyword '" + word + "' is reserved");
-    }
+    if (!containsEsc && isKeyword(word))
+      type = keywordTypes[word];
     return finishToken(type, word);
   }

Parser

A recursive descent parser operates by defining functions for all syntactic elements, and recursively calling those, each function @@ -1323,7 +1320,20 @@ for array literals).

when parsing properties), it will also convert keywords into identifiers.

  function parseIdent(liberal) {
     var node = startNode();
-    node.name = tokType === _name ? tokVal : (liberal && !options.forbidReserved && tokType.keyword) || unexpected();
+    if (liberal && options.forbidReserved == "everywhere") liberal = false;
+    if (tokType === _name) {
+      if (!liberal &&
+          (options.forbidReserved &&
+           (options.ecmaVersion === 3 ? isReservedWord3 : isReservedWord5)(tokVal) ||
+           strict && isStrictReservedWord(tokVal)) &&
+          input.slice(tokStart, tokEnd).indexOf("\\") == -1)
+        raise(tokStart, "The keyword '" + tokVal + "' is reserved");
+      node.name = tokVal;
+    } else if (liberal && tokType.keyword) {
+      node.name = tokType.keyword;
+    } else {
+      unexpected();
+    }
     tokRegexpAllowed = false;
     next();
     return finishNode(node, "Identifier");
diff --git a/test/tests.js b/test/tests.js
index efce0b4122..9cb04321fb 100644
--- a/test/tests.js
+++ b/test/tests.js
@@ -26348,6 +26348,39 @@ test("x = y-->10;\n --> nothing", {
   ]
 });
 
+test("'use strict';\nobject.static();", {
+  type: "Program",
+  body: [
+    {
+      type: "ExpressionStatement",
+      expression: {
+        type: "Literal",
+        value: "use strict",
+        raw: "'use strict'"
+      }
+    },
+    {
+      type: "ExpressionStatement",
+      expression: {
+        type: "CallExpression",
+        callee: {
+          type: "MemberExpression",
+          object: {
+            type: "Identifier",
+            name: "object"
+          },
+          property: {
+            type: "Identifier",
+            name: "static"
+          },
+          computed: false
+        },
+        arguments: []
+      }
+    }
+  ]
+});
+
 // Failure tests
 
 testFail("{",