Diff
Modified: trunk/JSTests/ChangeLog (223123 => 223124)
--- trunk/JSTests/ChangeLog 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/JSTests/ChangeLog 2017-10-10 05:53:12 UTC (rev 223124)
@@ -1,3 +1,17 @@
+2017-10-09 Yusuke Suzuki <[email protected]>
+
+ `async` should be able to be used as an imported binding name
+ https://bugs.webkit.org/show_bug.cgi?id=176573
+
+ Reviewed by Saam Barati.
+
+ * modules/import-default-async.js: Added.
+ * modules/import-named-async-as.js: Added.
+ * modules/import-named-async.js: Added.
+ * modules/import-named-async/target.js: Added.
+ * modules/import-namespace-async.js: Added.
+ * test262.yaml:
+
2017-09-29 Filip Pizlo <[email protected]>
Enable gigacage on iOS
Added: trunk/JSTests/modules/import-default-async.js (0 => 223124)
--- trunk/JSTests/modules/import-default-async.js (rev 0)
+++ trunk/JSTests/modules/import-default-async.js 2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1,6 @@
+import { shouldBe } from "./resources/assert.js";
+import async from "./import-default-async.js"
+
+export default 42;
+
+shouldBe(async, 42);
Added: trunk/JSTests/modules/import-named-async/target.js (0 => 223124)
--- trunk/JSTests/modules/import-named-async/target.js (rev 0)
+++ trunk/JSTests/modules/import-named-async/target.js 2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1 @@
+export let async = 42;
Added: trunk/JSTests/modules/import-named-async-as.js (0 => 223124)
--- trunk/JSTests/modules/import-named-async-as.js (rev 0)
+++ trunk/JSTests/modules/import-named-async-as.js 2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1,6 @@
+import { shouldBe } from "./resources/assert.js";
+import { Cocoa as async } from "./import-named-async-as.js"
+
+export let Cocoa = 42;
+shouldBe(async, 42);
+shouldBe(Cocoa, 42);
Added: trunk/JSTests/modules/import-named-async.js (0 => 223124)
--- trunk/JSTests/modules/import-named-async.js (rev 0)
+++ trunk/JSTests/modules/import-named-async.js 2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1,4 @@
+import { shouldBe } from "./resources/assert.js";
+import { async } from "./import-named-async/target.js"
+
+shouldBe(async, 42);
Added: trunk/JSTests/modules/import-namespace-async.js (0 => 223124)
--- trunk/JSTests/modules/import-namespace-async.js (rev 0)
+++ trunk/JSTests/modules/import-namespace-async.js 2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1,5 @@
+import { shouldBe } from "./resources/assert.js";
+import * as async from "./import-namespace-async.js"
+
+export let Cocoa = 42;
+shouldBe(async.Cocoa, 42);
Modified: trunk/JSTests/test262.yaml (223123 => 223124)
--- trunk/JSTests/test262.yaml 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/JSTests/test262.yaml 2017-10-10 05:53:12 UTC (rev 223124)
@@ -58868,11 +58868,11 @@
- path: test262/test/language/eval-code/indirect/var-env-var-strict.js
cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
- path: test262/test/language/export/escaped-as-export-specifier.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+ cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
- path: test262/test/language/export/escaped-default.js
cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
- path: test262/test/language/export/escaped-from.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+ cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
- path: test262/test/language/expressions/addition/S11.6.1_A1.js
cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
- path: test262/test/language/expressions/addition/S11.6.1_A1.js
@@ -77142,9 +77142,9 @@
- path: test262/test/language/expressions/new.target/escaped-new.js
cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
- path: test262/test/language/expressions/new.target/escaped-target.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+ cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
- path: test262/test/language/expressions/new.target/escaped-target.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+ cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
- path: test262/test/language/expressions/new.target/value-via-call.js
cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
- path: test262/test/language/expressions/new.target/value-via-call.js
@@ -84264,11 +84264,11 @@
- path: test262/test/language/import/dup-bound-names.js
cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
- path: test262/test/language/import/escaped-as-import-specifier.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+ cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
- path: test262/test/language/import/escaped-as-namespace-import.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+ cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
- path: test262/test/language/import/escaped-from.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+ cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
- path: test262/test/language/keywords/ident-ref-break.js
cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], []
- path: test262/test/language/keywords/ident-ref-break.js
@@ -102026,9 +102026,9 @@
- path: test262/test/language/statements/for-await-of/async-gen-dstr-var-obj-ptrn-rest-val-obj.js
cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/propertyHelper.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
- path: test262/test/language/statements/for-await-of/escaped-of.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+ cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
- path: test262/test/language/statements/for-await-of/escaped-of.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+ cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
- path: test262/test/language/statements/for-await-of/let-array-with-newline.js
cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
- path: test262/test/language/statements/for-await-of/let-block-with-newline.js
@@ -104616,9 +104616,9 @@
- path: test262/test/language/statements/for-of/dstr-var-obj-ptrn-rest-val-obj.js
cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/propertyHelper.js"], [:strict]
- path: test262/test/language/statements/for-of/escaped-of.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+ cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
- path: test262/test/language/statements/for-of/escaped-of.js
- cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+ cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
- path: test262/test/language/statements/for-of/float32array-mutate.js
cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
- path: test262/test/language/statements/for-of/float32array-mutate.js
Modified: trunk/Source/_javascript_Core/ChangeLog (223123 => 223124)
--- trunk/Source/_javascript_Core/ChangeLog 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/ChangeLog 2017-10-10 05:53:12 UTC (rev 223124)
@@ -1,3 +1,45 @@
+2017-10-09 Yusuke Suzuki <[email protected]>
+
+ `async` should be able to be used as an imported binding name
+ https://bugs.webkit.org/show_bug.cgi?id=176573
+
+ Reviewed by Saam Barati.
+
+ Previously, we have ASYNC keyword in the parser. This is introduced only for performance,
+ and ECMA262 spec does not categorize "async" to keyword. This makes parser code complicated,
+ since ASYNC should be handled as IDENT. If we missed this ASYNC keyword, we cause a bug.
+ For example, import declaration failed to bind imported binding to the name "async" because
+ the parser considered ASYNC as keyword.
+
+ This patch removes ASYNC keyword from the parser. By carefully handling ASYNC, we can keep
+ the current performance without using this ASYNC keyword.
+
+ We also add `escaped` field to token data since contextual keyword is valid only if it does
+ not contain any escape sequences. We fix bunch of contextual keyword use with this fix too
+ e.g. `of in for-of`. This improves test262 score.
+
+ * parser/Keywords.table:
+ * parser/Lexer.cpp:
+ (JSC::Lexer<LChar>::parseIdentifier):
+ (JSC::Lexer<UChar>::parseIdentifier):
+ (JSC::Lexer<CharacterType>::parseIdentifierSlowCase):
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseStatementListItem):
+ (JSC::Parser<LexerType>::parseForStatement):
+ (JSC::Parser<LexerType>::parseStatement):
+ (JSC::Parser<LexerType>::maybeParseAsyncFunctionDeclarationStatement):
+ (JSC::Parser<LexerType>::parseClass):
+ (JSC::Parser<LexerType>::parseExportDeclaration):
+ (JSC::Parser<LexerType>::parseAssignmentExpression):
+ (JSC::Parser<LexerType>::parseProperty):
+ (JSC::Parser<LexerType>::parsePrimaryExpression):
+ (JSC::Parser<LexerType>::parseMemberExpression):
+ (JSC::Parser<LexerType>::printUnexpectedTokenText):
+ * parser/Parser.h:
+ (JSC::Parser::matchContextualKeyword):
+ * parser/ParserTokens.h:
+ * runtime/CommonIdentifiers.h:
+
2017-10-09 Saam Barati <[email protected]>
We don't need to clearEmptyObjectStructureForPrototype because JSGlobalObject* is part of the cache's key
Modified: trunk/Source/_javascript_Core/parser/Keywords.table (223123 => 223124)
--- trunk/Source/_javascript_Core/parser/Keywords.table 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/Keywords.table 2017-10-10 05:53:12 UTC (rev 223124)
@@ -7,7 +7,6 @@
false FALSETOKEN
# Keywords.
-async ASYNC
await AWAIT
break BREAK
case CASE
Modified: trunk/Source/_javascript_Core/parser/Lexer.cpp (223123 => 223124)
--- trunk/Source/_javascript_Core/parser/Lexer.cpp 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/Lexer.cpp 2017-10-10 05:53:12 UTC (rev 223124)
@@ -935,6 +935,7 @@
template <>
template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<LChar>::parseIdentifier(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
{
+ tokenData->escaped = false;
const ptrdiff_t remaining = m_codeEnd - m_code;
if ((remaining >= maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) {
JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
@@ -959,7 +960,7 @@
return parseIdentifierSlowCase<shouldCreateIdentifier>(tokenData, lexerFlags, strictMode);
}
- const Identifier* ident = 0;
+ const Identifier* ident = nullptr;
if (shouldCreateIdentifier || m_parsingBuiltinFunction) {
int identifierLength = currentSourcePtr() - identifierStart;
@@ -978,7 +979,7 @@
}
tokenData->ident = ident;
} else
- tokenData->ident = 0;
+ tokenData->ident = nullptr;
if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) && !isPrivateName) {
ASSERT(shouldCreateIdentifier);
@@ -999,6 +1000,7 @@
template <>
template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<UChar>::parseIdentifier(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
{
+ tokenData->escaped = false;
const ptrdiff_t remaining = m_codeEnd - m_code;
if ((remaining >= maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) {
JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
@@ -1033,7 +1035,7 @@
if (!(orAllChars & ~0xff))
isAll8Bit = true;
- const Identifier* ident = 0;
+ const Identifier* ident = nullptr;
if (shouldCreateIdentifier || m_parsingBuiltinFunction) {
int identifierLength = currentSourcePtr() - identifierStart;
@@ -1055,7 +1057,7 @@
}
tokenData->ident = ident;
} else
- tokenData->ident = 0;
+ tokenData->ident = nullptr;
if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) && !isPrivateName) {
ASSERT(shouldCreateIdentifier);
@@ -1075,6 +1077,7 @@
template<typename CharacterType> template<bool shouldCreateIdentifier> JSTokenType Lexer<CharacterType>::parseIdentifierSlowCase(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
{
+ tokenData->escaped = true;
auto identifierStart = currentSourcePtr();
bool bufferRequired = false;
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (223123 => 223124)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2017-10-10 05:53:12 UTC (rev 223124)
@@ -657,19 +657,19 @@
case FUNCTION:
result = parseFunctionDeclaration(context);
break;
- case ASYNC: {
- // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case,
- // but could be mistakenly parsed as an AsyncFunctionExpression.
- SavePoint savePoint = createSavePoint();
- next();
- if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) {
- result = parseAsyncFunctionDeclaration(context);
- break;
+ case IDENT:
+ if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+ // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case,
+ // but could be mistakenly parsed as an AsyncFunctionExpression.
+ SavePoint savePoint = createSavePoint();
+ next();
+ if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) {
+ result = parseAsyncFunctionDeclaration(context);
+ break;
+ }
+ restoreSavePoint(savePoint);
}
- restoreSavePoint(savePoint);
FALLTHROUGH;
- }
- case IDENT:
case AWAIT:
case YIELD: {
// This is a convenient place to notice labeled statements
@@ -1349,7 +1349,7 @@
JSTextPosition inLocation = tokenStartPosition();
bool isOfEnumeration = false;
if (!match(INTOKEN)) {
- failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
+ failIfFalse(matchContextualKeyword(m_vm->propertyNames->of), "Expected either 'in' or 'of' in enumeration syntax");
isOfEnumeration = true;
next();
} else {
@@ -1399,7 +1399,7 @@
declsStart = tokenStartPosition();
pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::DeclarationStatement);
declsEnd = lastTokenEndPosition();
- if (pattern && (match(INTOKEN) || (match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of)))
+ if (pattern && (match(INTOKEN) || matchContextualKeyword(m_vm->propertyNames->of)))
goto enumerationLoop;
pattern = TreeDestructuringPattern(0);
restoreSavePoint(savePoint);
@@ -1454,7 +1454,7 @@
failIfFalse(nonLHSCount == m_parserState.nonLHSCount, "Expected a reference on the left hand side of an enumeration statement");
bool isOfEnumeration = false;
if (!match(INTOKEN)) {
- failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
+ failIfFalse(matchContextualKeyword(m_vm->propertyNames->of), "Expected either 'in' or 'of' in enumeration syntax");
isOfEnumeration = true;
next();
} else {
@@ -1899,11 +1899,12 @@
goto identcase;
goto defaultCase;
}
- case ASYNC:
- if (maybeParseAsyncFunctionDeclarationStatement(context, result, parentAllowsFunctionDeclarationAsStatement))
- break;
+ case IDENT:
+ if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+ if (maybeParseAsyncFunctionDeclarationStatement(context, result, parentAllowsFunctionDeclarationAsStatement))
+ break;
+ }
FALLTHROUGH;
- case IDENT:
case AWAIT:
case YIELD: {
identcase:
@@ -1988,7 +1989,7 @@
template <typename LexerType>
template <class TreeBuilder> bool Parser<LexerType>::maybeParseAsyncFunctionDeclarationStatement(TreeBuilder& context, TreeStatement& result, bool parentAllowsFunctionDeclarationAsStatement)
{
- ASSERT(match(ASYNC));
+ ASSERT(matchContextualKeyword(m_vm->propertyNames->async));
SavePoint savePoint = createSavePoint();
next();
if (match(FUNCTION) && !m_lexer->prevTerminator()) {
@@ -2835,20 +2836,21 @@
ASSERT(ident);
next();
break;
- case ASYNC:
- if (!isGeneratorMethodParseMode(parseMode) && !isAsyncMethodParseMode(parseMode)) {
- ident = m_token.m_data.ident;
- next();
- if (match(OPENPAREN) || match(COLON) || match(EQUAL) || m_lexer->prevTerminator())
- break;
- if (Options::useAsyncIterator() && UNLIKELY(consume(TIMES)))
- parseMode = SourceParseMode::AsyncGeneratorWrapperMethodMode;
- else
- parseMode = SourceParseMode::AsyncMethodMode;
- goto parseMethod;
+ case IDENT:
+ if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+ if (!isGeneratorMethodParseMode(parseMode) && !isAsyncMethodParseMode(parseMode)) {
+ ident = m_token.m_data.ident;
+ next();
+ if (match(OPENPAREN) || match(COLON) || match(EQUAL) || m_lexer->prevTerminator())
+ break;
+ if (Options::useAsyncIterator() && UNLIKELY(consume(TIMES)))
+ parseMode = SourceParseMode::AsyncGeneratorWrapperMethodMode;
+ else
+ parseMode = SourceParseMode::AsyncMethodMode;
+ goto parseMethod;
+ }
}
FALLTHROUGH;
- case IDENT:
case AWAIT:
ident = m_token.m_data.ident;
ASSERT(ident);
@@ -3369,7 +3371,7 @@
if (match(IDENT))
localName = m_token.m_data.ident;
restoreSavePoint(savePoint);
- } else if (match(ASYNC)) {
+ } else if (matchContextualKeyword(m_vm->propertyNames->async)) {
SavePoint savePoint = createSavePoint();
next();
if (match(FUNCTION) && !m_lexer->prevTerminator()) {
@@ -3393,7 +3395,7 @@
} else if (match(CLASSTOKEN)) {
result = parseClassDeclaration(context, ExportType::NotExported, DeclarationDefaultContext::ExportDefault);
} else {
- ASSERT(match(ASYNC));
+ ASSERT(matchContextualKeyword(m_vm->propertyNames->async));
next();
DepthManager statementDepth(&m_statementDepth);
m_statementDepth = 1;
@@ -3514,15 +3516,16 @@
result = parseClassDeclaration(context, ExportType::Exported);
break;
- case ASYNC: {
- next();
- semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator");
- DepthManager statementDepth(&m_statementDepth);
- m_statementDepth = 1;
- result = parseAsyncFunctionDeclaration(context, ExportType::Exported);
- break;
- }
-
+ case IDENT:
+ if (*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped) {
+ next();
+ semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator");
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth = 1;
+ result = parseAsyncFunctionDeclaration(context, ExportType::Exported);
+ break;
+ }
+ FALLTHROUGH;
default:
failWithMessage("Expected either a declaration or a variable statement");
break;
@@ -3620,7 +3623,7 @@
restoreSavePoint(savePoint);
bool isAsyncArrow = false;
if (UNLIKELY(classifier.indicatesPossibleAsyncArrowFunction())) {
- ASSERT(match(ASYNC));
+ ASSERT(matchContextualKeyword(m_vm->propertyNames->async));
next();
isAsyncArrow = !m_lexer->prevTerminator();
}
@@ -3888,26 +3891,27 @@
parseProperty:
switch (m_token.m_type) {
- case ASYNC:
- if (parseMode == SourceParseMode::MethodMode) {
- SavePoint savePoint = createSavePoint();
- next();
+ case IDENT:
+ if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+ if (parseMode == SourceParseMode::MethodMode) {
+ SavePoint savePoint = createSavePoint();
+ next();
- if (match(COLON) || match(OPENPAREN) || match(COMMA) || match(CLOSEBRACE)) {
- restoreSavePoint(savePoint);
- wasIdent = true;
- goto namedProperty;
+ if (match(COLON) || match(OPENPAREN) || match(COMMA) || match(CLOSEBRACE)) {
+ restoreSavePoint(savePoint);
+ wasIdent = true;
+ goto namedProperty;
+ }
+
+ failIfTrue(m_lexer->prevTerminator(), "Expected a property name following keyword 'async'");
+ if (Options::useAsyncIterator() && UNLIKELY(consume(TIMES)))
+ parseMode = SourceParseMode::AsyncGeneratorWrapperMethodMode;
+ else
+ parseMode = SourceParseMode::AsyncMethodMode;
+ goto parseProperty;
}
-
- failIfTrue(m_lexer->prevTerminator(), "Expected a property name following keyword 'async'");
- if (Options::useAsyncIterator() && UNLIKELY(consume(TIMES)))
- parseMode = SourceParseMode::AsyncGeneratorWrapperMethodMode;
- else
- parseMode = SourceParseMode::AsyncMethodMode;
- goto parseProperty;
}
FALLTHROUGH;
- case IDENT:
case YIELD:
case AWAIT:
wasIdent = true;
@@ -4448,22 +4452,22 @@
return parseAwaitExpression(context);
goto identifierExpression;
- case ASYNC: {
- JSTextPosition start = tokenStartPosition();
- const Identifier* ident = m_token.m_data.ident;
- JSTokenLocation location(tokenLocation());
- next();
- if (match(FUNCTION) && !m_lexer->prevTerminator())
- return parseAsyncFunctionExpression(context);
+ case IDENT: {
+ if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+ JSTextPosition start = tokenStartPosition();
+ const Identifier* ident = m_token.m_data.ident;
+ JSTokenLocation location(tokenLocation());
+ next();
+ if (match(FUNCTION) && !m_lexer->prevTerminator())
+ return parseAsyncFunctionExpression(context);
- // Avoid using variable if it is an arrow function parameter
- if (UNLIKELY(match(ARROWFUNCTION)))
- return 0;
+ // Avoid using variable if it is an arrow function parameter
+ if (UNLIKELY(match(ARROWFUNCTION)))
+ return 0;
- const bool isEval = false;
- return createResolveAndUseVariable(context, ident, isEval, start, location);
- }
- case IDENT: {
+ const bool isEval = false;
+ return createResolveAndUseVariable(context, ident, isEval, start, location);
+ }
identifierExpression:
JSTextPosition start = tokenStartPosition();
const Identifier* ident = m_token.m_data.ident;
@@ -4649,23 +4653,21 @@
bool baseIsNewTarget = false;
if (newCount && match(DOT)) {
next();
- if (match(IDENT)) {
- const Identifier* ident = m_token.m_data.ident;
- if (m_vm->propertyNames->target == *ident) {
- ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
- semanticFailIfFalse(currentScope()->isFunction() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is only valid inside functions");
- baseIsNewTarget = true;
- if (currentScope()->isArrowFunction()) {
- semanticFailIfFalse(!closestOrdinaryFunctionScope->isGlobalCodeScope() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is not valid inside arrow functions in global code");
- currentScope()->setInnerArrowFunctionUsesNewTarget();
- }
- base = context.createNewTargetExpr(location);
- newCount--;
- next();
- } else
- failWithMessage("\"new.\" can only followed with target");
- } else
+ if (matchContextualKeyword(m_vm->propertyNames->target)) {
+ ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
+ semanticFailIfFalse(currentScope()->isFunction() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is only valid inside functions");
+ baseIsNewTarget = true;
+ if (currentScope()->isArrowFunction()) {
+ semanticFailIfFalse(!closestOrdinaryFunctionScope->isGlobalCodeScope() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is not valid inside arrow functions in global code");
+ currentScope()->setInnerArrowFunctionUsesNewTarget();
+ }
+ base = context.createNewTargetExpr(location);
+ newCount--;
+ next();
+ } else {
+ failIfTrue(match(IDENT), "\"new.\" can only followed with target");
failDueToUnexpectedToken();
+ }
}
bool baseIsAsyncKeyword = false;
@@ -4691,17 +4693,16 @@
next();
JSTextPosition expressionEnd = lastTokenEndPosition();
if (consume(DOT)) {
- if (!match(IDENT))
+ if (matchContextualKeyword(m_vm->propertyNames->builtinNames().metaPublicName())) {
+ semanticFailIfFalse(m_scriptMode == JSParserScriptMode::Module, "import.meta is only valid inside modules");
+
+ JSTokenLocation location(tokenLocation());
+ base = createResolveAndUseVariable(context, &m_vm->propertyNames->builtinNames().metaPrivateName(), false, expressionStart, location);
+ next();
+ } else {
+ failIfTrue(match(IDENT), "\"import.\" can only followed with meta");
failDueToUnexpectedToken();
- const Identifier* ident = m_token.m_data.ident;
- if (m_vm->propertyNames->builtinNames().metaPublicName() != *ident)
- failWithMessage("\"import.\" can only followed with meta");
-
- semanticFailIfFalse(m_scriptMode == JSParserScriptMode::Module, "import.meta is only valid inside modules");
-
- JSTokenLocation location(tokenLocation());
- base = createResolveAndUseVariable(context, &m_vm->propertyNames->builtinNames().metaPrivateName(), false, expressionStart, location);
- next();
+ }
} else {
consumeOrFail(OPENPAREN, "import call expects exactly one argument");
TreeExpression expr = parseAssignmentExpression(context);
@@ -4710,7 +4711,7 @@
base = context.createImportExpr(location, expr, expressionStart, expressionEnd, lastTokenEndPosition());
}
} else if (!baseIsNewTarget) {
- const bool isAsync = match(ASYNC);
+ const bool isAsync = matchContextualKeyword(m_vm->propertyNames->async);
base = parsePrimaryExpression(context);
failIfFalse(base, "Cannot parse base _expression_");
@@ -5067,7 +5068,6 @@
out.print("Invalid private name '", getToken(), "'");
return;
- case ASYNC:
case AWAIT:
case IDENT:
out.print("Unexpected identifier '", getToken(), "'");
Modified: trunk/Source/_javascript_Core/parser/Parser.h (223123 => 223124)
--- trunk/Source/_javascript_Core/parser/Parser.h 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/Parser.h 2017-10-10 05:53:12 UTC (rev 223124)
@@ -1370,7 +1370,7 @@
ALWAYS_INLINE bool matchContextualKeyword(const Identifier& identifier)
{
- return m_token.m_type == IDENT && *m_token.m_data.ident == identifier;
+ return m_token.m_type == IDENT && *m_token.m_data.ident == identifier && !m_token.m_data.escaped;
}
ALWAYS_INLINE bool matchIdentifierOrKeyword()
Modified: trunk/Source/_javascript_Core/parser/ParserTokens.h (223123 => 223124)
--- trunk/Source/_javascript_Core/parser/ParserTokens.h 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/ParserTokens.h 2017-10-10 05:53:12 UTC (rev 223124)
@@ -93,10 +93,9 @@
LET,
YIELD,
AWAIT,
- ASYNC,
FirstContextualKeywordToken = LET,
- LastContextualKeywordToken = ASYNC,
+ LastContextualKeywordToken = AWAIT,
FirstSafeContextualKeywordToken = AWAIT,
LastSafeContextualKeywordToken = LastContextualKeywordToken,
@@ -214,8 +213,11 @@
uint32_t lineStartOffset;
};
double doubleValue;
- const Identifier* ident;
struct {
+ const Identifier* ident;
+ bool escaped;
+ };
+ struct {
const Identifier* cooked;
const Identifier* raw;
bool isTail;
Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (223123 => 223124)
--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h 2017-10-10 05:53:12 UTC (rev 223124)
@@ -79,6 +79,7 @@
macro(arguments) \
macro(as) \
macro(assign) \
+ macro(async) \
macro(back) \
macro(bind) \
macro(buffer) \
@@ -219,7 +220,6 @@
macro(year)
#define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
- macro(async) \
macro(await) \
macro(break) \
macro(case) \