diff --git a/acorn.js b/acorn.js index 2fe39a2d90..00402ed773 100644 --- a/acorn.js +++ b/acorn.js @@ -1660,36 +1660,6 @@ return this.finishNode(node, "AssignmentPattern"); }; - // Verify that argument names are not repeated, and it does not - // try to bind the words `eval` or `arguments`. - - pp.checkFunctionParam = function(param, nameHash) { - switch (param.type) { - case "Identifier": - if (isStrictReservedWord(param.name) || isStrictBadIdWord(param.name)) - this.raise(param.start, "Defining '" + param.name + "' in strict mode"); - if (has(nameHash, param.name)) - this.raise(param.start, "Argument name clash in strict mode"); - nameHash[param.name] = true; - break; - - case "ObjectPattern": - for (var i = 0; i < param.properties.length; i++) - this.checkFunctionParam(param.properties[i].value, nameHash); - break; - - case "ArrayPattern": - for (var i = 0; i < param.elements.length; i++) { - var elem = param.elements[i]; - if (elem) this.checkFunctionParam(elem, nameHash); - } - break; - - case "RestElement": - return this.checkFunctionParam(param.argument, nameHash); - } - }; - // Check if property name clashes with already added. // Object/class getters and setters are not allowed to clash — // either with each other or with an init property — and in @@ -1722,39 +1692,44 @@ // Verify that a node is an lval — something that can be assigned // to. - pp.checkLVal = function(expr, isBinding) { + pp.checkLVal = function(expr, isBinding, checkClashes) { switch (expr.type) { case "Identifier": if (this.strict && (isStrictBadIdWord(expr.name) || isStrictReservedWord(expr.name))) this.raise(expr.start, (isBinding ? "Binding " : "Assigning to ") + expr.name + " in strict mode"); + if (checkClashes) { + if (has(checkClashes, expr.name)) + this.raise(expr.start, "Argument name clash in strict mode"); + checkClashes[expr.name] = true; + } break; case "MemberExpression": - if (isBinding) this.raise(expr.start, "Binding to member expression"); + if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression"); break; case "ObjectPattern": for (var i = 0; i < expr.properties.length; i++) - this.checkLVal(expr.properties[i].value, isBinding); + this.checkLVal(expr.properties[i].value, isBinding, checkClashes); break; case "ArrayPattern": for (var i = 0; i < expr.elements.length; i++) { var elem = expr.elements[i]; - if (elem) this.checkLVal(elem, isBinding); + if (elem) this.checkLVal(elem, isBinding, checkClashes); } break; case "AssignmentPattern": - this.checkLVal(expr.left); + this.checkLVal(expr.left, isBinding, checkClashes); break; case "RestElement": - this.checkLVal(expr.argument); + this.checkLVal(expr.argument, isBinding, checkClashes); break; default: - this.raise(expr.start, "Assigning to rvalue"); + this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue"); } }; @@ -2650,11 +2625,13 @@ // are not repeated, and it does not try to bind the words `eval` // or `arguments`. if (this.strict || !isExpression && node.body.body.length && this.isUseStrict(node.body.body[0])) { - var nameHash = {}; + var nameHash = {}, oldStrict = this.strict; + this.strict = true; if (node.id) - this.checkFunctionParam(node.id, {}); + this.checkLVal(node.id, true); for (var i = 0; i < node.params.length; i++) - this.checkFunctionParam(node.params[i], nameHash); + this.checkLVal(node.params[i], true, nameHash); + this.strict = oldStrict; } }; diff --git a/test/tests-harmony.js b/test/tests-harmony.js index a300fa8d84..15fcd92c1e 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -13967,7 +13967,7 @@ testFail("x \n isnt y", "Unexpected token (2:6)", {ecmaVersion: 6}); testFail("function default() {}", "Unexpected token (1:9)", {ecmaVersion: 6}); -testFail("function hello() {'use strict'; ({ i: 10, s(eval) { } }); }", "Defining 'eval' in strict mode (1:44)", {ecmaVersion: 6}); +testFail("function hello() {'use strict'; ({ i: 10, s(eval) { } }); }", "Binding eval in strict mode (1:44)", {ecmaVersion: 6}); testFail("function a() { \"use strict\"; ({ b(t, t) { } }); }", "Argument name clash in strict mode (1:37)", {ecmaVersion: 6}); @@ -13999,15 +13999,15 @@ 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}); -testFail("\"use strict\"; eval => 42", "Defining 'eval' in strict mode (1:14)", {ecmaVersion: 6}); +testFail("\"use strict\"; eval => 42", "Binding eval in strict mode (1:14)", {ecmaVersion: 6}); -testFail("\"use strict\"; arguments => 42", "Defining 'arguments' in strict mode (1:14)", {ecmaVersion: 6}); +testFail("\"use strict\"; arguments => 42", "Binding arguments in strict mode (1:14)", {ecmaVersion: 6}); -testFail("\"use strict\"; (eval, a) => 42", "Defining 'eval' in strict mode (1:15)", {ecmaVersion: 6}); +testFail("\"use strict\"; (eval, a) => 42", "Binding eval in strict mode (1:15)", {ecmaVersion: 6}); -testFail("\"use strict\"; (arguments, a) => 42", "Defining 'arguments' in strict mode (1:15)", {ecmaVersion: 6}); +testFail("\"use strict\"; (arguments, a) => 42", "Binding arguments in strict mode (1:15)", {ecmaVersion: 6}); -testFail("\"use strict\"; (eval, a = 10) => 42", "Defining 'eval' in strict mode (1:15)", {ecmaVersion: 6}); +testFail("\"use strict\"; (eval, a = 10) => 42", "Binding eval in strict mode (1:15)", {ecmaVersion: 6}); testFail("\"use strict\"; (a, a) => 42", "Argument name clash in strict mode (1:18)", {ecmaVersion: 6}); @@ -14261,7 +14261,7 @@ testFail("[...{ a }] = b", "Unexpected token (1:4)", {ecmaVersion: 6}); testFail("[...a, b] = c", "Assigning to rvalue (1:1)", {ecmaVersion: 6}); -testFail("({ t(eval) { \"use strict\"; } });", "Defining 'eval' in strict mode (1:5)", {ecmaVersion: 6}); +testFail("({ t(eval) { \"use strict\"; } });", "Binding eval in strict mode (1:5)", {ecmaVersion: 6}); testFail("\"use strict\"; `${test}\\02`;", "Octal literal in strict mode (1:22)", {ecmaVersion: 6}); @@ -14330,9 +14330,9 @@ testFail("(b, ...a)", "Unexpected token (1:4)", {ecmaVersion: 6}); testFail("switch (cond) { case 10: let a = 20; ", "Unexpected token (1:37)", {ecmaVersion: 6}); -testFail("\"use strict\"; (eval) => 42", "Defining 'eval' in strict mode (1:15)", {ecmaVersion: 6}); +testFail("\"use strict\"; (eval) => 42", "Binding eval in strict mode (1:15)", {ecmaVersion: 6}); -testFail("(eval) => { \"use strict\"; 42 }", "Defining 'eval' in strict mode (1:1)", {ecmaVersion: 6}); +testFail("(eval) => { \"use strict\"; 42 }", "Binding eval in strict mode (1:1)", {ecmaVersion: 6}); testFail("({ get test() { } }) => 42", "Object pattern can't contain getter or setter (1:7)", {ecmaVersion: 6}); diff --git a/test/tests.js b/test/tests.js index f3d499dd11..b13dfb2e2e 100644 --- a/test/tests.js +++ b/test/tests.js @@ -27261,55 +27261,55 @@ testFail("function hello() {'use strict'; arguments--; }", "Assigning to arguments in strict mode (1:32)"); testFail("function hello() {'use strict'; function eval() { } }", - "Defining 'eval' in strict mode (1:41)"); + "Binding eval in strict mode (1:41)"); testFail("function hello() {'use strict'; function arguments() { } }", - "Defining 'arguments' in strict mode (1:41)"); + "Binding arguments in strict mode (1:41)"); testFail("function eval() {'use strict'; }", - "Defining 'eval' in strict mode (1:9)"); + "Binding eval in strict mode (1:9)"); testFail("function arguments() {'use strict'; }", - "Defining 'arguments' in strict mode (1:9)"); + "Binding arguments in strict mode (1:9)"); testFail("function hello() {'use strict'; (function eval() { }()) }", - "Defining 'eval' in strict mode (1:42)"); + "Binding eval in strict mode (1:42)"); testFail("function hello() {'use strict'; (function arguments() { }()) }", - "Defining 'arguments' in strict mode (1:42)"); + "Binding arguments in strict mode (1:42)"); testFail("(function eval() {'use strict'; })()", - "Defining 'eval' in strict mode (1:10)"); + "Binding eval in strict mode (1:10)"); testFail("(function arguments() {'use strict'; })()", - "Defining 'arguments' in strict mode (1:10)"); + "Binding arguments in strict mode (1:10)"); testFail("function hello() {'use strict'; ({ s: function eval() { } }); }", - "Defining 'eval' in strict mode (1:47)"); + "Binding eval in strict mode (1:47)"); testFail("(function package() {'use strict'; })()", - "Defining 'package' in strict mode (1:10)"); + "Binding package in strict mode (1:10)"); testFail("function hello() {'use strict'; ({ i: 10, set s(eval) { } }); }", - "Defining 'eval' in strict mode (1:48)"); + "Binding eval in strict mode (1:48)"); testFail("function hello() {'use strict'; ({ set s(eval) { } }); }", - "Defining 'eval' in strict mode (1:41)"); + "Binding eval in strict mode (1:41)"); testFail("function hello() {'use strict'; ({ s: function s(eval) { } }); }", - "Defining 'eval' in strict mode (1:49)"); + "Binding eval in strict mode (1:49)"); testFail("function hello(eval) {'use strict';}", - "Defining 'eval' in strict mode (1:15)"); + "Binding eval in strict mode (1:15)"); testFail("function hello(arguments) {'use strict';}", - "Defining 'arguments' in strict mode (1:15)"); + "Binding arguments in strict mode (1:15)"); testFail("function hello() { 'use strict'; function inner(eval) {} }", - "Defining 'eval' in strict mode (1:48)"); + "Binding eval in strict mode (1:48)"); testFail("function hello() { 'use strict'; function inner(arguments) {} }", - "Defining 'arguments' in strict mode (1:48)"); + "Binding arguments in strict mode (1:48)"); testFail("function hello() { 'use strict'; \"\\1\"; }", "Octal literal in strict mode (1:34)"); @@ -27348,10 +27348,10 @@ testFail("function hello() { \"use strict\"; var static; }", "The keyword 'static' is reserved (1:37)"); testFail("function hello(static) { \"use strict\"; }", - "Defining 'static' in strict mode (1:15)"); + "Binding static in strict mode (1:15)"); testFail("function static() { \"use strict\"; }", - "Defining 'static' in strict mode (1:9)"); + "Binding static in strict mode (1:9)"); testFail("\"use strict\"; function static() { }", "The keyword 'static' is reserved (1:23)"); @@ -27360,10 +27360,10 @@ testFail("function a(t, t) { \"use strict\"; }", "Argument name clash in strict mode (1:14)"); testFail("function a(eval) { \"use strict\"; }", - "Defining 'eval' in strict mode (1:11)"); + "Binding eval in strict mode (1:11)"); testFail("function a(package) { \"use strict\"; }", - "Defining 'package' in strict mode (1:11)"); + "Binding package in strict mode (1:11)"); testFail("function a() { \"use strict\"; function b(t, t) { }; }", "Argument name clash in strict mode (1:43)"); @@ -27375,10 +27375,10 @@ testFail("function a() { \"use strict\"; (function b(t, t) { }); }", "Argument name clash in strict mode (1:44)"); testFail("(function a(eval) { \"use strict\"; })", - "Defining 'eval' in strict mode (1:12)"); + "Binding eval in strict mode (1:12)"); testFail("(function a(package) { \"use strict\"; })", - "Defining 'package' in strict mode (1:12)"); + "Binding package in strict mode (1:12)"); testFail("\"use strict\";function foo(){\"use strict\";}function bar(){var v = 015}", "Invalid number (1:65)");