diff --git a/ets2panda/ir/module/importDeclaration.h b/ets2panda/ir/module/importDeclaration.h index 2da6374989c9541c10731ccc600647b9fbf5dcf1..c22360ba7bd893bf5f3c09ea0c5ad536e9a5f806 100644 --- a/ets2panda/ir/module/importDeclaration.h +++ b/ets2panda/ir/module/importDeclaration.h @@ -22,6 +22,7 @@ namespace ark::es2panda::ir { class StringLiteral; enum class ImportKinds { ALL, TYPES }; +using ExportKinds = ImportKinds; class ImportDeclaration : public Statement { public: diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index e4b25915ea843bfd0b9febf3a5945ebebd39ad08..d1a18c47d0488c2234106a5dd7af184c0e3ace98 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -1173,9 +1173,36 @@ ir::Statement *ETSParser::ParseDefaultIfSingleExport(ir::ModifierFlags modifiers return !isSelectiveExport ? ParseSingleExport(modifiers) : nullptr; } -ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::ModifierFlags modifiers) +ir::ExportNamedDeclaration *ETSParser::CreateExportNamedDeclaration(const SpecifiersInfo &specs, + const ir::ModifierFlags &modifiers, + const lexer::SourcePosition &startLoc) { const size_t exportDefaultMaxSize = 1; + ArenaVector exports(Allocator()->Adapter()); + auto endLoc = startLoc; + for (auto spec : specs.result) { + exports.emplace_back(AllocNode(spec->Local(), spec->Imported())); + endLoc = endLoc.index < spec->End().index ? spec->End() : endLoc; + } + + if (specs.resultExportDefault.size() > exportDefaultMaxSize) { + LogError(diagnostic::EXPORT_DEFAULT_WITH_MUPLTIPLE_SPECIFIER); + } + for (auto spec : specs.resultExportDefault) { + exports.emplace_back(spec); + endLoc = endLoc.index < spec->End().index ? spec->End() : endLoc; + } + + auto result = AllocNode(Allocator(), static_cast(nullptr), + std::move(exports)); + ES2PANDA_ASSERT(result != nullptr); + result->AddModifier(modifiers); + result->SetRange({startLoc, endLoc}); + return result; +} + +ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::ModifierFlags modifiers) +{ if (!InAmbientContext() && (GetContext().Status() & ParserStatus::IN_NAMESPACE) != 0) { LogError(diagnostic::EXPORT_IN_NAMESPACE); } @@ -1196,32 +1223,14 @@ ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::Modifi // export * as xxx from yyy, the xxx should have export flag to pass the following check. specifiers[0]->AddModifier(ir::ModifierFlags::EXPORT); } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - auto specs = ParseNamedSpecifiers(); + ir::ExportKinds exportKind = + (modifiers & ir::ModifierFlags::EXPORT_TYPE) != 0U ? ir::ExportKinds::TYPES : ir::ExportKinds::ALL; + auto specs = ParseNamedSpecifiers(exportKind); if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM) { specifiers = util::Helpers::ConvertVector(specs.result); } else { - ArenaVector exports(Allocator()->Adapter()); - auto endLoc = startLoc; - for (auto spec : specs.result) { - exports.emplace_back(AllocNode(spec->Local(), spec->Imported())); - endLoc = endLoc.index < spec->End().index ? spec->End() : endLoc; - } - - if (specs.resultExportDefault.size() > exportDefaultMaxSize) { - LogError(diagnostic::EXPORT_DEFAULT_WITH_MUPLTIPLE_SPECIFIER); - } - for (auto spec : specs.resultExportDefault) { - exports.emplace_back(spec); - endLoc = endLoc.index < spec->End().index ? spec->End() : endLoc; - } - - auto result = AllocNode(Allocator(), static_cast(nullptr), - std::move(exports)); - ES2PANDA_ASSERT(result != nullptr); - result->AddModifier(modifiers); - result->SetRange({startLoc, endLoc}); - return result; + return CreateExportNamedDeclaration(specs, modifiers, startLoc); } } else { return ParseSingleExport(modifiers); @@ -1343,7 +1352,7 @@ ArenaVector ETSParser::ParseImportDeclarations() if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) { ParseNameSpaceSpecifier(&specifiers); } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - auto specs = ParseNamedSpecifiers(); + auto specs = ParseNamedSpecifiers(importKind); specifiers = util::Helpers::ConvertVector(specs.result); defaultSpecifiers = util::Helpers::ConvertVector(specs.resultDefault); } else { @@ -1526,7 +1535,7 @@ bool ETSParser::ParseNamedSpecifiesImport(ArenaVector *re return true; } -SpecifiersInfo ETSParser::ParseNamedSpecifiers() +SpecifiersInfo ETSParser::ParseNamedSpecifiers(const ir::ImportKinds importKind) { // NOTE(user): handle qualifiedName in file bindings: qualifiedName '.' '*' if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) { @@ -1551,18 +1560,23 @@ SpecifiersInfo ETSParser::ParseNamedSpecifiers() ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT, - [this, &result, &resultDefault, &resultExportDefault, &fileName]() { + [this, &result, &resultDefault, &resultExportDefault, &fileName, &importKind](bool &typeKeywordOnSpecifier) { + if (typeKeywordOnSpecifier && importKind == ir::ImportKinds::TYPES) { + LogError(diagnostic::REPEATED_TYPE_KEYWORD); + } if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) { LogError(diagnostic::ASTERIKS_NOT_ALLOWED_IN_SELECTIVE_BINDING); } if (!IsDefaultImport()) { + typeKeywordOnSpecifier = false; return ParseNamedSpecifiesImport(&result, &resultExportDefault, fileName); } ParseNamedSpecifiesDefaultImport(&resultDefault, fileName); + typeKeywordOnSpecifier = false; return true; }, - nullptr, true); + nullptr, ParseListOptions::ALLOW_TRAILING_SEP | ParseListOptions::ALLOW_TYPE_KEYWORD); return {result, resultDefault, resultExportDefault}; } @@ -1623,7 +1637,10 @@ ir::AstNode *ETSParser::ParseImportDefaultSpecifier(ArenaVector * if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) { ParseNameSpaceSpecifier(specifiers); } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - auto specs = ParseNamedSpecifiers(); + const ir::ImportKinds importKind = Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_TYPE) + ? ir::ImportKinds::TYPES + : ir::ImportKinds::ALL; + auto specs = ParseNamedSpecifiers(importKind); auto importSpecifiers = util::Helpers::ConvertVector(specs.result); specifiers->insert(specifiers->end(), importSpecifiers.begin(), importSpecifiers.end()); } @@ -2328,7 +2345,8 @@ ir::OverloadDeclaration *ETSParser::ParseOverloadDeclaration(ir::ModifierFlags m ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::NONE, - [this, &overloads, overloadDef]() { return ParseOverloadListElement(overloads, overloadDef); }, &endLoc, true); + [this, &overloads, overloadDef](bool &) { return ParseOverloadListElement(overloads, overloadDef); }, &endLoc, + ParseListOptions::ALLOW_TRAILING_SEP); overloadDef->SetOverloadedList(std::move(overloads)); overloadDef->SetRange({startLoc, endLoc}); for (ir::Expression *overloadedName : overloadDef->OverloadedList()) { diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 66ddcc044e8e2c478bf790a9923d043e37cef6ec..e4fc7f93f23adfe3843b22622d90eb3faccb01ec 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -202,7 +202,7 @@ private: bool ParseNamedSpecifiesImport(ArenaVector *result, ArenaVector *resultExportDefault, const std::string &fileName); - SpecifiersInfo ParseNamedSpecifiers(); + SpecifiersInfo ParseNamedSpecifiers(const ir::ImportKinds importKind); ir::ExportNamedDeclaration *ParseSingleExport(ir::ModifierFlags modifiers); ir::ExportNamedDeclaration *ParseSingleExportForAnonymousConst(ir::ModifierFlags modifiers); ArenaVector ParseImportDeclarations(); @@ -301,6 +301,9 @@ private: ir::Statement *ParseTryStatement() override; ir::Statement *ParseDebuggerStatement() override; ir::Statement *ParseDefaultIfSingleExport(ir::ModifierFlags modifiers); + ir::ExportNamedDeclaration *CreateExportNamedDeclaration(const SpecifiersInfo &specs, + const ir::ModifierFlags &modifiers, + const lexer::SourcePosition &startLoc); ir::Statement *ParseExport(lexer::SourcePosition startLoc, ir::ModifierFlags modifiers); ir::Statement *ParseImportDeclaration(StatementParsingFlags flags) override; ir::Statement *ParseExportDeclaration(StatementParsingFlags flags) override; diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp index f9d858dbc79b249ffe63e527ea2fae7a0c9e30e8..ca48d702b3083831abd56f9894880eb78f05f2af 100644 --- a/ets2panda/parser/ETSparserClasses.cpp +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -565,7 +565,8 @@ ir::OverloadDeclaration *ETSParser::ParseClassOverloadDeclaration(ir::ModifierFl ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::NONE, - [this, &overloads, overloadDef]() { return ParseOverloadListElement(overloads, overloadDef); }, &endLoc, true); + [this, &overloads, overloadDef](bool &) { return ParseOverloadListElement(overloads, overloadDef); }, &endLoc, + ParseListOptions::ALLOW_TRAILING_SEP); overloadDef->SetOverloadedList(std::move(overloads)); overloadDef->SetRange({startLoc, endLoc}); ValidateOverloadList(overloadDef->OverloadedList()); @@ -1122,7 +1123,8 @@ ir::OverloadDeclaration *ETSParser::ParseInterfaceOverload(ir::ModifierFlags mod ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::NONE, - [this, &overloads, overloadDef]() { return ParseOverloadListElement(overloads, overloadDef); }, &endLoc, true); + [this, &overloads, overloadDef](bool &) { return ParseOverloadListElement(overloads, overloadDef); }, &endLoc, + ParseListOptions::ALLOW_TRAILING_SEP); overloadDef->SetOverloadedList(std::move(overloads)); overloadDef->SetRange({startLoc, endLoc}); diff --git a/ets2panda/parser/ETSparserEnums.cpp b/ets2panda/parser/ETSparserEnums.cpp index 44434862cb24624894067944521b420157710561..b2eadae5ea74a1391395c47c4ce0ee26e6367c2c 100644 --- a/ets2panda/parser/ETSparserEnums.cpp +++ b/ets2panda/parser/ETSparserEnums.cpp @@ -246,7 +246,7 @@ lexer::SourcePosition ETSParser::ParseEnumMember(ArenaVector &mem ir::Expression *currentNumberExpr = AllocNode(lexer::Number(0)); // Lambda to parse enum member (maybe with initializer) - auto const parseMember = [this, &members, ¤tNumberExpr]() { + auto const parseMember = [this, &members, ¤tNumberExpr](bool &) { auto *const ident = ExpectIdentifier(false, true); ir::Expression *ordinal; @@ -285,7 +285,7 @@ lexer::SourcePosition ETSParser::ParseEnumMember(ArenaVector &mem lexer::SourcePosition enumEnd; ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT, parseMember, &enumEnd, - true); + ParseListOptions::ALLOW_TRAILING_SEP); return enumEnd; } diff --git a/ets2panda/parser/ETSparserExpressions.cpp b/ets2panda/parser/ETSparserExpressions.cpp index f1cd269a67a4657c5c4fdef72b7a06fd81b8256c..8733d9fc98c63f7cb69b4f35b1d4797a02cf8e7f 100644 --- a/ets2panda/parser/ETSparserExpressions.cpp +++ b/ets2panda/parser/ETSparserExpressions.cpp @@ -683,7 +683,7 @@ void ETSParser::ParseArgumentsNewExpression(ArenaVector &argum ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, lexer::NextTokenFlags::NONE, - [this, &arguments]() { + [this, &arguments](bool &) { ir::Expression *argument = Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD ? ParseSpreadElement(ExpressionParseFlags::POTENTIALLY_IN_PATTERN) @@ -695,7 +695,7 @@ void ETSParser::ParseArgumentsNewExpression(ArenaVector &argum arguments.push_back(argument); return true; }, - &endLoc, true); + &endLoc, ParseListOptions::ALLOW_TRAILING_SEP); } } diff --git a/ets2panda/parser/ETSparserStatements.cpp b/ets2panda/parser/ETSparserStatements.cpp index bb7d3f6db0e6f009aa5414a9d115b164e3732e4d..7d665ac913b45d709d97a0d72da4ff6d64655024 100644 --- a/ets2panda/parser/ETSparserStatements.cpp +++ b/ets2panda/parser/ETSparserStatements.cpp @@ -189,8 +189,7 @@ ir::Statement *ETSParser::ParseTopLevelDeclStatement(StatementParsingFlags flags } ir::Statement *result = nullptr; - auto token = Lexer()->GetToken(); - switch (token.Type()) { + switch (Lexer()->GetToken().Type()) { case lexer::TokenType::KEYW_FUNCTION: { result = ParseFunctionDeclaration(false, memberModifiers); ES2PANDA_ASSERT(result != nullptr); diff --git a/ets2panda/parser/ETSparserTypes.cpp b/ets2panda/parser/ETSparserTypes.cpp index cef870f6170d8a578b15479571850a4217654cb5..c9c96f75d9b93fba8d0d342e8355081b8412d9b8 100644 --- a/ets2panda/parser/ETSparserTypes.cpp +++ b/ets2panda/parser/ETSparserTypes.cpp @@ -250,7 +250,7 @@ ir::TypeNode *ETSParser::ParseETSTupleType(TypeAnnotationParsingOptions *const o ArenaVector tupleTypeList(Allocator()->Adapter()); auto *const tupleType = AllocNode(Allocator()); - auto parseElem = [this, options, &tupleTypeList, &tupleType]() { + auto parseElem = [this, options, &tupleTypeList, &tupleType](bool &) { auto *const currentTypeAnnotation = ParseTypeAnnotation(options); if (currentTypeAnnotation == nullptr) { // Error processing. Lexer()->NextToken(); @@ -264,7 +264,8 @@ ir::TypeNode *ETSParser::ParseETSTupleType(TypeAnnotationParsingOptions *const o }; lexer::SourcePosition endLoc; - ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET, lexer::NextTokenFlags::NONE, parseElem, &endLoc, true); + ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET, lexer::NextTokenFlags::NONE, parseElem, &endLoc, + ParseListOptions::ALLOW_TRAILING_SEP); ES2PANDA_ASSERT(tupleType != nullptr); tupleType->SetTypeAnnotationsList(std::move(tupleTypeList)); diff --git a/ets2panda/parser/TypedParser.cpp b/ets2panda/parser/TypedParser.cpp index 64dc2383bc7e5e12726cc4b7c49469ab91c1a4be..d7a1834407264781a3745bca70895a5f129c55bb 100644 --- a/ets2panda/parser/TypedParser.cpp +++ b/ets2panda/parser/TypedParser.cpp @@ -669,7 +669,7 @@ ir::TSEnumDeclaration *TypedParser::ParseEnumMembers(ir::Identifier *key, const lexer::SourcePosition endLoc; ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT, - [this, &members]() { + [this, &members](bool &) { ir::Expression *memberKey = nullptr; if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { @@ -700,7 +700,7 @@ ir::TSEnumDeclaration *TypedParser::ParseEnumMembers(ir::Identifier *key, const members.push_back(member); return true; }, - &endLoc, true); + &endLoc, ParseListOptions::ALLOW_TRAILING_SEP); auto *enumDeclaration = AllocNode(Allocator(), key, std::move(members), diff --git a/ets2panda/parser/expressionParser.cpp b/ets2panda/parser/expressionParser.cpp index 6d111ce34ace4c3348ba058e12bf2ad0e88774d0..57fae67e1eb1a3e9cd2a9076f48d6119f975f43f 100644 --- a/ets2panda/parser/expressionParser.cpp +++ b/ets2panda/parser/expressionParser.cpp @@ -182,7 +182,7 @@ ir::ArrayExpression *ParserImpl::ParseArrayExpression(ExpressionParseFlags flags lexer::SourcePosition endLoc; ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET, lexer::NextTokenFlags::NONE, - [this, inPattern, startLoc, allowOmitted, &elements, &trailingComma]() { + [this, inPattern, startLoc, allowOmitted, &elements, &trailingComma](bool &) { if (allowOmitted && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { auto *omitted = AllocNode(); omitted->SetRange(lexer_->GetToken().Loc()); @@ -204,7 +204,7 @@ ir::ArrayExpression *ParserImpl::ParseArrayExpression(ExpressionParseFlags flags trailingComma = ParseArrayExpressionRightBracketHelper(containsRest, startLoc); return true; }, - &endLoc, true); + &endLoc, ParseListOptions::ALLOW_TRAILING_SEP); auto nodeType = inPattern ? ir::AstNodeType::ARRAY_PATTERN : ir::AstNodeType::ARRAY_EXPRESSION; auto *arrayExpressionNode = @@ -806,7 +806,7 @@ ir::Expression *ParserImpl::ParseNewExpression() // parse argument part of NewExpression ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, lexer::NextTokenFlags::NONE, - [this, &arguments]() { + [this, &arguments](bool &) { ir::Expression *argument = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { @@ -817,7 +817,7 @@ ir::Expression *ParserImpl::ParseNewExpression() arguments.push_back(argument); return true; }, - &endLoc, true); + &endLoc, ParseListOptions::ALLOW_TRAILING_SEP); auto *newExprNode = AllocNode(callee, std::move(arguments)); ES2PANDA_ASSERT(newExprNode != nullptr); @@ -1381,7 +1381,7 @@ ArenaVector ParserImpl::ParseCallExpressionArguments(bool &tra } else { ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, lexer::NextTokenFlags::NONE, - [this, &trailingComma, &arguments]() { + [this, &trailingComma, &arguments](bool &) { trailingComma = false; ir::Expression *argument {}; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { @@ -1396,7 +1396,7 @@ ArenaVector ParserImpl::ParseCallExpressionArguments(bool &tra } return true; }, - &endLoc, true); + &endLoc, ParseListOptions::ALLOW_TRAILING_SEP); } return arguments; diff --git a/ets2panda/parser/parserImpl.cpp b/ets2panda/parser/parserImpl.cpp index a96e0eabc0c24a277eca86cb4321ee72c33375be..1496bd4dbd3f668748262382d76dc9f0cc937ff2 100644 --- a/ets2panda/parser/parserImpl.cpp +++ b/ets2panda/parser/parserImpl.cpp @@ -898,7 +898,7 @@ ArenaVector ParserImpl::ParseFunctionParams() ArenaVector params(Allocator()->Adapter()); - auto parseFunc = [this, ¶ms]() { + auto parseFunc = [this, ¶ms](bool &) { ir::Expression *parameter = ParseFunctionParameter(); if (parameter == nullptr) { return false; @@ -933,7 +933,7 @@ ArenaVector ParserImpl::ParseFunctionParams() params = std::move(ParseExpressionsArrayFormatPlaceholder()); } else { ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS, lexer::NextTokenFlags::NONE, parseFunc, nullptr, - true); + ParseListOptions::ALLOW_TRAILING_SEP); } return params; @@ -1497,15 +1497,22 @@ bool ParserImpl::CheckModuleAsModifier() } bool ParserImpl::ParseList(std::optional termToken, lexer::NextTokenFlags flags, - const std::function &parseElement, lexer::SourcePosition *sourceEnd, - bool allowTrailingSep) + const std::function &parseElement, + lexer::SourcePosition *sourceEnd, ParseListOptions parseListOptions) { bool success = true; + bool allowTypeKeyword = (parseListOptions & ParseListOptions::ALLOW_TYPE_KEYWORD) != 0U; auto sep = lexer::TokenType::PUNCTUATOR_COMMA; + bool typeKeywordOnSpecifier = false; while (Lexer()->GetToken().Type() != termToken && Lexer()->GetToken().Type() != lexer::TokenType::EOS) { // ErrorRecursionGuard is not feasible because we can break without consuming any tokens + if (allowTypeKeyword && Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_TYPE) { + Lexer()->NextToken(flags); // eat 'type' + typeKeywordOnSpecifier = true; + continue; + } auto savedPos = lexer_->Save(); - auto elemSuccess = parseElement(); + auto elemSuccess = parseElement(typeKeywordOnSpecifier); bool hasSep = false; if (Lexer()->GetToken().Type() == sep) { Lexer()->NextToken(flags); @@ -1520,7 +1527,7 @@ bool ParserImpl::ParseList(std::optional termToken, lexer::Nex continue; } if (termToken == Lexer()->GetToken().Type() || (!termToken.has_value() && !hasSep)) { - if (hasSep && !allowTrailingSep) { + if (hasSep && (parseListOptions & ParseListOptions::ALLOW_TRAILING_SEP) == 0U) { LogError(diagnostic::TRAILING_COMMA_NOT_ALLOWED); } break; diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index cd39352b1d1015be72c794a3ccb5842142086e0e..d0238cef36ff4b495b3e6d9895561b7308db3631 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -69,6 +69,12 @@ enum class TypeAnnotationParsingOptions : uint32_t { TYPE_ALIAS_CONTEXT = 1U << 19U }; +enum class ParseListOptions : uint32_t { + NO_OPT = 0U, + ALLOW_TRAILING_SEP = 1U << 0U, + ALLOW_TYPE_KEYWORD = 1U << 1U, +}; + class ParserImpl { public: explicit ParserImpl(Program *program, const util::Options *options, util::DiagnosticEngine &diagnosticEngine, @@ -582,8 +588,9 @@ protected: } bool ParseList(std::optional termToken, lexer::NextTokenFlags flags, - const std::function &parseElement, lexer::SourcePosition *sourceEnd = nullptr, - bool allowTrailingSep = false); + const std::function &parseElement, + lexer::SourcePosition *sourceEnd = nullptr, + ParseListOptions parseListOptions = ParseListOptions::NO_OPT); RecursiveContext &RecursiveCtx() { @@ -608,4 +615,8 @@ template <> struct enumbitops::IsAllowedType : std::true_type { }; +template <> +struct enumbitops::IsAllowedType : std::true_type { +}; + #endif diff --git a/ets2panda/parser/statementParser.cpp b/ets2panda/parser/statementParser.cpp index 1a490f379b30ea32b4d6bada6c36e8077bb00f5b..915bc7bcba82c29ced2cc04a2542176818ed00be 100644 --- a/ets2panda/parser/statementParser.cpp +++ b/ets2panda/parser/statementParser.cpp @@ -1749,7 +1749,7 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT, - [this, &specifiers]() { + [this, &specifiers](bool &) { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { // test exists for ts extension only LogExpectedToken(lexer::TokenType::LITERAL_IDENT); @@ -1778,7 +1778,7 @@ ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer:: } return true; }, - &endPos, true); + &endPos, ParseListOptions::ALLOW_TRAILING_SEP); ir::StringLiteral *source = nullptr; @@ -1921,7 +1921,7 @@ void ParserImpl::ParseNamedImportSpecifiers(ArenaVector *specifie ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT, - [this, specifiers]() { + [this, specifiers](bool &) { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { // test exists for ts extension only LogExpectedToken(lexer::TokenType::LITERAL_IDENT); @@ -1947,7 +1947,7 @@ void ParserImpl::ParseNamedImportSpecifiers(ArenaVector *specifie specifiers->push_back(specifier); return true; }, - nullptr, true); + nullptr, ParseListOptions::ALLOW_TRAILING_SEP); } ir::AstNode *ParserImpl::ParseImportDefaultSpecifier(ArenaVector *specifiers) diff --git a/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/export.ets b/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/export.ets new file mode 100644 index 0000000000000000000000000000000000000000..c9e6a3d14b282d27e55a8ac0681c6fdfa9d74997 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/export.ets @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { A, B } +export type { C, D } +export { type E } +export { F, type G } +export { type H, type I } +export { J, K, type L } + +export {type a as default}; +export type { type /* @@ first */M, N } // expect: CTE +export type { O, type /* @@ second */P } // expect: CTE +export type { type /* @@ third */Q, type /* @@ fourth */R } // expect: CTE + +class A {} +class B {} +class C {} +class D {} +class E {} +class F {} +class G {} +class H {} +class I {} +class J {} +class K {} +class L {} +class M {} +class N {} +class O {} +class P {} +class Q {} +class R {} + +let a = 0; + + +/* @@@ first Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ +/* @@@ second Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ +/* @@@ third Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ +/* @@@ fourth Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ diff --git a/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/import.ets b/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/import.ets new file mode 100644 index 0000000000000000000000000000000000000000..a902fe01f1f5b6f6f04dba6cc0c500f08e7b7d40 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/import.ets @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import { A, B } from "./source" +import type { C, D } from "./source" +import { type E } from "./source" +import { F, type G } from "./source" +import { type H, type I } from "./source" +import { J, K, type L } from "./source" + +import d from "./source" +import type dd from "./source" +import {type default as ddd} from "./source" +import {type default as type} from "./source"; + +import type { type /* @@ first */M, N } from "./source" // expect: CTE +import type { O, type /* @@ second */P } from "./source" // expect: CTE +import type { type /* @@ third */Q, type /* @@ fourth */R } from "./source" // expect: CTE + +import type {type /* @@ fifth */default as DD} from "./source" + +/* @@@ first Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ +/* @@@ second Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ +/* @@@ third Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ +/* @@@ fourth Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ +/* @@@ fifth Error SyntaxError: Type keyword set on both the specifier list and on the specifier itself. */ diff --git a/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/source.ets b/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/source.ets new file mode 100644 index 0000000000000000000000000000000000000000..205045ba8fa4ae75c02f37cc888bc3de13220748 --- /dev/null +++ b/ets2panda/test/ast/parser/ets/type_export_import/type_kw_on_identifiers/source.ets @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export class A {} +export class B {} +export class C {} +export class D {} +export class E {} +export class F {} +export class G {} +export class H {} +export class I {} +export class J {} +export class K {} +export class L {} +export class M {} +export class N {} +export class O {} +export class P {} +export class Q {} +export class R {} + +export default d; + +let d = 0; \ No newline at end of file diff --git a/ets2panda/util/diagnostic/syntax.yaml b/ets2panda/util/diagnostic/syntax.yaml index 6ce29340a696b837f62bfd17d1cd9db204c37744..a1476af7017ea19b24d3d3785d78153fc67d7ac5 100644 --- a/ets2panda/util/diagnostic/syntax.yaml +++ b/ets2panda/util/diagnostic/syntax.yaml @@ -1023,6 +1023,10 @@ syntax: id: 237 message: "Readonly utility type expected but readonly found." +- name: REPEATED_TYPE_KEYWORD + id: 135857 + message: "Type keyword set on both the specifier list and on the specifier itself." + - name: REQUIRED_PARAM_AFTER_DEFAULT id: 14 message: "Required parameter follows default parameter(s)."