From 2db14fbb08ce12f57b7ed92c6c3d70e68d0c52ab Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Thu, 24 Jul 2014 02:51:37 +0300 Subject: [PATCH] Checking argument names clash in strict mode for arrow functions. Some more testFail message fixes. --- acorn.js | 79 +++++++++++++++++++++++-------------------- test/tests-harmony.js | 28 +++++++-------- 2 files changed, 57 insertions(+), 50 deletions(-) diff --git a/acorn.js b/acorn.js index 43500b6853..556ab0e5cb 100644 --- a/acorn.js +++ b/acorn.js @@ -1810,7 +1810,6 @@ node.defaults = []; node.rest = null; node.generator = false; - node.expression = false; } expect(_parenL); for (;;) { @@ -1828,36 +1827,7 @@ } } } - - // Start a new scope with regard to labels and the `inFunction` - // flag (restore them to their old value afterwards). - var oldInFunc = inFunction, oldLabels = labels; - inFunction = true; labels = []; - node.body = parseBlock(true); - inFunction = oldInFunc; labels = oldLabels; - - // If this is a strict mode function, verify that argument names - // are not repeated, and it does not try to bind the words `eval` - // or `arguments`. - if (strict || node.body.body.length && isUseStrict(node.body.body[0])) { - // Negative indices are used to reuse loop body for node.rest and node.id - for (var i = -2, id; i < node.params.length; ++i) { - if (i >= 0) { - id = node.params[i]; - } else if (i == -2) { - if (node.rest) id = node.rest; - else continue; - } else { - if (node.id) id = node.id; - else continue; - } - if (isStrictReservedWord(id.name) || isStrictBadIdWord(id.name)) - raise(id.start, "Defining '" + id.name + "' in strict mode"); - if (i >= 0) for (var j = 0; j < i; ++j) if (id.name === node.params[j].name) - raise(id.start, "Argument name clash in strict mode"); - } - } - + parseFunctionBody(node); return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); } @@ -1885,19 +1855,56 @@ } } - var isExpression = tokType !== _braceL; - var body = isExpression ? parseExpression(true) : parseBlock(true); - node.id = null; node.params = params; node.defaults = hasDefaults ? defaults : []; node.rest = null; - node.body = body; node.generator = false; - node.expression = isExpression; + parseFunctionBody(node, true); return finishNode(node, "ArrowFunctionExpression"); } + // Parse function body and check parameters. + + function parseFunctionBody(node, allowExpression) { + var isExpression = allowExpression && tokType !== _braceL; + + if (isExpression) { + node.body = parseExpression(true); + node.expression = true; + } else { + // Start a new scope with regard to labels and the `inFunction` + // flag (restore them to their old value afterwards). + var oldInFunc = inFunction, oldLabels = labels; + inFunction = true; labels = []; + node.body = parseBlock(true); + node.expression = false; + inFunction = oldInFunc; labels = oldLabels; + } + + // If this is a strict mode function, verify that argument names + // are not repeated, and it does not try to bind the words `eval` + // or `arguments`. + if (strict || !isExpression && node.body.body.length && isUseStrict(node.body.body[0])) { + // Negative indices are used to reuse loop body for node.rest and node.id + for (var i = -2, id; i < node.params.length; ++i) { + if (i >= 0) { + id = node.params[i]; + } else if (i == -2) { + if (node.rest) id = node.rest; + else continue; + } else { + if (node.id) id = node.id; + else continue; + } + if (isStrictReservedWord(id.name) || isStrictBadIdWord(id.name)) + raise(id.start, "Defining '" + id.name + "' in strict mode"); + if (i >= 0) for (var j = 0; j < i; ++j) if (id.name === node.params[j].name) + raise(id.start, "Argument name clash in strict mode"); + } + } + } + // Parses a comma-separated list of expressions, and returns them as // an array. `close` is the token type that ends the list, and // `allowEmpty` can be turned on to allow subsequent commas with diff --git a/test/tests-harmony.js b/test/tests-harmony.js index 05d5097780..95905f1fbf 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -15817,33 +15817,33 @@ testFail("((a)) => 42", "Unexpected token (1:7)", {ecmaVersion: 6}); testFail("(a, (b)) => 42", "Unexpected token (1:10)", {ecmaVersion: 6}); -testFail("\"use strict\"; (eval = 10) => 42", "Unexpected token (1:16)", {ecmaVersion: 6}); +testFail("\"use strict\"; (eval = 10) => 42", "Assigning to eval in strict mode (1:15)", {ecmaVersion: 6}); -testFail("\"use strict\"; eval => 42", "Unexpected token (1:25)", {ecmaVersion: 6}); +testFail("\"use strict\"; eval => 42", "Defining 'eval' in strict mode (1:14)", {ecmaVersion: 6}); -testFail("\"use strict\"; arguments => 42", "Unexpected token (1:30)", {ecmaVersion: 6}); +testFail("\"use strict\"; arguments => 42", "Defining 'arguments' in strict mode (1:14)", {ecmaVersion: 6}); -testFail("\"use strict\"; (eval, a) => 42", "Unexpected token (1:30)", {ecmaVersion: 6}); +testFail("\"use strict\"; (eval, a) => 42", "Defining 'eval' in strict mode (1:15)", {ecmaVersion: 6}); -testFail("\"use strict\"; (arguments, a) => 42", "Unexpected token (1:35)", {ecmaVersion: 6}); +testFail("\"use strict\"; (arguments, a) => 42", "Defining 'arguments' in strict mode (1:15)", {ecmaVersion: 6}); -testFail("\"use strict\"; (eval, a = 10) => 42", "Unexpected token (1:35)", {ecmaVersion: 6}); +testFail("\"use strict\"; (eval, a = 10) => 42", "Defining 'eval' in strict mode (1:15)", {ecmaVersion: 6}); testFail("(a, a) => 42", "Unexpected token (1:7)", {ecmaVersion: 6}); -testFail("\"use strict\"; (a, a) => 42", "Unexpected token (1:21)", {ecmaVersion: 6}); +testFail("\"use strict\"; (a, a) => 42", "Argument name clash in strict mode (1:18)", {ecmaVersion: 6}); -testFail("\"use strict\"; (a) => 00", "Unexpected token (1:22)", {ecmaVersion: 6}); +testFail("\"use strict\"; (a) => 00", "Invalid number (1:21)", {ecmaVersion: 6}); testFail("() <= 42", "Unexpected token (1:4)", {ecmaVersion: 6}); -testFail("(10) => 00", "Unexpected token (1:6)", {ecmaVersion: 6}); +testFail("(10) => 00", "Unexpected token (1:1)", {ecmaVersion: 6}); -testFail("(10, 20) => 00", "Unexpected token (1:10)", {ecmaVersion: 6}); +testFail("(10, 20) => 00", "Unexpected token (1:1)", {ecmaVersion: 6}); -testFail("yield v", "Unexpected token (1:7)", {ecmaVersion: 6}); +testFail("yield v", "Unexpected token (1:6)", {ecmaVersion: 6}); -testFail("yield 10", "Unexpected token (1:7)", {ecmaVersion: 6}); +testFail("yield 10", "Unexpected token (1:6)", {ecmaVersion: 6}); test("yield* 10", { type: "Program", @@ -16126,8 +16126,8 @@ testFail("module \"Universe\" { ; ; ", "Unexpected token (1:27)", {ecmaVersion testFail("switch (cond) { case 10: let a = 20; ", "Unexpected token (1:37)", {ecmaVersion: 6}); -testFail("\"use strict\"; (eval) => 42", "Unexpected token (1:27)", {ecmaVersion: 6}); +testFail("\"use strict\"; (eval) => 42", "Defining 'eval' in strict mode (1:15)", {ecmaVersion: 6}); -testFail("(eval) => { \"use strict\"; 42 }", "Unexpected token (1:31)", {ecmaVersion: 6}); +testFail("(eval) => { \"use strict\"; 42 }", "Defining 'eval' in strict mode (1:1)", {ecmaVersion: 6}); testFail("({ get test() { } }) => 42", "Unexpected token (1:21)", {ecmaVersion: 6});