diff --git a/deps/chakrashim/core/lib/Parser/Parse.cpp b/deps/chakrashim/core/lib/Parser/Parse.cpp index ca50cd96a9a..e881d7d1f27 100644 --- a/deps/chakrashim/core/lib/Parser/Parse.cpp +++ b/deps/chakrashim/core/lib/Parser/Parse.cpp @@ -8278,7 +8278,7 @@ void Parser::DeferOrEmitPotentialSpreadError(ParseNodePtr pnodeT) } } -bool Parser::IsTerminateToken() +bool Parser::IsTerminateToken(bool fAllowIn) { return (m_token.tk == tkRCurly || m_token.tk == tkRBrack || @@ -8287,6 +8287,7 @@ bool Parser::IsTerminateToken() m_token.tk == tkColon || m_token.tk == tkComma || m_token.tk == tkLimKwd || + (m_token.tk == tkIN && fAllowIn) || this->GetScanner()->FHadNewLine()); } @@ -8299,7 +8300,7 @@ template bool Parser::ParseOptionalExpr(ParseNodePtr* pnode, bool fUnaryOrParen, int oplMin, BOOL *pfCanAssign, BOOL fAllowIn, BOOL fAllowEllipsis, _Inout_opt_ IdentToken* pToken) { *pnode = nullptr; - if (IsTerminateToken()) + if (IsTerminateToken(!fAllowIn)) { return false; } @@ -8433,7 +8434,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin, if (nop == knopYield) { - if (!ParseOptionalExpr(&pnodeT, false, opl, NULL, TRUE, fAllowEllipsis)) + if (!ParseOptionalExpr(&pnodeT, false, opl, NULL, fAllowIn, fAllowEllipsis)) { nop = knopYieldLeaf; if (buildAST) @@ -8795,7 +8796,7 @@ ParseNodePtr Parser::ParseExpr(int oplMin, // ArrowFunction/AsyncArrowFunction is part of AssignmentExpression, which should terminate the expression unless followed by a comma if (m_token.tk != tkComma && m_token.tk != tkIN) { - if (!(IsTerminateToken())) + if (!(IsTerminateToken(false))) { Error(ERRnoSemic); } diff --git a/deps/chakrashim/core/lib/Parser/Parse.h b/deps/chakrashim/core/lib/Parser/Parse.h index 2a69c0e1755..61d26fe0809 100644 --- a/deps/chakrashim/core/lib/Parser/Parse.h +++ b/deps/chakrashim/core/lib/Parser/Parse.h @@ -828,7 +828,7 @@ class Parser template ParseNodePtr ParseMemberList(LPCOLESTR pNameHint, uint32 *pHintLength, tokens declarationType = tkNone); template IdentPtr ParseSuper(bool fAllowCall); - bool IsTerminateToken(); + bool IsTerminateToken(bool fAllowIn); // Used to determine the type of JavaScript object member. // The values can be combined using bitwise OR. diff --git a/deps/chakrashim/core/test/es6/forInEdgeCases.js b/deps/chakrashim/core/test/es6/forInEdgeCases.js new file mode 100644 index 00000000000..4a686ad218f --- /dev/null +++ b/deps/chakrashim/core/test/es6/forInEdgeCases.js @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js"); + + +function testGen(func, values, count) +{ + const gen = func(); + let counter = 0; + for (const value of gen) + { + assert.isTrue(value == values[counter]); + ++counter; + } + assert.areEqual(counter, count); +} + + +const tests = [ + { + name : "For - in with Arrow function sloppy", + body : function () { + const arr = [0,1,2,5]; + for (var a = () => { return "a"} in {}); + assert.areEqual(a(), "a"); + for (var a = () => { return "a"} in arr); + assert.isTrue(a == "3"); + } + }, + { + name : "For - in with Arrow function strict", + body : function () { + "use strict"; + assert.throws(()=>{eval("for (var a = () => { return 'a'} in {});")}, SyntaxError); + } + }, + { + name : "For - in with yield - sloppy", + body : function () { + function* gen1() + { + for (var a = yield 'a' in {b: 1}) { + assert.isTrue(a == "b"); + } + } + testGen(gen1, ["a"], 1); + function* gen2() + { + for (var a = yield in {c: 1}) { + assert.isTrue(a == "c"); + } + } + testGen(gen2, [undefined], 1); + function* gen3() + { + for (var a = yield 'd' in {} in {a: 1}) { + assert.isTrue(false, "shouldn't reach here"); + } + } + testGen(gen3, ['d'], 1); + } + }, + { + name : "For - in with yield - strict", + body : function () { + "use strict"; + assert.throws(()=>{eval(`function* gen1() + { + for (var a = yield 'a' in {b: 1}) { + assert.isTrue(a == "b"); + } + }`)}, SyntaxError); + } + } +]; + +testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" }); diff --git a/deps/chakrashim/core/test/es6/generators-syntax.js b/deps/chakrashim/core/test/es6/generators-syntax.js index 2698c3ac8dc..c72564d9414 100644 --- a/deps/chakrashim/core/test/es6/generators-syntax.js +++ b/deps/chakrashim/core/test/es6/generators-syntax.js @@ -212,6 +212,14 @@ var tests = [ assert.throws(function () { eval("function *gf() { (a = (yield) => {}) => {}; }"); }, SyntaxError, "yield expression is disallowed within arrow function default parameter expression in nested case too", "The use of a keyword for an identifier is invalid"); } }, + { + name : "yield is allowed before 'in' in a for loop control but not elsewhere bug issue #5203", + body : function () { + assert.doesNotThrow(function () { eval("function* gf() {for(var a = yield in {});}"); }, "Yield is allowed before 'in' in a for loop"); + assert.throws(function () { eval("function* gf() {var a = yield in {};}"); }, SyntaxError, "Yield is not allowed before 'in' when not declaring a loop"); + assert.throws(function () { eval("function* gf() {yield in {};}"); }, SyntaxError, "Yield is not allowed before 'in' when not declaring a loop"); + } + } ]; testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" }); diff --git a/deps/chakrashim/core/test/es6/lambda-expr.js b/deps/chakrashim/core/test/es6/lambda-expr.js index 7f030ff405b..a1685a5c649 100644 --- a/deps/chakrashim/core/test/es6/lambda-expr.js +++ b/deps/chakrashim/core/test/es6/lambda-expr.js @@ -33,3 +33,6 @@ catch (e) { print(e.message); } + +// Legal case, lambda in object inside for() +for (var i = () => {} in {}); diff --git a/deps/chakrashim/core/test/es6/rlexe.xml b/deps/chakrashim/core/test/es6/rlexe.xml index 62594c96032..e2aeb8c7139 100644 --- a/deps/chakrashim/core/test/es6/rlexe.xml +++ b/deps/chakrashim/core/test/es6/rlexe.xml @@ -846,6 +846,12 @@ exclude_arm + + + forInEdgeCases.js + -args summary -endargs + + generators-deferparse.js