Unify checkLVal and checkFunctionParam

This commit is contained in:
Marijn Haverbeke 2015-03-19 13:42:26 +01:00
parent 0a755156a8
commit a45172e044
3 changed files with 49 additions and 72 deletions

View File

@ -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;
}
};

View File

@ -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});

View File

@ -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)");