Skip to content

Commit

Permalink
Throw ERRBadAwait instead of ERRnoSemic if applicable (chakra-cor…
Browse files Browse the repository at this point in the history
…e#6955)

* Throw `ERRBadAwait` instead of `ERRnoSemic` if applicable
  • Loading branch information
ShortDevelopment authored Apr 16, 2024
1 parent 2f15d4e commit 469795b
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 14 deletions.
10 changes: 8 additions & 2 deletions lib/Parser/Parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5483,7 +5483,7 @@ ParseNodeFnc * Parser::ParseFncDeclInternal(ushort flags, LPCOLESTR pNameHint, c
{
// Class member methods have optional separators. We need to check whether we are
// getting the IchLim of the correct token.
Assert(this->GetScanner()->m_tkPrevious == tkRCurly && needScanRCurly);
Assert(this->GetScanner()->GetPrevious() == tkRCurly && needScanRCurly);

this->m_funcInArray += this->GetScanner()->IchMinTok() - /*tkRCurly*/ 1 - ichMin;
}
Expand Down Expand Up @@ -6529,7 +6529,7 @@ bool Parser::FastScanFormalsAndBody()
{
int opl;
OpCode nop;
tokens tkPrev = this->GetScanner()->m_tkPrevious;
tokens tkPrev = this->GetScanner()->GetPrevious();
if ((this->GetHashTbl()->TokIsBinop(tkPrev, &opl, &nop) && nop != knopNone) ||
(this->GetHashTbl()->TokIsUnop(tkPrev, &opl, &nop) &&
nop != knopNone &&
Expand Down Expand Up @@ -11267,6 +11267,12 @@ ParseNodePtr Parser::ParseStatement()
default:
if (!this->GetScanner()->FHadNewLine())
{
Token previous = this->GetScanner()->GetPreviousToken();
if (tkID == previous.tk && wellKnownPropertyPids.await == previous.GetIdentifier(this->GetHashTbl()))
{
Error(ERRBadAwait);
}

Error(ERRnoSemic);
}
else
Expand Down
3 changes: 2 additions & 1 deletion lib/Parser/Scan.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "ParserPch.h"
Expand Down Expand Up @@ -1592,7 +1593,7 @@ tokens Scanner<EncodingPolicy>::ScanCore(bool identifyKwds)
bool seenDelimitedCommentEnd = false;

// store the last token
m_tkPrevious = m_ptoken->tk;
m_tokenPrevious = *m_ptoken;
m_iecpLimTokPrevious = IecpLimTok(); // Introduced for use by lambda parsing to find correct span of expression lambdas
m_ichLimTokPrevious = IchLimTok();
size_t savedMultiUnits = this->m_cMultiUnits;
Expand Down
6 changes: 4 additions & 2 deletions lib/Parser/Scan.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
Expand Down Expand Up @@ -705,7 +706,8 @@ class Scanner : public IScanner, public EncodingPolicy
}
};

tokens GetPrevious() { return m_tkPrevious; }
tokens GetPrevious() { return m_tokenPrevious.tk; }
Token GetPreviousToken() { return m_tokenPrevious; }
void Capture(_Out_ RestorePoint* restorePoint);
void SeekTo(const RestorePoint& restorePoint);
void SeekToForcingPid(const RestorePoint& restorePoint);
Expand Down Expand Up @@ -756,7 +758,7 @@ class Scanner : public IScanner, public EncodingPolicy
Js::ScriptContext* m_scriptContext;
const Js::CharClassifier *charClassifier;

tokens m_tkPrevious;
Token m_tokenPrevious;
size_t m_iecpLimTokPrevious;
charcount_t m_ichLimTokPrevious;

Expand Down
27 changes: 18 additions & 9 deletions test/es7/asyncawait-syntax.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -58,26 +59,26 @@ var tests = [
{
name: "Await in eval global scope",
body: function () {
assert.throws(function () { eval("var result = await call();"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ';'");
assert.throws(function () { eval("await call();"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ';'");
assert.throws(function () { eval("var result = await call();"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", `'await' expression not allowed in this context`);
assert.throws(function () { eval("await call();"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", `'await' expression not allowed in this context`);

assert.throws(function () { eval("await a;"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ';'");
assert.throws(function () { eval("await a[0];"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ';'");
assert.throws(function () { eval("await o.p;"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ';'");
assert.throws(function () { eval("await a;"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", `'await' expression not allowed in this context`);
assert.throws(function () { eval("await a[0];"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", `'await' expression not allowed in this context`);
assert.throws(function () { eval("await o.p;"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", `'await' expression not allowed in this context`);
assert.throws(function () { eval("a[await p];"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ']'");
assert.throws(function () { eval("a + await p;"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ';'");
assert.throws(function () { eval("await p + await q;"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ';'");
assert.throws(function () { eval("a + await p;"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", `'await' expression not allowed in this context`);
assert.throws(function () { eval("await p + await q;"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", `'await' expression not allowed in this context`);
assert.throws(function () { eval("foo(await p, await q);"); }, SyntaxError, "'await' keyword is not allowed in eval global scope", "Expected ')'");

assert.throws(function () { eval("var lambdaParenNoArg = await () => x < y;"); }, SyntaxError, "'await' keyword is not allowed with a non-async lambda expression", "Syntax error");
assert.throws(function () { eval("var lambdaArgs = await async (a, b ,c) => a + b + c;"); }, SyntaxError, "There miss parenthises", "Expected ';'");
assert.throws(function () { eval("var lambdaArgs = await async (a, b ,c) => a + b + c;"); }, SyntaxError, "There miss parenthises", `'await' expression not allowed in this context`);
assert.throws(function () { eval("var lambdaArgs = await (async (a, b ,c) => a + b + c);"); }, ReferenceError, "The 'await' function doesn't exists in this scope", "'await' is not defined");
}
},
{
name: "Await in a non-async function",
body: function () {
assert.throws(function () { eval("function method() { var x = await call(); }"); }, SyntaxError, "'await' cannot be used in a non-async function.", "Expected ';'");
assert.throws(function () { eval("function method() { var x = await call(); }"); }, SyntaxError, "'await' cannot be used in a non-async function.", `'await' expression not allowed in this context`);
}
},
{
Expand Down Expand Up @@ -216,6 +217,14 @@ var tests = [
assert.throws(function () { eval("async function af() { (b = (c = await => {}) => {}) => {}; }"); }, SyntaxError, "await cannot appear as the formal name of an unparathensized arrow function in a nested case too", "Unexpected token '=>' after 'await'");
}
},
{
name: "Specific error message when using 'await' as a keyword outside 'async' context",
body: function () {
assert.throws(function () {
eval(`await new Promise(() => {});`);
}, SyntaxError, "await is not a keyword here", `'await' expression not allowed in this context`);
}
}
];

testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

0 comments on commit 469795b

Please # to comment.