2727#include " src/runtime/runtime.h"
2828#include " src/strings/char-predicates-inl.h"
2929#include " src/strings/string-stream.h"
30+ #include " src/strings/unicode-inl.h"
3031#include " src/tracing/trace-event.h"
3132#include " src/zone/zone-list-inl.h"
3233
@@ -1071,7 +1072,8 @@ const AstRawString* Parser::ParseModuleSpecifier() {
10711072}
10721073
10731074ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause (
1074- Scanner::Location* reserved_loc) {
1075+ Scanner::Location* reserved_loc,
1076+ Scanner::Location* string_literal_local_name_loc) {
10751077 // ExportClause :
10761078 // '{' '}'
10771079 // '{' ExportsList '}'
@@ -1084,30 +1086,40 @@ ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause(
10841086 // ExportSpecifier :
10851087 // IdentifierName
10861088 // IdentifierName 'as' IdentifierName
1089+ // IdentifierName 'as' ModuleExportName
1090+ // ModuleExportName
1091+ // ModuleExportName 'as' ModuleExportName
1092+ //
1093+ // ModuleExportName :
1094+ // StringLiteral
10871095 ZoneChunkList<ExportClauseData>* export_data =
10881096 zone ()->New <ZoneChunkList<ExportClauseData>>(zone ());
10891097
10901098 Expect (Token::LBRACE);
10911099
10921100 Token::Value name_tok;
10931101 while ((name_tok = peek ()) != Token::RBRACE) {
1094- // Keep track of the first reserved word encountered in case our
1095- // caller needs to report an error.
1096- if (!reserved_loc->IsValid () &&
1097- !Token::IsValidIdentifier (name_tok, LanguageMode::kStrict , false ,
1098- flags ().is_module ())) {
1102+ const AstRawString* local_name = ParseExportSpecifierName ();
1103+ if (!string_literal_local_name_loc->IsValid () &&
1104+ name_tok == Token::STRING) {
1105+ // Keep track of the first string literal local name exported for error
1106+ // reporting. These must be followed by a 'from' clause.
1107+ *string_literal_local_name_loc = scanner ()->location ();
1108+ } else if (!reserved_loc->IsValid () &&
1109+ !Token::IsValidIdentifier (name_tok, LanguageMode::kStrict , false ,
1110+ flags ().is_module ())) {
1111+ // Keep track of the first reserved word encountered in case our
1112+ // caller needs to report an error.
10991113 *reserved_loc = scanner ()->location ();
11001114 }
1101- const AstRawString* local_name = ParsePropertyName ();
1102- const AstRawString* export_name = nullptr ;
1115+ const AstRawString* export_name;
11031116 Scanner::Location location = scanner ()->location ();
11041117 if (CheckContextualKeyword (ast_value_factory ()->as_string ())) {
1105- export_name = ParsePropertyName ();
1118+ export_name = ParseExportSpecifierName ();
11061119 // Set the location to the whole "a as b" string, so that it makes sense
11071120 // both for errors due to "a" and for errors due to "b".
11081121 location.end_pos = scanner ()->location ().end_pos ;
1109- }
1110- if (export_name == nullptr ) {
1122+ } else {
11111123 export_name = local_name;
11121124 }
11131125 export_data->push_back ({export_name, local_name, location});
@@ -1122,6 +1134,31 @@ ZoneChunkList<Parser::ExportClauseData>* Parser::ParseExportClause(
11221134 return export_data;
11231135}
11241136
1137+ const AstRawString* Parser::ParseExportSpecifierName () {
1138+ Token::Value next = Next ();
1139+
1140+ // IdentifierName
1141+ if (V8_LIKELY (Token::IsPropertyName (next))) {
1142+ return GetSymbol ();
1143+ }
1144+
1145+ // ModuleExportName
1146+ if (next == Token::STRING) {
1147+ const AstRawString* export_name = GetSymbol ();
1148+ if (V8_LIKELY (export_name->is_one_byte ())) return export_name;
1149+ if (!unibrow::Utf16::HasUnpairedSurrogate (
1150+ reinterpret_cast <const uint16_t *>(export_name->raw_data ()),
1151+ export_name->length ())) {
1152+ return export_name;
1153+ }
1154+ ReportMessage (MessageTemplate::kInvalidModuleExportName );
1155+ return EmptyIdentifierString ();
1156+ }
1157+
1158+ ReportUnexpectedToken (next);
1159+ return EmptyIdentifierString ();
1160+ }
1161+
11251162ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports (int pos) {
11261163 // NamedImports :
11271164 // '{' '}'
@@ -1135,12 +1172,13 @@ ZonePtrList<const Parser::NamedImport>* Parser::ParseNamedImports(int pos) {
11351172 // ImportSpecifier :
11361173 // BindingIdentifier
11371174 // IdentifierName 'as' BindingIdentifier
1175+ // ModuleExportName 'as' BindingIdentifier
11381176
11391177 Expect (Token::LBRACE);
11401178
11411179 auto result = zone ()->New <ZonePtrList<const NamedImport>>(1 , zone ());
11421180 while (peek () != Token::RBRACE) {
1143- const AstRawString* import_name = ParsePropertyName ();
1181+ const AstRawString* import_name = ParseExportSpecifierName ();
11441182 const AstRawString* local_name = import_name;
11451183 Scanner::Location location = scanner ()->location ();
11461184 // In the presence of 'as', the left-side of the 'as' can
@@ -1450,9 +1488,14 @@ void Parser::ParseExportStar() {
14501488 // export * as x from "...";
14511489 // ~>
14521490 // import * as .x from "..."; export {.x as x};
1491+ //
1492+ // Note that the desugared internal namespace export name (.x above) will
1493+ // never conflict with a string literal export name, as literal string export
1494+ // names in local name positions (i.e. left of 'as' or in a clause without
1495+ // 'as') are disallowed without a following 'from' clause.
14531496
14541497 ExpectContextualKeyword (ast_value_factory ()->as_string ());
1455- const AstRawString* export_name = ParsePropertyName ();
1498+ const AstRawString* export_name = ParseExportSpecifierName ();
14561499 Scanner::Location export_name_loc = scanner ()->location ();
14571500 const AstRawString* local_name = NextInternalNamespaceExportName ();
14581501 Scanner::Location local_name_loc = Scanner::Location::invalid ();
@@ -1478,12 +1521,18 @@ Statement* Parser::ParseExportDeclaration() {
14781521 // 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier ';'
14791522 // 'export' '*' 'as' IdentifierName 'from' ModuleSpecifier
14801523 // [no LineTerminator here] AssertClause ';'
1524+ // 'export' '*' 'as' ModuleExportName 'from' ModuleSpecifier ';'
1525+ // 'export' '*' 'as' ModuleExportName 'from' ModuleSpecifier ';'
1526+ // [no LineTerminator here] AssertClause ';'
14811527 // 'export' ExportClause ('from' ModuleSpecifier)? ';'
14821528 // 'export' ExportClause ('from' ModuleSpecifier [no LineTerminator here]
14831529 // AssertClause)? ';'
14841530 // 'export' VariableStatement
14851531 // 'export' Declaration
14861532 // 'export' 'default' ... (handled in ParseExportDefault)
1533+ //
1534+ // ModuleExportName :
1535+ // StringLiteral
14871536
14881537 Expect (Token::EXPORT);
14891538 Statement* result = nullptr ;
@@ -1510,8 +1559,10 @@ Statement* Parser::ParseExportDeclaration() {
15101559 // encountered, and then throw a SyntaxError if we are in the
15111560 // non-FromClause case.
15121561 Scanner::Location reserved_loc = Scanner::Location::invalid ();
1562+ Scanner::Location string_literal_local_name_loc =
1563+ Scanner::Location::invalid ();
15131564 ZoneChunkList<ExportClauseData>* export_data =
1514- ParseExportClause (&reserved_loc);
1565+ ParseExportClause (&reserved_loc, &string_literal_local_name_loc );
15151566 if (CheckContextualKeyword (ast_value_factory ()->from_string ())) {
15161567 Scanner::Location specifier_loc = scanner ()->peek_location ();
15171568 const AstRawString* module_specifier = ParseModuleSpecifier ();
@@ -1533,6 +1584,10 @@ Statement* Parser::ParseExportDeclaration() {
15331584 // No FromClause, so reserved words are invalid in ExportClause.
15341585 ReportMessageAt (reserved_loc, MessageTemplate::kUnexpectedReserved );
15351586 return nullptr ;
1587+ } else if (string_literal_local_name_loc.IsValid ()) {
1588+ ReportMessageAt (string_literal_local_name_loc,
1589+ MessageTemplate::kModuleExportNameWithoutFromClause );
1590+ return nullptr ;
15361591 }
15371592
15381593 ExpectSemicolon ();
0 commit comments