diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index c7a2c0f7737ea35a3a954601d077a86a2a23e1cd..14a3b74899ba38ec3d58bc74ee972a6d2b95b551 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -382,15 +382,22 @@ libes2panda_sources = [ "parser/ETSFormattedParser.cpp", "parser/ETSNolintParser.cpp", "parser/ETSparser.cpp", + "parser/ETSparserClasses.cpp", + "parser/ETSparserEnums.cpp", + "parser/ETSparserExpressions.cpp", + "parser/ETSparserStatements.cpp", + "parser/ETSparserTypes.cpp", "parser/JSparser.cpp", "parser/TSparser.cpp", "parser/TypedParser.cpp", "parser/context/classPrivateContext.cpp", "parser/context/parserContext.cpp", "parser/expressionParser.cpp", + "parser/expressionTSParser.cpp", "parser/parserImpl.cpp", "parser/program/program.cpp", "parser/statementParser.cpp", + "parser/statementTSParser.cpp", "util/arktsconfig.cpp", "util/bitset.cpp", "util/errorHandler.cpp", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index f6f77d63f6246841872b55a629301fab66f2fa39..270899a6b50bbf9379e0c090245d70ead6b8e745 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -373,16 +373,23 @@ set(ES2PANDA_LIB_SRC parser/context/classPrivateContext.cpp parser/context/parserContext.cpp parser/expressionParser.cpp + parser/expressionTSParser.cpp parser/ASparser.cpp parser/JSparser.cpp parser/parserImpl.cpp parser/ETSFormattedParser.cpp parser/ETSparser.cpp + parser/ETSparserClasses.cpp + parser/ETSparserEnums.cpp + parser/ETSparserExpressions.cpp + parser/ETSparserStatements.cpp + parser/ETSparserTypes.cpp parser/ETSNolintParser.cpp parser/TSparser.cpp parser/TypedParser.cpp parser/program/program.cpp parser/statementParser.cpp + parser/statementTSParser.cpp checker/checker.cpp checker/checkerContext.cpp checker/ETSAnalyzer.cpp diff --git a/ets2panda/parser/ASparser.cpp b/ets2panda/parser/ASparser.cpp index 5a083c11d7b68d0afc1b5f765d989d07c0b3e87f..bed6e27bc7555604942c3b50b100cb51becb21a4 100644 --- a/ets2panda/parser/ASparser.cpp +++ b/ets2panda/parser/ASparser.cpp @@ -15,6 +15,7 @@ #include "ASparser.h" +#include "parser/parserStatusContext.h" #include "parserFlags.h" #include "util/helpers.h" #include "varbinder/privateBinding.h" diff --git a/ets2panda/parser/ETSFormattedParser.cpp b/ets2panda/parser/ETSFormattedParser.cpp index baa5e2e2a75ba58c5692ce53b23a50ec14928f1d..de92c8c267f5269926da32846e57a615b23ed33f 100644 --- a/ets2panda/parser/ETSFormattedParser.cpp +++ b/ets2panda/parser/ETSFormattedParser.cpp @@ -24,6 +24,7 @@ #include "ir/statements/expressionStatement.h" #include "ir/base/methodDefinition.h" #include "ir/ts/tsInterfaceBody.h" +#include "parser/parserStatusContext.h" namespace ark::es2panda::parser { //================================================================================================// diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index d2d1546d1e91cda6edb37bef89dc61799d24414d..bb478ce458b109ed2e3063715d104dc1f9479a0d 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -19,6 +19,7 @@ #include "macros.h" #include "parser/parserFlags.h" +#include "parser/parserStatusContext.h" #include "util/helpers.h" #include "util/language.h" #include "utils/arena_containers.h" @@ -26,65 +27,26 @@ #include "varbinder/ETSBinder.h" #include "lexer/lexer.h" #include "lexer/ETSLexer.h" -#include "checker/types/ets/etsEnumType.h" #include "ir/astNode.h" -#include "ir/base/classDefinition.h" #include "ir/base/decorator.h" #include "ir/base/catchClause.h" -#include "ir/base/classProperty.h" #include "ir/base/scriptFunction.h" #include "ir/base/methodDefinition.h" -#include "ir/base/classStaticBlock.h" #include "ir/base/spreadElement.h" #include "ir/expressions/identifier.h" #include "ir/expressions/functionExpression.h" -#include "ir/statements/functionDeclaration.h" -#include "ir/statements/expressionStatement.h" -#include "ir/statements/classDeclaration.h" -#include "ir/statements/variableDeclarator.h" -#include "ir/statements/variableDeclaration.h" #include "ir/expressions/dummyNode.h" -#include "ir/expressions/callExpression.h" -#include "ir/expressions/thisExpression.h" -#include "ir/expressions/typeofExpression.h" -#include "ir/expressions/memberExpression.h" -#include "ir/expressions/updateExpression.h" -#include "ir/expressions/arrowFunctionExpression.h" -#include "ir/expressions/unaryExpression.h" -#include "ir/expressions/yieldExpression.h" -#include "ir/expressions/awaitExpression.h" -#include "ir/expressions/literals/nullLiteral.h" -#include "ir/expressions/literals/numberLiteral.h" -#include "ir/expressions/literals/stringLiteral.h" -#include "ir/expressions/literals/undefinedLiteral.h" #include "ir/module/importDeclaration.h" #include "ir/module/importDefaultSpecifier.h" #include "ir/module/importSpecifier.h" #include "ir/module/exportSpecifier.h" #include "ir/module/exportNamedDeclaration.h" -#include "ir/statements/assertStatement.h" -#include "ir/statements/blockStatement.h" -#include "ir/statements/ifStatement.h" -#include "ir/statements/labelledStatement.h" -#include "ir/statements/switchStatement.h" -#include "ir/statements/throwStatement.h" -#include "ir/statements/tryStatement.h" -#include "ir/statements/whileStatement.h" -#include "ir/statements/forOfStatement.h" -#include "ir/statements/doWhileStatement.h" -#include "ir/statements/breakStatement.h" -#include "ir/statements/debuggerStatement.h" -#include "ir/ets/etsLaunchExpression.h" -#include "ir/ets/etsClassLiteral.h" #include "ir/ets/etsPrimitiveType.h" #include "ir/ets/etsPackageDeclaration.h" #include "ir/ets/etsReExportDeclaration.h" #include "ir/ets/etsWildcardType.h" -#include "ir/ets/etsNewArrayInstanceExpression.h" #include "ir/ets/etsTuple.h" #include "ir/ets/etsFunctionType.h" -#include "ir/ets/etsNewClassInstanceExpression.h" -#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" #include "ir/ets/etsScript.h" #include "ir/ets/etsTypeReference.h" #include "ir/ets/etsTypeReferencePart.h" @@ -93,11 +55,8 @@ #include "ir/ets/etsImportSource.h" #include "ir/ets/etsImportDeclaration.h" #include "ir/ets/etsStructDeclaration.h" -#include "ir/ets/etsParameterExpression.h" #include "ir/module/importNamespaceSpecifier.h" -#include "ir/ts/tsAsExpression.h" #include "ir/ts/tsInterfaceDeclaration.h" -#include "ir/ts/tsEnumDeclaration.h" #include "ir/ts/tsTypeParameterInstantiation.h" #include "ir/ts/tsInterfaceBody.h" #include "ir/ts/tsImportEqualsDeclaration.h" @@ -105,18 +64,16 @@ #include "ir/ts/tsQualifiedName.h" #include "ir/ts/tsTypeReference.h" #include "ir/ts/tsTypeParameter.h" -#include "ir/ts/tsIntersectionType.h" #include "ir/ts/tsInterfaceHeritage.h" #include "ir/ts/tsFunctionType.h" -#include "ir/ts/tsClassImplements.h" -#include "ir/ts/tsEnumMember.h" #include "ir/ts/tsTypeAliasDeclaration.h" #include "ir/ts/tsTypeParameterDeclaration.h" -#include "ir/ts/tsNonNullExpression.h" #include "ir/ts/tsThisType.h" #include "generated/signatures.h" namespace ark::es2panda::parser { +class FunctionContext; + using namespace std::literals::string_literals; ETSParser::ETSParser(Program *program, const CompilerOptions &options, ParserStatus status) @@ -271,121 +228,6 @@ parser::Program *ETSParser::ParseSource(const SourceFile &sourceFile) return program; } -ArenaVector ETSParser::ParseTopLevelStatements() -{ - ArenaVector statements(Allocator()->Adapter()); - while (Lexer()->GetToken().Type() != lexer::TokenType::EOS) { - if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_SEMI_COLON)) { - continue; - } - auto stmt = ParseTopLevelStatement(); - GetContext().Status() &= ~ParserStatus::IN_AMBIENT_CONTEXT; - if (stmt != nullptr) { - statements.emplace_back(stmt); - } - } - - return statements; -} - -ir::Statement *ETSParser::ParseTopLevelDeclStatement(StatementParsingFlags flags) -{ - auto [memberModifiers, startLoc] = ParseMemberModifiers(); - if ((memberModifiers & (ir::ModifierFlags::EXPORTED)) != 0U && - (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY || - Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) { - return ParseExport(startLoc, memberModifiers); - } - - ir::Statement *result = nullptr; - auto token = Lexer()->GetToken(); - switch (token.Type()) { - case lexer::TokenType::KEYW_FUNCTION: { - result = ParseFunctionDeclaration(false, memberModifiers); - result->SetStart(startLoc); - break; - } - case lexer::TokenType::KEYW_CONST: { - memberModifiers |= ir::ModifierFlags::CONST; - [[fallthrough]]; - } - case lexer::TokenType::KEYW_LET: { - result = ParseStatement(flags); - break; - } - case lexer::TokenType::KEYW_NAMESPACE: - case lexer::TokenType::KEYW_STATIC: - case lexer::TokenType::KEYW_ABSTRACT: - case lexer::TokenType::KEYW_FINAL: - case lexer::TokenType::KEYW_ENUM: - case lexer::TokenType::KEYW_INTERFACE: - case lexer::TokenType::KEYW_CLASS: { - result = ParseTypeDeclaration(false); - break; - } - case lexer::TokenType::LITERAL_IDENT: { - result = ParseIdentKeyword(); - break; - } - default: { - } - } - if (result != nullptr) { - if ((memberModifiers & ir::ModifierFlags::EXPORT_TYPE) != 0U && - !(result->IsClassDeclaration() || result->IsTSInterfaceDeclaration() || - result->IsTSTypeAliasDeclaration())) { - ThrowSyntaxError("Can only type export class or interface!"); - } - result->AddModifier(memberModifiers); - } - return result; -} - -ir::Statement *ETSParser::ParseTopLevelStatement() -{ - const auto flags = StatementParsingFlags::ALLOW_LEXICAL; - static const std::unordered_set ALLOWED_TOP_LEVEL_STMTS = { - lexer::TokenType::PUNCTUATOR_LEFT_BRACE, - lexer::TokenType::PUNCTUATOR_SEMI_COLON, - lexer::TokenType::KEYW_ASSERT, - lexer::TokenType::KEYW_IF, - lexer::TokenType::KEYW_DO, - lexer::TokenType::KEYW_FOR, - lexer::TokenType::KEYW_TRY, - lexer::TokenType::KEYW_WHILE, - lexer::TokenType::KEYW_BREAK, - lexer::TokenType::KEYW_CONTINUE, - lexer::TokenType::KEYW_THROW, - lexer::TokenType::KEYW_SWITCH, - lexer::TokenType::KEYW_DEBUGGER, - lexer::TokenType::LITERAL_IDENT, - }; - - auto result = ParseTopLevelDeclStatement(flags); - if (result == nullptr) { - auto const tokenType = Lexer()->GetToken().Type(); - if (ALLOWED_TOP_LEVEL_STMTS.count(tokenType) != 0U) { - result = ParseStatement(flags); - } else { - ThrowUnexpectedToken(tokenType); - } - } - return result; -} - -ArenaVector ETSParser::ParseTopLevelDeclaration() -{ - auto topStatements = ParseTopLevelStatements(); - Lexer()->NextToken(); - return topStatements; -} - -static bool IsClassModifier(lexer::TokenType type) -{ - return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_ABSTRACT || - type == lexer::TokenType::KEYW_FINAL; -} - ir::Statement *ETSParser::ParseIdentKeyword() { const auto token = Lexer()->GetToken(); @@ -404,362 +246,6 @@ ir::Statement *ETSParser::ParseIdentKeyword() return nullptr; } -ir::ModifierFlags ETSParser::ParseClassModifiers() -{ - ir::ModifierFlags flags = ir::ModifierFlags::NONE; - - while (IsClassModifier(Lexer()->GetToken().KeywordType())) { - ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; - - lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); - if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { - ThrowSyntaxError("Keyword must not contain escaped characters"); - } - - switch (Lexer()->GetToken().KeywordType()) { - case lexer::TokenType::KEYW_STATIC: { - currentFlag = ir::ModifierFlags::STATIC; - break; - } - case lexer::TokenType::KEYW_FINAL: { - currentFlag = ir::ModifierFlags::FINAL; - break; - } - case lexer::TokenType::KEYW_ABSTRACT: { - currentFlag = ir::ModifierFlags::ABSTRACT; - break; - } - default: { - UNREACHABLE(); - } - } - - if ((flags & currentFlag) != 0) { - ThrowSyntaxError("Duplicated modifier is not allowed"); - } - - Lexer()->NextToken(); - flags |= currentFlag; - } - - return flags; -} - -std::tuple ETSParser::ParseClassImplementsElement() -{ - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | - TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | - TypeAnnotationParsingOptions::ALLOW_WILDCARD; - return {ParseTypeReference(&options), nullptr}; -} - -ir::Expression *ETSParser::ParseSuperClassReference() -{ - if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) { - Lexer()->NextToken(); - - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | - TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | - TypeAnnotationParsingOptions::ALLOW_WILDCARD; - return ParseTypeReference(&options); - } - - return nullptr; -} - -ir::TypeNode *ETSParser::ParseInterfaceExtendsElement() -{ - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | - TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | - TypeAnnotationParsingOptions::ALLOW_WILDCARD; - return ParseTypeReference(&options); -} - -static bool IsClassMemberAccessModifier(lexer::TokenType type) -{ - return type == lexer::TokenType::KEYW_PUBLIC || type == lexer::TokenType::KEYW_PRIVATE || - type == lexer::TokenType::KEYW_PROTECTED || type == lexer::TokenType::KEYW_INTERNAL; -} - -std::tuple ETSParser::ParseClassMemberAccessModifiers() -{ - if (IsClassMemberAccessModifier(Lexer()->GetToken().Type())) { - char32_t nextCp = Lexer()->Lookahead(); - if (!(nextCp != lexer::LEX_CHAR_EQUALS && nextCp != lexer::LEX_CHAR_COLON && - nextCp != lexer::LEX_CHAR_LEFT_PAREN)) { - return {ir::ModifierFlags::NONE, false}; - } - - lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); - if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { - ThrowSyntaxError("Keyword must not contain escaped characters"); - } - - ir::ModifierFlags accessFlag = ir::ModifierFlags::NONE; - - switch (Lexer()->GetToken().KeywordType()) { - case lexer::TokenType::KEYW_PUBLIC: { - accessFlag = ir::ModifierFlags::PUBLIC; - break; - } - case lexer::TokenType::KEYW_PRIVATE: { - accessFlag = ir::ModifierFlags::PRIVATE; - break; - } - case lexer::TokenType::KEYW_PROTECTED: { - accessFlag = ir::ModifierFlags::PROTECTED; - break; - } - case lexer::TokenType::KEYW_INTERNAL: { - Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); - if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_PROTECTED) { - accessFlag = ir::ModifierFlags::INTERNAL; - return {accessFlag, true}; - } - accessFlag = ir::ModifierFlags::INTERNAL_PROTECTED; - break; - } - default: { - UNREACHABLE(); - } - } - if (((GetContext().Status() & ParserStatus::FUNCTION) != 0) && - (accessFlag == ir::ModifierFlags::PUBLIC || accessFlag == ir::ModifierFlags::PRIVATE || - accessFlag == ir::ModifierFlags::PROTECTED)) { - ThrowSyntaxError("Local class declaration members can not have access modifies", - Lexer()->GetToken().Start()); - } - - Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); - return {accessFlag, true}; - } - - return {ir::ModifierFlags::PUBLIC, false}; -} - -static bool IsClassFieldModifier(lexer::TokenType type) -{ - return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_READONLY; -} - -ir::ModifierFlags ETSParser::ParseClassFieldModifiers(bool seenStatic) -{ - ir::ModifierFlags flags = seenStatic ? ir::ModifierFlags::STATIC : ir::ModifierFlags::NONE; - - while (IsClassFieldModifier(Lexer()->GetToken().KeywordType())) { - char32_t nextCp = Lexer()->Lookahead(); - if (!(nextCp != lexer::LEX_CHAR_EQUALS && nextCp != lexer::LEX_CHAR_COLON)) { - return flags; - } - - ir::ModifierFlags currentFlag; - - lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); - if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { - ThrowSyntaxError("Keyword must not contain escaped characters"); - } - - switch (Lexer()->GetToken().KeywordType()) { - case lexer::TokenType::KEYW_STATIC: { - currentFlag = ir::ModifierFlags::STATIC; - break; - } - case lexer::TokenType::KEYW_READONLY: { - currentFlag = ir::ModifierFlags::READONLY; - break; - } - default: { - UNREACHABLE(); - } - } - - if ((flags & currentFlag) != 0) { - ThrowSyntaxError("Duplicated modifier is not allowed"); - } - - Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); - flags |= currentFlag; - } - - return flags; -} - -bool ETSParser::IsClassMethodModifier(lexer::TokenType type) noexcept -{ - switch (type) { - case lexer::TokenType::KEYW_STATIC: - case lexer::TokenType::KEYW_FINAL: - case lexer::TokenType::KEYW_NATIVE: - case lexer::TokenType::KEYW_ASYNC: - case lexer::TokenType::KEYW_OVERRIDE: - case lexer::TokenType::KEYW_ABSTRACT: { - return true; - } - default: { - break; - } - } - - return false; -} - -ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seenStatic) -{ - ir::ModifierFlags flags = seenStatic ? ir::ModifierFlags::STATIC : ir::ModifierFlags::NONE; - - while (IsClassMethodModifier(Lexer()->GetToken().KeywordType())) { - char32_t nextCp = Lexer()->Lookahead(); - if (!(nextCp != lexer::LEX_CHAR_LEFT_PAREN)) { - return flags; - } - - ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; - - lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); - if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { - ThrowSyntaxError("Keyword must not contain escaped characters"); - } - - switch (Lexer()->GetToken().KeywordType()) { - case lexer::TokenType::KEYW_STATIC: { - currentFlag = ir::ModifierFlags::STATIC; - break; - } - case lexer::TokenType::KEYW_FINAL: { - currentFlag = ir::ModifierFlags::FINAL; - break; - } - case lexer::TokenType::KEYW_NATIVE: { - currentFlag = ir::ModifierFlags::NATIVE; - break; - } - case lexer::TokenType::KEYW_ASYNC: { - currentFlag = ir::ModifierFlags::ASYNC; - break; - } - case lexer::TokenType::KEYW_OVERRIDE: { - currentFlag = ir::ModifierFlags::OVERRIDE; - break; - } - case lexer::TokenType::KEYW_ABSTRACT: { - currentFlag = ir::ModifierFlags::ABSTRACT; - break; - } - case lexer::TokenType::KEYW_DECLARE: { - currentFlag = ir::ModifierFlags::DECLARE; - break; - } - default: { - UNREACHABLE(); - } - } - - if ((flags & currentFlag) != 0) { - ThrowSyntaxError("Duplicated modifier is not allowed"); - } - - Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); - flags |= currentFlag; - if ((flags & ir::ModifierFlags::ASYNC) != 0) { - if ((flags & ir::ModifierFlags::NATIVE) != 0) { - ThrowSyntaxError("Native method cannot be async"); - } else if ((flags & ir::ModifierFlags::ABSTRACT) != 0) { - ThrowSyntaxError("Abstract method cannot be async"); - } - } - } - - return flags; -} - -// NOLINTNEXTLINE(google-default-arguments) -void ETSParser::ParseClassFieldDefinition(ir::Identifier *fieldName, ir::ModifierFlags modifiers, - ArenaVector *declarations) -{ - lexer::SourcePosition endLoc = fieldName->End(); - ir::TypeNode *typeAnnotation = nullptr; - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - bool optionalField = false; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { - Lexer()->NextToken(); // eat '?' - optionalField = true; - } - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - typeAnnotation = ParseTypeAnnotation(&options); - endLoc = typeAnnotation->End(); - } - - ir::Expression *initializer = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { - Lexer()->NextToken(); // eat '=' - initializer = ParseExpression(); - } else if (typeAnnotation == nullptr) { - ThrowSyntaxError("Field type annotation expected"); - } - - bool isDeclare = (modifiers & ir::ModifierFlags::DECLARE) != 0; - - if (isDeclare && initializer != nullptr) { - ThrowSyntaxError("Initializers are not allowed in ambient contexts."); - } - - auto *field = AllocNode(fieldName, initializer, typeAnnotation, modifiers, Allocator(), false); - field->SetRange({fieldName->Start(), initializer != nullptr ? initializer->End() : endLoc}); - if (optionalField) { - field->AddModifier(ir::ModifierFlags::OPTIONAL); - } - - declarations->push_back(field); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { - Lexer()->NextToken(); - ir::Identifier *nextName = ExpectIdentifier(false, true); - ParseClassFieldDefinition(nextName, modifiers, declarations); - } -} - -ir::MethodDefinition *ETSParser::ParseClassMethodDefinition(ir::Identifier *methodName, ir::ModifierFlags modifiers, - ir::Identifier *className) -{ - auto newStatus = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ALLOW_SUPER; - auto methodKind = ir::MethodDefinitionKind::METHOD; - - if (className != nullptr) { - methodKind = ir::MethodDefinitionKind::EXTENSION_METHOD; - newStatus |= ParserStatus::IN_EXTENSION_FUNCTION; - } - - if ((modifiers & ir::ModifierFlags::CONSTRUCTOR) != 0) { - newStatus = ParserStatus::CONSTRUCTOR_FUNCTION | ParserStatus::ALLOW_SUPER | ParserStatus::ALLOW_SUPER_CALL; - methodKind = ir::MethodDefinitionKind::CONSTRUCTOR; - } - - if ((modifiers & ir::ModifierFlags::ASYNC) != 0) { - newStatus |= ParserStatus::ASYNC_FUNCTION; - } - - if ((modifiers & ir::ModifierFlags::STATIC) == 0) { - newStatus |= ParserStatus::ALLOW_THIS_TYPE; - } - - ir::ScriptFunction *func = ParseFunction(newStatus, className); - func->SetIdent(methodName); - auto *funcExpr = AllocNode(func); - funcExpr->SetRange(func->Range()); - func->AddModifier(modifiers); - - if (className != nullptr) { - func->AddFlag(ir::ScriptFunctionFlags::INSTANCE_EXTENSION_METHOD); - } - auto *method = AllocNode(methodKind, methodName->Clone(Allocator(), nullptr)->AsExpression(), - funcExpr, modifiers, Allocator(), false); - method->SetRange(funcExpr->Range()); - func->Id()->SetReference(); - return method; -} - ir::ScriptFunction *ETSParser::ParseFunction(ParserStatus newStatus, ir::Identifier *className) { FunctionContext functionContext(this, newStatus | ParserStatus::FUNCTION); @@ -813,40 +299,6 @@ ir::ScriptFunction *ETSParser::ParseFunction(ParserStatus newStatus, ir::Identif return funcNode; } -ir::MethodDefinition *ETSParser::ParseClassMethod(ClassElementDescriptor *desc, - const ArenaVector &properties, - ir::Expression *propName, lexer::SourcePosition *propEnd) -{ - if (desc->methodKind != ir::MethodDefinitionKind::SET && - (desc->newStatus & ParserStatus::CONSTRUCTOR_FUNCTION) == 0) { - desc->newStatus |= ParserStatus::NEED_RETURN_TYPE; - } - - ir::ScriptFunction *func = ParseFunction(desc->newStatus); - if (propName->IsIdentifier()) { - func->SetIdent(propName->AsIdentifier()->Clone(Allocator(), nullptr)); - func->Id()->SetReference(); - } - - auto *funcExpr = AllocNode(func); - funcExpr->SetRange(func->Range()); - - if (desc->methodKind == ir::MethodDefinitionKind::SET) { - ValidateClassSetter(desc, properties, propName, func); - } else if (desc->methodKind == ir::MethodDefinitionKind::GET) { - ValidateClassGetter(desc, properties, propName, func); - } - - *propEnd = func->End(); - func->AddFlag(ir::ScriptFunctionFlags::METHOD); - auto *method = - AllocNode(desc->methodKind, propName->Clone(Allocator(), nullptr)->AsExpression(), - funcExpr, desc->modifiers, Allocator(), desc->isComputed); - method->SetRange(funcExpr->Range()); - - return method; -} - std::tuple ETSParser::ParseFunctionBody( [[maybe_unused]] const ArenaVector ¶ms, [[maybe_unused]] ParserStatus newStatus, [[maybe_unused]] ParserStatus contextStatus) @@ -858,22 +310,6 @@ std::tuple ETSParser::P return {true, body, body->End(), false}; } -ir::TypeNode *ETSParser::ParseFunctionReturnType([[maybe_unused]] ParserStatus status) -{ - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - if ((status & ParserStatus::CONSTRUCTOR_FUNCTION) != 0U) { - ThrowSyntaxError("Type annotation isn't allowed for constructor."); - } - Lexer()->NextToken(); // eat ':' - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | - TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE | - TypeAnnotationParsingOptions::RETURN_TYPE; - return ParseTypeAnnotation(&options); - } - - return nullptr; -} - ir::ScriptFunctionFlags ETSParser::ParseFunctionThrowMarker(bool isRethrowsAllowed) { ir::ScriptFunctionFlags throwMarker = ir::ScriptFunctionFlags::NONE; @@ -895,14 +331,6 @@ ir::ScriptFunctionFlags ETSParser::ParseFunctionThrowMarker(bool isRethrowsAllow return throwMarker; } -void ETSParser::ValidateLabeledStatement(lexer::TokenType type) -{ - if (type != lexer::TokenType::KEYW_DO && type != lexer::TokenType::KEYW_WHILE && - type != lexer::TokenType::KEYW_FOR && type != lexer::TokenType::KEYW_SWITCH) { - ThrowSyntaxError("Label must be followed by a loop statement", Lexer()->GetToken().Start()); - } -} - ir::AstNode *ETSParser::ParseInnerTypeDeclaration(ir::ModifierFlags memberModifiers, lexer::LexerPosition savedPos, bool isStepToken, bool seenStatic) { @@ -1010,135 +438,19 @@ ir::AstNode *ETSParser::ParseInnerRest(const ArenaVector &propert return placeholder; } -ir::AstNode *ETSParser::ParseClassElement(const ArenaVector &properties, - ir::ClassDefinitionModifiers modifiers, - [[maybe_unused]] ir::ModifierFlags flags) +ir::Statement *ETSParser::ParseTypeDeclarationAbstractFinal(bool allowStatic, ir::ClassDefinitionModifiers modifiers) { - auto startLoc = Lexer()->GetToken().Start(); - auto savedPos = Lexer()->Save(); // NOLINT(clang-analyzer-deadcode.DeadStores) - - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC && - Lexer()->Lookahead() == lexer::LEX_CHAR_LEFT_BRACE) { - return ParseClassStaticBlock(); + auto flags = ParseClassModifiers(); + if (allowStatic && (flags & ir::ModifierFlags::STATIC) == 0U) { + modifiers |= ir::ClassDefinitionModifiers::INNER; } - auto [memberModifiers, isStepToken] = ParseClassMemberAccessModifiers(); - - if (InAmbientContext()) { - memberModifiers |= ir::ModifierFlags::DECLARE; + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS) { + return ParseClassDeclaration(modifiers, flags); } - bool seenStatic = false; - char32_t nextCp = Lexer()->Lookahead(); - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC && nextCp != lexer::LEX_CHAR_EQUALS && - nextCp != lexer::LEX_CHAR_COLON && nextCp != lexer::LEX_CHAR_LEFT_PAREN && - nextCp != lexer::LEX_CHAR_LESS_THAN) { - Lexer()->NextToken(); - memberModifiers |= ir::ModifierFlags::STATIC; - seenStatic = true; - } - - if (IsClassFieldModifier(Lexer()->GetToken().KeywordType())) { - memberModifiers |= ParseClassFieldModifiers(seenStatic); - } else if (IsClassMethodModifier(Lexer()->GetToken().Type())) { - memberModifiers |= ParseClassMethodModifiers(seenStatic); - } - - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::KEYW_INTERFACE: - case lexer::TokenType::KEYW_CLASS: - case lexer::TokenType::KEYW_ENUM: { - return ParseInnerTypeDeclaration(memberModifiers, savedPos, isStepToken, seenStatic); - } - case lexer::TokenType::KEYW_CONSTRUCTOR: { - return ParseInnerConstructorDeclaration(memberModifiers, startLoc); - } - case lexer::TokenType::KEYW_PUBLIC: - case lexer::TokenType::KEYW_PRIVATE: - case lexer::TokenType::KEYW_PROTECTED: { - ThrowSyntaxError("Access modifier must precede field and method modifiers."); - break; - } - default: { - break; - } - } - - return ParseInnerRest(properties, modifiers, memberModifiers, startLoc); -} - -ir::MethodDefinition *ETSParser::ParseClassGetterSetterMethod(const ArenaVector &properties, - const ir::ClassDefinitionModifiers modifiers, - const ir::ModifierFlags memberModifiers) -{ - ClassElementDescriptor desc(Allocator()); - desc.methodKind = Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ? ir::MethodDefinitionKind::GET - : ir::MethodDefinitionKind::SET; - Lexer()->NextToken(); // eat get/set - auto *methodName = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - if (desc.methodKind == ir::MethodDefinitionKind::GET) { - methodName->SetAccessor(); - } else { - methodName->SetMutator(); - } - - Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); - - desc.newStatus = ParserStatus::ALLOW_SUPER; - desc.hasSuperClass = (modifiers & ir::ClassDefinitionModifiers::HAS_SUPER) != 0U; - desc.propStart = Lexer()->GetToken().Start(); - desc.modifiers = memberModifiers; - - lexer::SourcePosition propEnd = methodName->End(); - ir::MethodDefinition *method = ParseClassMethod(&desc, properties, methodName, &propEnd); - method->Function()->AddModifier(desc.modifiers); - method->SetRange({desc.propStart, propEnd}); - if (desc.methodKind == ir::MethodDefinitionKind::GET) { - method->Function()->AddFlag(ir::ScriptFunctionFlags::GETTER); - } else { - method->Function()->AddFlag(ir::ScriptFunctionFlags::SETTER); - } - - return method; -} - -ir::MethodDefinition *ETSParser::ParseInterfaceGetterSetterMethod(const ir::ModifierFlags modifiers) -{ - auto methodKind = Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ? ir::MethodDefinitionKind::GET - : ir::MethodDefinitionKind::SET; - Lexer()->NextToken(); // eat get/set - ExpectToken(lexer::TokenType::LITERAL_IDENT, false); - ir::MethodDefinition *method = ParseInterfaceMethod(modifiers, methodKind); - method->AddModifier(ir::ModifierFlags::PUBLIC); - method->SetRange({Lexer()->GetToken().Start(), method->Id()->End()}); - if (methodKind == ir::MethodDefinitionKind::GET) { - method->Id()->SetAccessor(); - method->Function()->AddFlag(ir::ScriptFunctionFlags::GETTER); - } else { - method->Id()->SetMutator(); - method->Function()->AddFlag(ir::ScriptFunctionFlags::SETTER); - } - method->AddModifier(ir::ModifierFlags::PUBLIC); - - method->Function()->SetIdent(method->Id()->Clone(Allocator(), nullptr)); - method->Function()->AddModifier(method->Modifiers()); - - return method; -} - -ir::Statement *ETSParser::ParseTypeDeclarationAbstractFinal(bool allowStatic, ir::ClassDefinitionModifiers modifiers) -{ - auto flags = ParseClassModifiers(); - if (allowStatic && (flags & ir::ModifierFlags::STATIC) == 0U) { - modifiers |= ir::ClassDefinitionModifiers::INNER; - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS) { - return ParseClassDeclaration(modifiers, flags); - } - - if (IsStructKeyword()) { - return ParseStructDeclaration(modifiers, flags); + if (IsStructKeyword()) { + return ParseStructDeclaration(modifiers, flags); } ThrowUnexpectedToken(Lexer()->GetToken().Type()); @@ -1188,37 +500,12 @@ ir::Statement *ETSParser::ParseTypeDeclaration(bool allowStatic) case lexer::TokenType::KEYW_CLASS: { return ParseClassDeclaration(modifiers); } - case lexer::TokenType::KEYW_TYPE: { - return ParseTypeAliasDeclaration(); - } case lexer::TokenType::LITERAL_IDENT: { if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT) { return ParseStructDeclaration(modifiers); } [[fallthrough]]; } - case lexer::TokenType::LITERAL_NUMBER: - case lexer::TokenType::LITERAL_NULL: - case lexer::TokenType::KEYW_UNDEFINED: - case lexer::TokenType::LITERAL_STRING: - case lexer::TokenType::LITERAL_FALSE: - case lexer::TokenType::LITERAL_TRUE: - case lexer::TokenType::LITERAL_CHAR: { - std::string errMsg("Cannot used in global scope '"); - - std::string text = tokenType == lexer::TokenType::LITERAL_CHAR - ? util::Helpers::UTF16toUTF8(Lexer()->GetToken().Utf16()) - : Lexer()->GetToken().Ident().Mutf8(); - - if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) == 0) { - errMsg.append(text); - } else { - errMsg.append(util::Helpers::CreateEscapedString(text)); - } - - errMsg.append("'"); - ThrowSyntaxError(errMsg.c_str()); - } default: { ThrowUnexpectedToken(Lexer()->GetToken().Type()); } @@ -1272,321 +559,6 @@ ir::TSTypeAliasDeclaration *ETSParser::ParseTypeAliasDeclaration() return typeAliasDecl; } -ir::TSInterfaceDeclaration *ETSParser::ParseInterfaceBody(ir::Identifier *name, bool isStatic) -{ - GetContext().Status() |= ParserStatus::ALLOW_THIS_TYPE; - - ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { - auto options = - TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE; - typeParamDecl = ParseTypeParameterDeclaration(&options); - } - - ArenaVector extends(Allocator()->Adapter()); - if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) { - extends = ParseInterfaceExtendsClause(); - } - - lexer::SourcePosition bodyStart = Lexer()->GetToken().Start(); - auto members = ParseTypeLiteralOrInterface(); - - for (auto &member : members) { - if (member->Type() == ir::AstNodeType::CLASS_DECLARATION || - member->Type() == ir::AstNodeType::STRUCT_DECLARATION || - member->Type() == ir::AstNodeType::TS_ENUM_DECLARATION || - member->Type() == ir::AstNodeType::TS_INTERFACE_DECLARATION) { - ThrowSyntaxError( - "Local type declaration (class, struct, interface and enum) support is not yet implemented."); - } - } - - auto *body = AllocNode(std::move(members)); - body->SetRange({bodyStart, Lexer()->GetToken().End()}); - - const auto isExternal = IsExternal(); - auto *interfaceDecl = AllocNode( - Allocator(), std::move(extends), - ir::TSInterfaceDeclaration::ConstructorData {name, typeParamDecl, body, isStatic, isExternal, - GetContext().GetLanguage()}); - - Lexer()->NextToken(); - GetContext().Status() &= ~ParserStatus::ALLOW_THIS_TYPE; - - return interfaceDecl; -} - -ir::Statement *ETSParser::ParseInterfaceDeclaration(bool isStatic) -{ - lexer::SourcePosition interfaceStart = Lexer()->GetToken().Start(); - Lexer()->NextToken(); // eat interface keyword - - auto *id = ExpectIdentifier(false, true); - - auto *declNode = ParseInterfaceBody(id, isStatic); - - declNode->SetRange({interfaceStart, Lexer()->GetToken().End()}); - return declNode; -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Statement *ETSParser::ParseEnumDeclaration(bool isConst, bool isStatic) -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ENUM); - - if ((GetContext().Status() & parser::ParserStatus::FUNCTION) != 0U) { - ThrowSyntaxError("Local enum declaration support is not yet implemented."); - } - - lexer::SourcePosition enumStart = Lexer()->GetToken().Start(); - Lexer()->NextToken(); // eat enum keyword - - auto *key = ExpectIdentifier(false, true); - - auto *declNode = ParseEnumMembers(key, enumStart, isConst, isStatic); - - return declNode; -} - -ir::Expression *ETSParser::ParseLaunchExpression(ExpressionParseFlags flags) -{ - lexer::SourcePosition start = Lexer()->GetToken().Start(); - Lexer()->NextToken(); // eat launch - - ir::Expression *expr = ParseLeftHandSideExpression(flags); - if (!expr->IsCallExpression()) { - ThrowSyntaxError("Only call expressions are allowed after 'launch'", expr->Start()); - } - auto call = expr->AsCallExpression(); - auto *launchExpression = AllocNode(call); - launchExpression->SetRange({start, call->End()}); - - return launchExpression; -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::ClassDefinition *ETSParser::ParseClassDefinition(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags) -{ - Lexer()->NextToken(); - - ir::Identifier *identNode = ParseClassIdent(modifiers); - - ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { - auto options = - TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE; - typeParamDecl = ParseTypeParameterDeclaration(&options); - } - - // Parse SuperClass - auto [superClass, superTypeParams] = ParseSuperClass(); - - if (superClass != nullptr) { - modifiers |= ir::ClassDefinitionModifiers::HAS_SUPER; - GetContext().Status() |= ParserStatus::ALLOW_SUPER; - } - - if (InAmbientContext()) { - flags |= ir::ModifierFlags::DECLARE; - } - - // Parse implements clause - ArenaVector implements(Allocator()->Adapter()); - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_IMPLEMENTS) { - Lexer()->NextToken(); - implements = ParseClassImplementClause(); - } - - ArenaVector properties(Allocator()->Adapter()); - ir::MethodDefinition *ctor = nullptr; - lexer::SourceRange bodyRange; - - if ((flags & ir::ModifierFlags::DECLARE) != 0U && - Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - // without ClassBody - bodyRange = lexer::SourceRange {Lexer()->GetToken().Start(), Lexer()->GetToken().Start()}; - } else { - ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE, false); - - // Parse ClassBody - std::tie(ctor, properties, bodyRange) = ParseClassBody(modifiers, flags); - } - - auto *classDefinition = AllocNode( - util::StringView(), identNode, typeParamDecl, superTypeParams, std::move(implements), ctor, superClass, - std::move(properties), modifiers, flags, GetContext().GetLanguage()); - - classDefinition->SetRange(bodyRange); - - GetContext().Status() &= ~ParserStatus::ALLOW_SUPER; - - return classDefinition; -} - -static bool IsInterfaceMethodModifier(lexer::TokenType type) -{ - // NOTE (psiket) Rewrite this - return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_PRIVATE || - type == lexer::TokenType::KEYW_PROTECTED || type == lexer::TokenType::KEYW_PUBLIC; -} - -ir::ModifierFlags ETSParser::ParseInterfaceMethodModifiers() -{ - ir::ModifierFlags flags = ir::ModifierFlags::NONE; - - while (IsInterfaceMethodModifier(Lexer()->GetToken().Type())) { - ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; - - if ((GetContext().Status() & ParserStatus::FUNCTION) != 0) { - if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PUBLIC || - Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PROTECTED || - Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PRIVATE) { - ThrowSyntaxError("Local interface declaration members can not have access modifies", - Lexer()->GetToken().Start()); - } - } else if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PUBLIC || - Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PROTECTED) { - break; - } - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::KEYW_STATIC: { - currentFlag = ir::ModifierFlags::STATIC; - break; - } - case lexer::TokenType::KEYW_PRIVATE: { - currentFlag = ir::ModifierFlags::PRIVATE; - break; - } - default: { - UNREACHABLE(); - } - } - - char32_t nextCp = Lexer()->Lookahead(); - if (nextCp == lexer::LEX_CHAR_COLON || nextCp == lexer::LEX_CHAR_LEFT_PAREN || - nextCp == lexer::LEX_CHAR_EQUALS) { - break; - } - - if ((flags & currentFlag) != 0) { - ThrowSyntaxError("Duplicated modifier is not allowed"); - } - - Lexer()->NextToken(); - flags |= currentFlag; - } - - return flags; -} - -ir::ClassProperty *ETSParser::ParseInterfaceField() -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT); - auto *name = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - name->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - bool optionalField = false; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { - Lexer()->NextToken(); // eat '?' - optionalField = true; - } - - ir::TypeNode *typeAnnotation = nullptr; - if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) { - ThrowSyntaxError("Interface fields must have type annotation."); - } - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - typeAnnotation = ParseTypeAnnotation(&options); - - name->SetTsTypeAnnotation(typeAnnotation); - typeAnnotation->SetParent(name); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EQUAL) { - ThrowSyntaxError("Initializers are not allowed on interface properties."); - } - - ir::ModifierFlags fieldModifiers = ir::ModifierFlags::PUBLIC; - - if (InAmbientContext()) { - fieldModifiers |= ir::ModifierFlags::DECLARE; - } - - auto *field = AllocNode(name, nullptr, typeAnnotation->Clone(Allocator(), nullptr), - fieldModifiers, Allocator(), false); - if (optionalField) { - field->AddModifier(ir::ModifierFlags::OPTIONAL); - } - field->SetEnd(Lexer()->GetToken().End()); - - return field; -} - -ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, ir::MethodDefinitionKind methodKind) -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT); - auto *name = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - name->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - - FunctionContext functionContext(this, ParserStatus::FUNCTION); - - lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); - - auto [signature, throwMarker] = ParseFunctionSignature(ParserStatus::NEED_RETURN_TYPE); - - ir::BlockStatement *body = nullptr; - - bool isDeclare = InAmbientContext(); - if (isDeclare) { - flags |= ir::ModifierFlags::DECLARE; - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - if (methodKind == ir::MethodDefinitionKind::SET || methodKind == ir::MethodDefinitionKind::GET) { - ThrowSyntaxError("Getter and setter methods must be abstracts in the interface body", startLoc); - } - body = ParseBlockStatement(); - } else if ((flags & (ir::ModifierFlags::PRIVATE | ir::ModifierFlags::STATIC)) != 0 && !isDeclare) { - ThrowSyntaxError("Private or static interface methods must have body", startLoc); - } - - functionContext.AddFlag(throwMarker); - - if ((GetContext().Status() & ParserStatus::FUNCTION_HAS_RETURN_STATEMENT) != 0) { - functionContext.AddFlag(ir::ScriptFunctionFlags::HAS_RETURN); - GetContext().Status() ^= ParserStatus::FUNCTION_HAS_RETURN_STATEMENT; - } - - auto *func = AllocNode( - Allocator(), ir::ScriptFunction::ScriptFunctionData {body, std::move(signature), functionContext.Flags(), flags, - true, GetContext().GetLanguage()}); - - if ((flags & ir::ModifierFlags::STATIC) == 0 && body == nullptr) { - func->AddModifier(ir::ModifierFlags::ABSTRACT); - } - func->SetRange({startLoc, body != nullptr ? body->End() - : func->ReturnTypeAnnotation() != nullptr ? func->ReturnTypeAnnotation()->End() - : func->Params().empty() ? Lexer()->GetToken().End() - : (*func->Params().end())->End()}); - - auto *funcExpr = AllocNode(func); - funcExpr->SetRange(func->Range()); - func->AddFlag(ir::ScriptFunctionFlags::METHOD); - - func->SetIdent(name); - auto *method = AllocNode(ir::MethodDefinitionKind::METHOD, - name->Clone(Allocator(), nullptr)->AsExpression(), funcExpr, flags, - Allocator(), false); - method->SetRange(funcExpr->Range()); - - func->Id()->SetReference(); - - ConsumeSemicolon(method); - - return method; -} - std::pair ETSParser::CheckDefaultParameters(const ir::ScriptFunction *const function) const { bool hasDefaultParameter = false; @@ -1748,49 +720,6 @@ bool ETSParser::ValidateContinueLabel([[maybe_unused]] util::StringView label) return true; } -ir::AstNode *ETSParser::ParseTypeLiteralOrInterfaceMember() -{ - auto startLoc = Lexer()->GetToken().Start(); - ir::ModifierFlags methodFlags = ParseInterfaceMethodModifiers(); - if (methodFlags != ir::ModifierFlags::NONE) { - if ((methodFlags & ir::ModifierFlags::PRIVATE) == 0) { - methodFlags |= ir::ModifierFlags::PUBLIC; - } - - auto *method = ParseInterfaceMethod(methodFlags, ir::MethodDefinitionKind::METHOD); - method->SetStart(startLoc); - return method; - } - - if (Lexer()->Lookahead() != lexer::LEX_CHAR_LEFT_PAREN && Lexer()->Lookahead() != lexer::LEX_CHAR_LESS_THAN && - (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET || - Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_SET)) { - return ParseInterfaceGetterSetterMethod(methodFlags); - } - - if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_READONLY)) { - auto *field = ParseInterfaceField(); - field->SetStart(startLoc); - field->AddModifier(ir::ModifierFlags::READONLY); - return field; - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { - char32_t nextCp = Lexer()->Lookahead(); - if (nextCp == lexer::LEX_CHAR_LEFT_PAREN || nextCp == lexer::LEX_CHAR_LESS_THAN) { - auto *method = ParseInterfaceMethod(ir::ModifierFlags::PUBLIC, ir::MethodDefinitionKind::METHOD); - method->SetStart(startLoc); - return method; - } - - auto *field = ParseInterfaceField(); - field->SetStart(startLoc); - return field; - } - - return ParseTypeDeclaration(true); -} - std::tuple ETSParser::ParseTypeReferencePart( TypeAnnotationParsingOptions *options) { @@ -1906,355 +835,36 @@ ir::TypeNode *ETSParser::ParseBaseTypeReference(TypeAnnotationParsingOptions *op return typeAnnotation; } -ir::TypeNode *ETSParser::ParsePrimitiveType(TypeAnnotationParsingOptions *options, ir::PrimitiveType type) +std::optional ETSParser::GetDefaultParamPosition(ArenaVector params) { - if (((*options) & TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE) != 0) { - ThrowSyntaxError("Primitive type is not allowed here."); + for (auto ¶m : params) { + if (param->IsETSParameterExpression() && param->AsETSParameterExpression()->IsDefault()) { + return param->AsETSParameterExpression()->Initializer()->Start(); + } } - - auto *typeAnnotation = AllocNode(type); - typeAnnotation->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - return typeAnnotation; + return {}; } -ir::TypeNode *ETSParser::ParseUnionType(ir::TypeNode *const firstType) +ir::TypeNode *ETSParser::ParseLiteralIdent(TypeAnnotationParsingOptions *options) { - ArenaVector types(Allocator()->Adapter()); - types.push_back(firstType->AsTypeNode()); - - while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { - Lexer()->NextToken(); // eat '|' + if (const auto keyword = Lexer()->GetToken().KeywordType(); + keyword == lexer::TokenType::KEYW_IN || keyword == lexer::TokenType::KEYW_OUT) { + return ParseWildcardType(options); + } - auto options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_UNION; - types.push_back(ParseTypeAnnotation(&options)); + if (Lexer()->GetToken().IsDefinableTypeName()) { + return GetTypeAnnotationOfPrimitiveType(Lexer()->GetToken().KeywordType(), options); } - auto const endLoc = types.back()->End(); - auto *const unionType = AllocNode(std::move(types)); - unionType->SetRange({firstType->Start(), endLoc}); - return unionType; + return ParseTypeReference(options); } -ir::TSIntersectionType *ETSParser::ParseIntersectionType(ir::Expression *type) +void ETSParser::ParseRightParenthesis(TypeAnnotationParsingOptions *options, ir::TypeNode *&typeAnnotation, + lexer::LexerPosition savedPos) { - auto startLoc = type->Start(); - ArenaVector types(Allocator()->Adapter()); - types.push_back(type); - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - - while (true) { - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_BITWISE_AND) { - break; - } - - Lexer()->NextToken(); // eat '&' - types.push_back(ParseTypeReference(&options)); - } - - lexer::SourcePosition endLoc = types.back()->End(); - auto *intersectionType = AllocNode(std::move(types)); - intersectionType->SetRange({startLoc, endLoc}); - return intersectionType; -} - -ir::TypeNode *ETSParser::GetTypeAnnotationOfPrimitiveType([[maybe_unused]] lexer::TokenType tokenType, - TypeAnnotationParsingOptions *options) -{ - ir::TypeNode *typeAnnotation = nullptr; - switch (tokenType) { - case lexer::TokenType::KEYW_BOOLEAN: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BOOLEAN); - break; - case lexer::TokenType::KEYW_DOUBLE: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::DOUBLE); - break; - case lexer::TokenType::KEYW_BYTE: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BYTE); - break; - case lexer::TokenType::KEYW_FLOAT: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::FLOAT); - break; - case lexer::TokenType::KEYW_SHORT: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::SHORT); - break; - case lexer::TokenType::KEYW_INT: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::INT); - break; - case lexer::TokenType::KEYW_CHAR: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::CHAR); - break; - case lexer::TokenType::KEYW_LONG: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::LONG); - break; - case lexer::TokenType::KEYW_VOID: - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::VOID); - break; - default: - typeAnnotation = ParseTypeReference(options); - break; - } - return typeAnnotation; -} - -ir::TypeNode *ETSParser::ParseWildcardType(TypeAnnotationParsingOptions *options) -{ - const auto varianceStartLoc = Lexer()->GetToken().Start(); - const auto varianceEndLoc = Lexer()->GetToken().End(); - const auto varianceModifier = ParseTypeVarianceModifier(options); - - auto *typeReference = [this, &varianceModifier, options]() -> ir::ETSTypeReference * { - if (varianceModifier == ir::ModifierFlags::OUT && - (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_GREATER_THAN || - Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA)) { - // unbounded 'out' - return nullptr; - } - return ParseTypeReference(options)->AsETSTypeReference(); - }(); - - auto *wildcardType = AllocNode(typeReference, varianceModifier); - wildcardType->SetRange({varianceStartLoc, typeReference == nullptr ? varianceEndLoc : typeReference->End()}); - - return wildcardType; -} - -ir::TypeNode *ETSParser::ParseFunctionType() -{ - auto startLoc = Lexer()->GetToken().Start(); - auto params = ParseFunctionParams(); - - auto *const returnTypeAnnotation = [this]() -> ir::TypeNode * { - ExpectToken(lexer::TokenType::PUNCTUATOR_ARROW); - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - return ParseTypeAnnotation(&options); - }(); - - ir::ScriptFunctionFlags throwMarker = ParseFunctionThrowMarker(false); - - auto *funcType = AllocNode( - ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation), throwMarker); - const auto endLoc = returnTypeAnnotation->End(); - funcType->SetRange({startLoc, endLoc}); - - return funcType; -} - -ir::TypeNode *ETSParser::ParseETSTupleType(TypeAnnotationParsingOptions *const options) -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET); - - const auto startLoc = Lexer()->GetToken().Start(); - Lexer()->NextToken(); // eat '[' - - ArenaVector tupleTypeList(Allocator()->Adapter()); - auto *const tupleType = AllocNode(Allocator()); - - bool spreadTypePresent = false; - - while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { - // Parse named parameter if name presents - if ((Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) && - (Lexer()->Lookahead() == lexer::LEX_CHAR_COLON)) { - ExpectIdentifier(); - Lexer()->NextToken(); // eat ':' - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { - if (spreadTypePresent) { - ThrowSyntaxError("Only one spread type declaration allowed, at the last index"); - } - - spreadTypePresent = true; - Lexer()->NextToken(); // eat '...' - } else if (spreadTypePresent) { - // This can't be implemented to any index, with type consistency. If a spread type is in the middle of - // the tuple, then bounds check can't be made for element access, so the type of elements after the - // spread can't be determined in compile time. - ThrowSyntaxError("Spread type must be at the last index in the tuple type"); - } - - auto *const currentTypeAnnotation = ParseTypeAnnotation(options); - currentTypeAnnotation->SetParent(tupleType); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { - // NOTE(mmartin): implement optional types for tuples - ThrowSyntaxError("Optional types in tuples are not yet implemented."); - } - - if (spreadTypePresent) { - if (!currentTypeAnnotation->IsTSArrayType()) { - ThrowSyntaxError("Spread type must be an array type"); - } - - tupleType->SetSpreadType(currentTypeAnnotation); - } else { - tupleTypeList.push_back(currentTypeAnnotation); - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { - Lexer()->NextToken(); // eat comma - continue; - } - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { - ThrowSyntaxError("Comma is mandatory between elements in a tuple type declaration"); - } - } - - Lexer()->NextToken(); // eat ']' - - tupleType->SetTypeAnnotationsList(tupleTypeList); - const auto endLoc = Lexer()->GetToken().End(); - tupleType->SetRange({startLoc, endLoc}); - - return tupleType; -} - -std::optional ETSParser::GetDefaultParamPosition(ArenaVector params) -{ - for (auto ¶m : params) { - if (param->IsETSParameterExpression() && param->AsETSParameterExpression()->IsDefault()) { - return param->AsETSParameterExpression()->Initializer()->Start(); - } - } - return {}; -} - -// Just to reduce the size of ParseTypeAnnotation(...) method -std::pair ETSParser::GetTypeAnnotationFromToken(TypeAnnotationParsingOptions *options) -{ - ir::TypeNode *typeAnnotation = nullptr; - - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::LITERAL_IDENT: { - typeAnnotation = ParseLiteralIdent(options); - if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 && - (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) { - return std::make_pair(typeAnnotation, false); - } - break; - } - case lexer::TokenType::KEYW_VOID: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::VOID); - break; - } - case lexer::TokenType::KEYW_BOOLEAN: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BOOLEAN); - break; - } - case lexer::TokenType::KEYW_BYTE: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BYTE); - break; - } - case lexer::TokenType::KEYW_CHAR: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::CHAR); - break; - } - case lexer::TokenType::KEYW_DOUBLE: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::DOUBLE); - break; - } - case lexer::TokenType::KEYW_FLOAT: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::FLOAT); - break; - } - case lexer::TokenType::KEYW_INT: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::INT); - break; - } - case lexer::TokenType::KEYW_LONG: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::LONG); - break; - } - case lexer::TokenType::KEYW_SHORT: { - typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::SHORT); - break; - } - case lexer::TokenType::LITERAL_NULL: { - typeAnnotation = AllocNode(); - typeAnnotation->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - break; - } - case lexer::TokenType::KEYW_UNDEFINED: { - typeAnnotation = AllocNode(); - typeAnnotation->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - break; - } - case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { - auto startLoc = Lexer()->GetToken().Start(); - lexer::LexerPosition savedPos = Lexer()->Save(); - Lexer()->NextToken(); // eat '(' - - if (((*options) & TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE) == 0 && - (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS || - Lexer()->Lookahead() == lexer::LEX_CHAR_COLON)) { - typeAnnotation = ParseFunctionType(); - typeAnnotation->SetStart(startLoc); - - if (auto position = GetDefaultParamPosition(typeAnnotation->AsETSFunctionType()->Params())) { - ThrowSyntaxError("Default parameters can not be used in functional type", position.value()); - } - - return std::make_pair(typeAnnotation, false); - } - - typeAnnotation = ParseTypeAnnotation(options); - typeAnnotation->SetStart(startLoc); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { - typeAnnotation = ParseUnionType(typeAnnotation); - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { - ThrowSyntaxError("Default parameters can not be used in functional type"); - } - - ParseRightParenthesis(options, typeAnnotation, savedPos); - break; - } - case lexer::TokenType::PUNCTUATOR_FORMAT: { - typeAnnotation = ParseTypeFormatPlaceholder(); - break; - } - case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { - typeAnnotation = ParseETSTupleType(options); - break; - } - case lexer::TokenType::KEYW_THIS: { - typeAnnotation = ParseThisType(options); - break; - } - default: { - break; - } - } - - return std::make_pair(typeAnnotation, true); -} - -ir::TypeNode *ETSParser::ParseLiteralIdent(TypeAnnotationParsingOptions *options) -{ - if (const auto keyword = Lexer()->GetToken().KeywordType(); - keyword == lexer::TokenType::KEYW_IN || keyword == lexer::TokenType::KEYW_OUT) { - return ParseWildcardType(options); - } - - if (Lexer()->GetToken().IsDefinableTypeName()) { - return GetTypeAnnotationOfPrimitiveType(Lexer()->GetToken().KeywordType(), options); - } - - return ParseTypeReference(options); -} - -void ETSParser::ParseRightParenthesis(TypeAnnotationParsingOptions *options, ir::TypeNode *&typeAnnotation, - lexer::LexerPosition savedPos) -{ - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - if (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0) { - ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + if (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0) { + ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); } Lexer()->Rewind(savedPos); @@ -2264,83 +874,6 @@ void ETSParser::ParseRightParenthesis(TypeAnnotationParsingOptions *options, ir: } } -ir::TypeNode *ETSParser::ParseThisType(TypeAnnotationParsingOptions *options) -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS); - - // A syntax error should be thrown if - // - the usage of 'this' as a type is not allowed in the current context, or - // - 'this' is not used as a return type, or - // - the current context is an arrow function (might be inside a method of a class where 'this' is allowed). - if (((*options & TypeAnnotationParsingOptions::THROW_ERROR) != 0) && - (((GetContext().Status() & ParserStatus::ALLOW_THIS_TYPE) == 0) || - ((*options & TypeAnnotationParsingOptions::RETURN_TYPE) == 0) || - ((GetContext().Status() & ParserStatus::ARROW_FUNCTION) != 0))) { - ThrowSyntaxError("A 'this' type is available only as return type in a non-static method of a class or struct."); - } - - auto *thisType = AllocNode(); - thisType->SetRange(Lexer()->GetToken().Loc()); - - Lexer()->NextToken(); // eat 'this' - - return thisType; -} - -ir::TypeNode *ETSParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *options) -{ - bool const throwError = ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0; - - auto [typeAnnotation, needFurtherProcessing] = GetTypeAnnotationFromToken(options); - - if (typeAnnotation == nullptr) { - if (throwError) { - ThrowSyntaxError("Invalid Type"); - } - return nullptr; - } - - if (!needFurtherProcessing) { - return typeAnnotation; - } - - const lexer::SourcePosition &startPos = Lexer()->GetToken().Start(); - - if (((*options) & TypeAnnotationParsingOptions::ALLOW_INTERSECTION) != 0 && - Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_AND) { - if (typeAnnotation->IsETSPrimitiveType()) { - if (throwError) { - ThrowSyntaxError("Invalid intersection type."); - } - return nullptr; - } - - return ParseIntersectionType(typeAnnotation); - } - - while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { - Lexer()->NextToken(); // eat '[' - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { - if (throwError) { - ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET); - } - return nullptr; - } - - Lexer()->NextToken(); // eat ']' - typeAnnotation = AllocNode(typeAnnotation); - typeAnnotation->SetRange({startPos, Lexer()->GetToken().End()}); - } - - if (((*options) & TypeAnnotationParsingOptions::DISALLOW_UNION) == 0 && - Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { - return ParseUnionType(typeAnnotation); - } - - return typeAnnotation; -} - void ETSParser::ThrowIfVarDeclaration(VariableParsingFlags flags) { if ((flags & VariableParsingFlags::VAR) != 0) { @@ -2348,16 +881,6 @@ void ETSParser::ThrowIfVarDeclaration(VariableParsingFlags flags) } } -void ETSParser::ValidateForInStatement() -{ - ThrowUnexpectedToken(lexer::TokenType::KEYW_IN); -} - -ir::DebuggerStatement *ETSParser::ParseDebuggerStatement() -{ - ThrowUnexpectedToken(lexer::TokenType::KEYW_DEBUGGER); -} - ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::ModifierFlags modifiers) { ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY || @@ -2398,12 +921,6 @@ ir::Statement *ETSParser::ParseExport(lexer::SourcePosition startLoc, ir::Modifi return reExport; } -ir::Statement *ETSParser::ParseFunctionStatement([[maybe_unused]] const StatementParsingFlags flags) -{ - ASSERT((flags & StatementParsingFlags::GLOBAL) == 0); - ThrowSyntaxError("Nested functions are not allowed"); -} - ir::ETSPackageDeclaration *ETSParser::ParsePackageDeclaration() { auto startLoc = Lexer()->GetToken().Start(); @@ -2699,62 +1216,6 @@ ir::ETSUnionType *ETSParser::CreateOptionalParameterTypeNode(ir::TypeNode *typeA return unionType; } -ir::Expression *ETSParser::ParseFunctionParameterExpression(ir::AnnotatedExpression *const paramIdent, - ir::ETSUndefinedType *defaultUndef) -{ - ir::ETSParameterExpression *paramExpression; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { - if (paramIdent->IsRestElement()) { - ThrowSyntaxError(NO_DEFAULT_FOR_REST); - } - - auto const lexerPos = Lexer()->Save().Iterator(); - Lexer()->NextToken(); // eat '=' - - if (defaultUndef != nullptr) { - ThrowSyntaxError("Not enable default value with default undefined"); - } - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS || - Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { - ThrowSyntaxError("You didn't set the value."); - } - - paramExpression = AllocNode(paramIdent->AsIdentifier(), ParseExpression()); - - std::string value = Lexer()->SourceView(lexerPos.Index(), Lexer()->Save().Iterator().Index()).Mutf8(); - while (value.back() == ' ') { - value.pop_back(); - } - if (value.back() == ')' || value.back() == ',') { - value.pop_back(); - } - paramExpression->SetLexerSaved(util::UString(value, Allocator()).View()); - - paramExpression->SetRange({paramIdent->Start(), paramExpression->Initializer()->End()}); - } else if (paramIdent->IsIdentifier()) { - auto *typeAnnotation = paramIdent->AsIdentifier()->TypeAnnotation(); - - const auto typeAnnotationValue = [this, typeAnnotation, - defaultUndef]() -> std::pair { - if (typeAnnotation == nullptr) { - return std::make_pair(nullptr, ""); - } - return std::make_pair(defaultUndef != nullptr ? AllocNode() : nullptr, "undefined"); - }(); - - paramExpression = - AllocNode(paramIdent->AsIdentifier(), std::get<0>(typeAnnotationValue)); - if (defaultUndef != nullptr) { - paramExpression->SetLexerSaved(util::UString(std::get<1>(typeAnnotationValue), Allocator()).View()); - } - paramExpression->SetRange({paramIdent->Start(), paramIdent->End()}); - } else { - paramExpression = AllocNode(paramIdent->AsRestElement(), nullptr); - paramExpression->SetRange({paramIdent->Start(), paramIdent->End()}); - } - return paramExpression; -} - ir::Expression *ETSParser::ParseFunctionParameter() { auto *const paramIdent = GetAnnotatedExpressionFromParam(); @@ -2886,33 +1347,11 @@ ir::VariableDeclarator *ETSParser::ParseVariableDeclarator(ir::Expression *init, return declarator; } -ir::Statement *ETSParser::ParseAssertStatement() +ir::Expression *ETSParser::ParseCatchParam() { - lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); - Lexer()->NextToken(); - - ir::Expression *test = ParseExpression(); - lexer::SourcePosition endLoc = test->End(); - ir::Expression *second = nullptr; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - second = ParseExpression(); - endLoc = second->End(); - } - - auto *asStatement = AllocNode(test, second); - asStatement->SetRange({startLoc, endLoc}); - ConsumeSemicolon(asStatement); - - return asStatement; -} - -ir::Expression *ETSParser::ParseCatchParam() -{ - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { - ThrowSyntaxError("Unexpected token, expected '('"); - } + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { + ThrowSyntaxError("Unexpected token, expected '('"); + } ir::AnnotatedExpression *param = nullptr; @@ -2953,50 +1392,6 @@ void ETSParser::ParseCatchParamTypeAnnotation([[maybe_unused]] ir::AnnotatedExpr } } -ir::Statement *ETSParser::ParseTryStatement() -{ - lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); - Lexer()->NextToken(); // eat the 'try' keyword - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - ThrowSyntaxError("Unexpected token, expected '{'"); - } - - ir::BlockStatement *body = ParseBlockStatement(); - - ArenaVector catchClauses(Allocator()->Adapter()); - - while (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_CATCH) { - ir::CatchClause *clause {}; - - clause = ParseCatchClause(); - - catchClauses.push_back(clause); - } - - ir::BlockStatement *finalizer = nullptr; - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FINALLY) { - Lexer()->NextToken(); // eat 'finally' keyword - - finalizer = ParseBlockStatement(); - } - - if (catchClauses.empty() && finalizer == nullptr) { - ThrowSyntaxError("A try statement should contain either finally clause or at least one catch clause.", - startLoc); - } - - lexer::SourcePosition endLoc = finalizer != nullptr ? finalizer->End() : catchClauses.back()->End(); - - ArenaVector> finalizerInsertions(Allocator()->Adapter()); - - auto *tryStatement = AllocNode(body, std::move(catchClauses), finalizer, finalizerInsertions); - tryStatement->SetRange({startLoc, endLoc}); - ConsumeSemicolon(tryStatement); - - return tryStatement; -} - ir::Statement *ETSParser::ParseImportDeclaration([[maybe_unused]] StatementParsingFlags flags) { char32_t nextChar = Lexer()->Lookahead(); @@ -3038,208 +1433,6 @@ ir::Statement *ETSParser::ParseExportDeclaration([[maybe_unused]] StatementParsi ThrowUnexpectedToken(lexer::TokenType::KEYW_EXPORT); } -ir::Expression *ETSParser::ResolveArgumentUnaryExpr(ExpressionParseFlags flags) -{ - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::PUNCTUATOR_PLUS: - case lexer::TokenType::PUNCTUATOR_MINUS: - case lexer::TokenType::PUNCTUATOR_TILDE: - case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: - case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: - case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: - case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: - case lexer::TokenType::KEYW_TYPEOF: { - return ParseUnaryOrPrefixUpdateExpression(); - } - default: { - return ParseLeftHandSideExpression(flags); - } - } -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *ETSParser::ParseUnaryOrPrefixUpdateExpression(ExpressionParseFlags flags) -{ - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: - case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: - case lexer::TokenType::PUNCTUATOR_PLUS: - case lexer::TokenType::PUNCTUATOR_MINUS: - case lexer::TokenType::PUNCTUATOR_TILDE: - case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: - case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: - case lexer::TokenType::KEYW_TYPEOF: { - break; - } - case lexer::TokenType::KEYW_LAUNCH: { - return ParseLaunchExpression(flags); - } - default: { - return ParseLeftHandSideExpression(flags); - } - } - - lexer::TokenType operatorType = Lexer()->GetToken().Type(); - auto start = Lexer()->GetToken().Start(); - Lexer()->NextToken(); - - ir::Expression *argument = ResolveArgumentUnaryExpr(flags); - - if (lexer::Token::IsUpdateToken(operatorType)) { - if (!argument->IsIdentifier() && !argument->IsMemberExpression()) { - ThrowSyntaxError("Invalid left-hand side in prefix operation"); - } - } - - lexer::SourcePosition end = argument->End(); - - ir::Expression *returnExpr = nullptr; - if (lexer::Token::IsUpdateToken(operatorType)) { - returnExpr = AllocNode(argument, operatorType, true); - } else if (operatorType == lexer::TokenType::KEYW_TYPEOF) { - returnExpr = AllocNode(argument); - } else { - returnExpr = AllocNode(argument, operatorType); - } - - returnExpr->SetRange({start, end}); - - return returnExpr; -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *ETSParser::ParseDefaultPrimaryExpression(ExpressionParseFlags flags) -{ - auto startLoc = Lexer()->GetToken().Start(); - auto savedPos = Lexer()->Save(); - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL | - TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | - TypeAnnotationParsingOptions::DISALLOW_UNION; - ir::TypeNode *potentialType = ParseTypeAnnotation(&options); - - if (potentialType != nullptr) { - if (potentialType->IsTSArrayType()) { - return potentialType; - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { - Lexer()->NextToken(); // eat '.' - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword()) { - Lexer()->NextToken(); // eat 'class' and 'struct' - auto *classLiteral = AllocNode(potentialType); - classLiteral->SetRange({startLoc, Lexer()->GetToken().End()}); - return classLiteral; - } - } - - Lexer()->Rewind(savedPos); - - Lexer()->NextToken(); - bool pretendArrow = Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW; - Lexer()->Rewind(savedPos); - - if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && !pretendArrow) { - return ParsePrimaryExpressionIdent(flags); - } - - ThrowSyntaxError({"Unexpected token '", lexer::TokenToString(Lexer()->GetToken().Type()), "'."}); - return nullptr; -} - -ir::Expression *ETSParser::ParsePrimaryExpressionWithLiterals(ExpressionParseFlags flags) -{ - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::LITERAL_TRUE: - case lexer::TokenType::LITERAL_FALSE: { - return ParseBooleanLiteral(); - } - case lexer::TokenType::LITERAL_NULL: { - return ParseNullLiteral(); - } - case lexer::TokenType::KEYW_UNDEFINED: { - return ParseUndefinedLiteral(); - } - case lexer::TokenType::LITERAL_NUMBER: { - return ParseCoercedNumberLiteral(); - } - case lexer::TokenType::LITERAL_STRING: { - return ParseStringLiteral(); - } - case lexer::TokenType::LITERAL_CHAR: { - return ParseCharLiteral(); - } - default: { - return ParseDefaultPrimaryExpression(flags); - } - } -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *ETSParser::ParsePrimaryExpression(ExpressionParseFlags flags) -{ - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { - return ParseCoverParenthesizedExpressionAndArrowParameterList(flags); - } - case lexer::TokenType::KEYW_THIS: { - return ParseThisExpression(); - } - case lexer::TokenType::KEYW_SUPER: { - return ParseSuperExpression(); - } - case lexer::TokenType::KEYW_NEW: { - return ParseNewExpression(); - } - case lexer::TokenType::KEYW_ASYNC: { - return ParseAsyncExpression(); - } - case lexer::TokenType::KEYW_AWAIT: { - return ParseAwaitExpression(); - } - case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { - return ParseArrayExpression(CarryPatternFlags(flags)); - } - case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { - return ParseObjectExpression(CarryPatternFlags(flags)); - } - case lexer::TokenType::PUNCTUATOR_BACK_TICK: { - return ParseTemplateLiteral(); - } - case lexer::TokenType::KEYW_TYPE: { - ThrowSyntaxError("Type alias is allowed only as top-level declaration"); - } - case lexer::TokenType::PUNCTUATOR_FORMAT: { - return ParseExpressionFormatPlaceholder(); - } - case lexer::TokenType::KEYW_TYPEOF: { - return ParseUnaryOrPrefixUpdateExpression(); - } - default: { - return ParsePrimaryExpressionWithLiterals(flags); - } - } -} - -bool IsPunctuartorSpecialCharacter(lexer::TokenType tokenType) -{ - switch (tokenType) { - case lexer::TokenType::PUNCTUATOR_COLON: - case lexer::TokenType::PUNCTUATOR_COMMA: - case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: - case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: - case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: - case lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET: - case lexer::TokenType::PUNCTUATOR_LESS_THAN: - case lexer::TokenType::PUNCTUATOR_GREATER_THAN: - case lexer::TokenType::PUNCTUATOR_BITWISE_OR: - return true; - default: - return false; - } -} - ir::Expression *ETSParser::ParseExpressionOrTypeAnnotation(lexer::TokenType type, [[maybe_unused]] ExpressionParseFlags flags) { @@ -3260,93 +1453,6 @@ ir::Expression *ETSParser::ParseExpressionOrTypeAnnotation(lexer::TokenType type return ParseExpression(ExpressionParseFlags::DISALLOW_YIELD); } -bool ETSParser::IsArrowFunctionExpressionStart() -{ - const auto savedPos = Lexer()->Save(); - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); - Lexer()->NextToken(); - auto tokenType = Lexer()->GetToken().Type(); - - size_t openBrackets = 1; - bool expectIdentifier = true; - while (tokenType != lexer::TokenType::EOS && openBrackets > 0) { - switch (tokenType) { - case lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS: - --openBrackets; - break; - case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: - ++openBrackets; - break; - case lexer::TokenType::PUNCTUATOR_COMMA: - expectIdentifier = true; - break; - case lexer::TokenType::PUNCTUATOR_SEMI_COLON: - Lexer()->Rewind(savedPos); - return false; - default: - if (!expectIdentifier) { - break; - } - if (tokenType != lexer::TokenType::LITERAL_IDENT && - tokenType != lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { - Lexer()->Rewind(savedPos); - return false; - } - expectIdentifier = false; - } - Lexer()->NextToken(); - tokenType = Lexer()->GetToken().Type(); - } - - while (tokenType != lexer::TokenType::EOS && tokenType != lexer::TokenType::PUNCTUATOR_ARROW) { - if (lexer::Token::IsPunctuatorToken(tokenType) && !IsPunctuartorSpecialCharacter(tokenType)) { - break; - } - Lexer()->NextToken(); - tokenType = Lexer()->GetToken().Type(); - } - Lexer()->Rewind(savedPos); - return tokenType == lexer::TokenType::PUNCTUATOR_ARROW; -} - -ir::ArrowFunctionExpression *ETSParser::ParseArrowFunctionExpression() -{ - auto newStatus = ParserStatus::ARROW_FUNCTION; - auto *func = ParseFunction(newStatus); - auto *arrowFuncNode = AllocNode(func); - arrowFuncNode->SetRange(func->Range()); - return arrowFuncNode; -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *ETSParser::ParseCoverParenthesizedExpressionAndArrowParameterList(ExpressionParseFlags flags) -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); - if (IsArrowFunctionExpressionStart()) { - return ParseArrowFunctionExpression(); - } - - lexer::SourcePosition start = Lexer()->GetToken().Start(); - Lexer()->NextToken(); - - ExpressionParseFlags newFlags = ExpressionParseFlags::ACCEPT_COMMA; - if ((flags & ExpressionParseFlags::INSTANCEOF) != 0) { - newFlags |= ExpressionParseFlags::INSTANCEOF; - }; - - ir::Expression *expr = ParseExpression(newFlags); - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - ThrowSyntaxError("Unexpected token, expected ')'"); - } - - expr->SetGrouped(); - expr->SetRange({start, Lexer()->GetToken().End()}); - Lexer()->NextToken(); - - return expr; -} - bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, ir::Expression **returnExpression, [[maybe_unused]] const lexer::SourcePosition &startLoc, bool ignoreCallExpression) @@ -3389,224 +1495,6 @@ bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, i return true; } -ir::Expression *ETSParser::ParsePostPrimaryExpression(ir::Expression *primaryExpr, lexer::SourcePosition startLoc, - bool ignoreCallExpression, - [[maybe_unused]] bool *isChainExpression) -{ - ir::Expression *returnExpression = primaryExpr; - - while (true) { - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::PUNCTUATOR_QUESTION_DOT: { - if (*isChainExpression) { - break; // terminate current chain - } - *isChainExpression = true; - Lexer()->NextToken(); // eat ?. - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { - returnExpression = ParseElementAccess(returnExpression, true); - continue; - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { - returnExpression = ParseCallExpression(returnExpression, true, false); - continue; - } - - returnExpression = ParsePropertyAccess(returnExpression, true); - continue; - } - case lexer::TokenType::PUNCTUATOR_PERIOD: { - Lexer()->NextToken(); // eat period - - returnExpression = ParsePropertyAccess(returnExpression); - continue; - } - case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { - returnExpression = ParseElementAccess(returnExpression); - continue; - } - case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: - case lexer::TokenType::PUNCTUATOR_LESS_THAN: { - if (ParsePotentialGenericFunctionCall(returnExpression, &returnExpression, startLoc, - ignoreCallExpression)) { - break; - } - - continue; - } - case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { - if (ignoreCallExpression) { - break; - } - returnExpression = ParseCallExpression(returnExpression, false, false); - continue; - } - case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { - const bool shouldBreak = ParsePotentialNonNullExpression(&returnExpression, startLoc); - if (shouldBreak) { - break; - } - - continue; - } - case lexer::TokenType::PUNCTUATOR_FORMAT: { - ThrowUnexpectedToken(lexer::TokenType::PUNCTUATOR_FORMAT); - } - default: { - break; - } - } - - break; - } - - return returnExpression; -} - -ir::Expression *ETSParser::ParsePotentialAsExpression(ir::Expression *primaryExpr) -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_AS); - Lexer()->NextToken(); - - TypeAnnotationParsingOptions options = - TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_INTERSECTION; - ir::TypeNode *type = ParseTypeAnnotation(&options); - - auto *asExpression = AllocNode(primaryExpr, type, false); - asExpression->SetRange(primaryExpr->Range()); - return asExpression; -} - -// Extracted from 'ParseNewExpression()' to reduce function's size -ir::ClassDefinition *ETSParser::CreateClassDefinitionForNewExpression(ArenaVector &arguments, - ir::TypeNode *typeReference, - ir::TypeNode *baseTypeReference) -{ - lexer::SourcePosition endLoc = typeReference->End(); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { - if (baseTypeReference != nullptr) { - ThrowSyntaxError("Can not use 'new' on primitive types.", baseTypeReference->Start()); - } - - Lexer()->NextToken(); - - while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - ir::Expression *argument = ParseExpression(); - arguments.push_back(argument); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { - Lexer()->NextToken(); - continue; - } - } - - endLoc = Lexer()->GetToken().End(); - Lexer()->NextToken(); - } - - ir::ClassDefinition *classDefinition {}; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - ArenaVector implements(Allocator()->Adapter()); - auto modifiers = ir::ClassDefinitionModifiers::ANONYMOUS | ir::ClassDefinitionModifiers::HAS_SUPER; - auto [ctor, properties, bodyRange] = ParseClassBody(modifiers); - - auto newIdent = AllocNode("#0", Allocator()); - classDefinition = AllocNode( - "#0", newIdent, nullptr, nullptr, std::move(implements), ctor, // remove name - typeReference->Clone(Allocator(), nullptr), std::move(properties), modifiers, ir::ModifierFlags::NONE, - Language(Language::Id::ETS)); - - classDefinition->SetRange(bodyRange); - } - - return classDefinition; -} - -ir::Expression *ETSParser::ParseNewExpression() -{ - lexer::SourcePosition start = Lexer()->GetToken().Start(); - - Lexer()->NextToken(); // eat new - - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - ir::TypeNode *baseTypeReference = ParseBaseTypeReference(&options); - ir::TypeNode *typeReference = baseTypeReference; - if (typeReference == nullptr) { - options |= TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | TypeAnnotationParsingOptions::ALLOW_WILDCARD; - typeReference = ParseTypeReference(&options); - } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - ThrowSyntaxError("Invalid { after base types."); - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { - Lexer()->NextToken(); - ir::Expression *dimension = ParseExpression(); - - auto endLoc = Lexer()->GetToken().End(); - ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET); - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { - auto *arrInstance = AllocNode(typeReference, dimension); - arrInstance->SetRange({start, endLoc}); - return arrInstance; - } - - ArenaVector dimensions(Allocator()->Adapter()); - dimensions.push_back(dimension); - - do { - Lexer()->NextToken(); - dimensions.push_back(ParseExpression()); - - endLoc = Lexer()->GetToken().End(); - ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET); - } while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET); - - auto *multiArray = AllocNode(typeReference, std::move(dimensions)); - multiArray->SetRange({start, endLoc}); - return multiArray; - } - - ArenaVector arguments(Allocator()->Adapter()); - ir::ClassDefinition *classDefinition = - CreateClassDefinitionForNewExpression(arguments, typeReference, baseTypeReference); - - auto *newExprNode = - AllocNode(typeReference, std::move(arguments), classDefinition); - newExprNode->SetRange({start, Lexer()->GetToken().End()}); - - return newExprNode; -} - -ir::Expression *ETSParser::ParseAsyncExpression() -{ - Lexer()->NextToken(); // eat 'async' - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS || - !IsArrowFunctionExpressionStart()) { - ThrowSyntaxError("Unexpected token. expected '('"); - } - - auto newStatus = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ARROW_FUNCTION | ParserStatus::ASYNC_FUNCTION; - auto *func = ParseFunction(newStatus); - auto *arrowFuncNode = AllocNode(func); - arrowFuncNode->SetRange(func->Range()); - return arrowFuncNode; -} - -ir::Expression *ETSParser::ParseAwaitExpression() -{ - lexer::SourcePosition start = Lexer()->GetToken().Start(); - Lexer()->NextToken(); - ir::Expression *argument = ParseExpression(); - auto *awaitExpression = AllocNode(argument); - awaitExpression->SetRange({start, Lexer()->GetToken().End()}); - return awaitExpression; -} - ir::ModifierFlags ETSParser::ParseTypeVarianceModifier(TypeAnnotationParsingOptions *const options) { if ((*options & TypeAnnotationParsingOptions::ALLOW_WILDCARD) == 0 && @@ -3692,9 +1580,8 @@ ir::TSTypeParameter *ETSParser::ParseTypeParameter([[maybe_unused]] TypeAnnotati ir::TypeNode *constraint = nullptr; if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) { Lexer()->NextToken(); - TypeAnnotationParsingOptions newOptions = TypeAnnotationParsingOptions::THROW_ERROR | - TypeAnnotationParsingOptions::ALLOW_INTERSECTION | - TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE; + TypeAnnotationParsingOptions newOptions = + TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE; constraint = ParseTypeAnnotation(&newOptions); } @@ -3711,423 +1598,17 @@ ir::TSTypeParameter *ETSParser::ParseTypeParameter([[maybe_unused]] TypeAnnotati return typeParam; } -// NOLINTBEGIN(cert-err58-cpp) -static std::string const DUPLICATE_ENUM_VALUE = "Duplicate enum initialization value "s; -static std::string const INVALID_ENUM_TYPE = "Invalid enum initialization type"s; -static std::string const INVALID_ENUM_VALUE = "Invalid enum initialization value"s; -static std::string const MISSING_COMMA_IN_ENUM = "Missing comma between enum constants"s; -static std::string const TRAILING_COMMA_IN_ENUM = "Trailing comma is not allowed in enum constant list"s; -// NOLINTEND(cert-err58-cpp) - -ir::TSEnumDeclaration *ETSParser::ParseEnumMembers(ir::Identifier *const key, const lexer::SourcePosition &enumStart, - const bool isConst, const bool isStatic) -{ - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { - ThrowSyntaxError("'{' expected"); - } - - Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat '{' - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - ThrowSyntaxError("An enum must have at least one enum constant"); - } - - // Lambda to check if enum underlying type is string: - auto const isStringEnum = [this]() -> bool { - Lexer()->NextToken(); - auto tokenType = Lexer()->GetToken().Type(); - while (tokenType != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE && - tokenType != lexer::TokenType::PUNCTUATOR_COMMA) { - if (tokenType == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { - Lexer()->NextToken(); - if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_STRING) { - return true; - } - } - Lexer()->NextToken(); - tokenType = Lexer()->GetToken().Type(); - } - return false; - }; - - // Get the underlying type of enum (number or string). It is defined from the first element ONLY! - auto const pos = Lexer()->Save(); - auto const stringTypeEnum = isStringEnum(); - Lexer()->Rewind(pos); - - ArenaVector members(Allocator()->Adapter()); - - if (stringTypeEnum) { - ParseStringEnum(members); - } else { - ParseNumberEnum(members); - } - - auto *const enumDeclaration = AllocNode( - Allocator(), key, std::move(members), - ir::TSEnumDeclaration::ConstructorFlags {isConst, isStatic, InAmbientContext()}); - enumDeclaration->SetRange({enumStart, Lexer()->GetToken().End()}); - - Lexer()->NextToken(); // eat '}' - - return enumDeclaration; -} - -void ETSParser::ParseNumberEnum(ArenaVector &members) -{ - checker::ETSEnumType::ValueType currentValue {}; - - // Lambda to parse enum member (maybe with initializer) - auto const parseMember = [this, &members, ¤tValue]() { - auto *const ident = ExpectIdentifier(false, true); - - ir::NumberLiteral *ordinal; - lexer::SourcePosition endLoc; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { - // Case when user explicitly set the value for enumeration constant - - bool minusSign = false; - - Lexer()->NextToken(); - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PLUS) { - Lexer()->NextToken(); - } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS) { - minusSign = true; - Lexer()->NextToken(); - } - - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NUMBER) { - ThrowSyntaxError(INVALID_ENUM_TYPE); - } - - ordinal = ParseNumberLiteral()->AsNumberLiteral(); - if (minusSign) { - ordinal->Number().Negate(); - } - if (!ordinal->Number().CanGetValue()) { - ThrowSyntaxError(INVALID_ENUM_VALUE); - } - - currentValue = ordinal->Number().GetValue(); - - endLoc = ordinal->End(); - } else { - // Default enumeration constant value. Equal to 0 for the first item and = previous_value + 1 for all - // the others. - - ordinal = AllocNode(lexer::Number(currentValue)); - - endLoc = ident->End(); - } - - auto *const member = AllocNode(ident, ordinal); - member->SetRange({ident->Start(), endLoc}); - members.emplace_back(member); - - ++currentValue; - }; - - parseMember(); - - while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) { - ThrowSyntaxError(MISSING_COMMA_IN_ENUM); - } - - Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ',' - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - break; - } - - parseMember(); - } -} - -void ETSParser::ParseStringEnum(ArenaVector &members) -{ - // Lambda to parse enum member (maybe with initializer) - auto const parseMember = [this, &members]() { - auto *const ident = ExpectIdentifier(); - - ir::StringLiteral *itemValue; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { - // Case when user explicitly set the value for enumeration constant - - Lexer()->NextToken(); - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { - ThrowSyntaxError(INVALID_ENUM_TYPE); - } - - itemValue = ParseStringLiteral(); - } else { - // Default item value is not allowed for string type enumerations! - ThrowSyntaxError("All items of string-type enumeration should be explicitly initialized."); - } - - auto *const member = AllocNode(ident, itemValue); - member->SetRange({ident->Start(), itemValue->End()}); - members.emplace_back(member); - }; - - parseMember(); - - while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) { - ThrowSyntaxError(MISSING_COMMA_IN_ENUM); - } - - Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ',' - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { - ThrowSyntaxError(TRAILING_COMMA_IN_ENUM); - } - - parseMember(); - } -} - -ir::ThisExpression *ETSParser::ParseThisExpression() -{ - auto *thisExpression = TypedParser::ParseThisExpression(); - - if (Lexer()->GetToken().NewLine()) { - return thisExpression; - } - - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::PUNCTUATOR_PERIOD: - case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: - case lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS: - case lexer::TokenType::PUNCTUATOR_SEMI_COLON: - case lexer::TokenType::PUNCTUATOR_COLON: - case lexer::TokenType::PUNCTUATOR_EQUAL: - case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: - case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: - case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: - case lexer::TokenType::PUNCTUATOR_COMMA: - case lexer::TokenType::PUNCTUATOR_QUESTION_MARK: - case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: - case lexer::TokenType::KEYW_INSTANCEOF: - case lexer::TokenType::KEYW_AS: { - break; - } - default: { - ThrowUnexpectedToken(Lexer()->GetToken().Type()); - break; - } - } - - return thisExpression; -} - ir::Identifier *ETSParser::ParseClassIdent([[maybe_unused]] ir::ClassDefinitionModifiers modifiers) { return ExpectIdentifier(false, true); } -// NOLINTNEXTLINE(google-default-arguments) -ir::ClassDeclaration *ETSParser::ParseClassStatement([[maybe_unused]] StatementParsingFlags flags, - ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags modFlags) -{ - return ParseClassDeclaration(modifiers | ir::ClassDefinitionModifiers::ID_REQUIRED | - ir::ClassDefinitionModifiers::CLASS_DECL | ir::ClassDefinitionModifiers::LOCAL, - modFlags); -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::ETSStructDeclaration *ETSParser::ParseStructStatement([[maybe_unused]] StatementParsingFlags flags, - [[maybe_unused]] ir::ClassDefinitionModifiers modifiers, - [[maybe_unused]] ir::ModifierFlags modFlags) -{ - ThrowSyntaxError("Illegal start of expression", Lexer()->GetToken().Start()); -} - -bool ETSParser::CheckClassElement(ir::AstNode *property, [[maybe_unused]] ir::MethodDefinition *&ctor, - [[maybe_unused]] ArenaVector &properties) -{ - if (property->IsClassStaticBlock()) { - if (std::any_of(properties.cbegin(), properties.cend(), - [](const auto *prop) { return prop->IsClassStaticBlock(); })) { - ThrowSyntaxError("Only one static block is allowed", property->Start()); - } - - auto *id = AllocNode(compiler::Signatures::CCTOR, Allocator()); - property->AsClassStaticBlock()->Function()->SetIdent(id); - } - - if (property->IsTSInterfaceBody()) { - return CheckClassElementInterfaceBody(property, properties); - } - - if (!property->IsMethodDefinition()) { - return false; - } - - auto const *const method = property->AsMethodDefinition(); - auto const *const function = method->Function(); - - // Check the special '$_get' and '$_set' methods using for object's index access - if (method->Kind() == ir::MethodDefinitionKind::METHOD) { - CheckPredefinedMethods(function, property->Start()); - } - - return false; // resolve overloads later on scopes stage -} - -void ETSParser::CheckPredefinedMethods(ir::ScriptFunction const *function, const lexer::SourcePosition &position) const -{ - auto const name = function->Id()->Name(); - - auto const checkAsynchronous = [this, function, &name, &position]() -> void { - if (function->IsAsyncFunc()) { - ThrowSyntaxError(std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()} + - std::string {"' cannot be asynchronous."}, - position); - } - }; - - if (name.Is(compiler::Signatures::GET_INDEX_METHOD)) { - checkAsynchronous(); - - bool isValid = function->Params().size() == 1U; - if (isValid) { - auto const *const param = function->Params()[0]->AsETSParameterExpression(); - isValid = !param->IsDefault() && !param->IsRestParameter(); - } - - if (!isValid) { - ThrowSyntaxError(std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()} + - std::string {"' should have exactly one required parameter."}, - position); - } - } else if (name.Is(compiler::Signatures::SET_INDEX_METHOD)) { - checkAsynchronous(); - - bool isValid = function->Params().size() == 2U; - if (isValid) { - auto const *const param1 = function->Params()[0]->AsETSParameterExpression(); - auto const *const param2 = function->Params()[1]->AsETSParameterExpression(); - isValid = !param1->IsDefault() && !param1->IsRestParameter() && !param2->IsDefault() && - !param2->IsRestParameter(); - } - - if (!isValid) { - ThrowSyntaxError(std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()} + - std::string {"' should have exactly two required parameters."}, - position); - } - } else if (name.Is(compiler::Signatures::ITERATOR_METHOD)) { - checkAsynchronous(); - - if (!function->Params().empty()) { - ThrowSyntaxError(std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()} + - std::string {"' should not have parameters."}, - position); - } - } -} - -void ETSParser::CreateImplicitConstructor([[maybe_unused]] ir::MethodDefinition *&ctor, - ArenaVector &properties, - [[maybe_unused]] ir::ClassDefinitionModifiers modifiers, - const lexer::SourcePosition &startLoc) -{ - if (std::any_of(properties.cbegin(), properties.cend(), [](ir::AstNode *prop) { - return prop->IsMethodDefinition() && prop->AsMethodDefinition()->IsConstructor(); - })) { - return; - } - - if ((modifiers & ir::ClassDefinitionModifiers::ANONYMOUS) != 0) { - return; - } - - auto *methodDef = BuildImplicitConstructor(ir::ClassDefinitionModifiers::SET_CTOR_ID, startLoc); - properties.push_back(methodDef); -} - -ir::Expression *ETSParser::ParsePotentialExpressionSequence(ir::Expression *expr, ExpressionParseFlags flags) -{ - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA && - (flags & ExpressionParseFlags::ACCEPT_COMMA) != 0 && (flags & ExpressionParseFlags::IN_FOR) != 0U) { - return ParseSequenceExpression(expr, (flags & ExpressionParseFlags::ACCEPT_REST) != 0); - } - - return expr; -} - -bool ETSParser::ParsePotentialNonNullExpression(ir::Expression **expression, const lexer::SourcePosition startLoc) -{ - if (expression == nullptr || Lexer()->GetToken().NewLine()) { - return true; - } - - const auto nonNullExpr = AllocNode(*expression); - nonNullExpr->SetRange({startLoc, Lexer()->GetToken().End()}); - - *expression = nonNullExpr; - - Lexer()->NextToken(); - - return false; -} - bool ETSParser::IsStructKeyword() const { return (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT); } -void ETSParser::ValidateInstanceOfExpression(ir::Expression *expr) -{ - ValidateGroupedExpression(expr); - lexer::TokenType tokenType = Lexer()->GetToken().Type(); - if (tokenType == lexer::TokenType::PUNCTUATOR_LESS_THAN) { - auto options = TypeAnnotationParsingOptions::NO_OPTS; - - // Run checks to validate type declarations - // Should provide helpful messages with incorrect declarations like the following: - // `instanceof A;` - ThrowSyntaxError("Invalid right-hand side in 'instanceof' expression"); - } -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *ETSParser::ParseExpression(ExpressionParseFlags flags) -{ - if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_YIELD && - (flags & ExpressionParseFlags::DISALLOW_YIELD) == 0U) { - ir::YieldExpression *yieldExpr = ParseYieldExpression(); - - return ParsePotentialExpressionSequence(yieldExpr, flags); - } - - ir::Expression *unaryExpressionNode = ParseUnaryOrPrefixUpdateExpression(flags); - if ((flags & ExpressionParseFlags::INSTANCEOF) != 0) { - ValidateInstanceOfExpression(unaryExpressionNode); - } - - ir::Expression *assignmentExpression = ParseAssignmentExpression(unaryExpressionNode, flags); - - if (Lexer()->GetToken().NewLine()) { - return assignmentExpression; - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA && - (flags & ExpressionParseFlags::ACCEPT_COMMA) != 0U && (flags & ExpressionParseFlags::IN_FOR) != 0U) { - return ParseSequenceExpression(assignmentExpression, (flags & ExpressionParseFlags::ACCEPT_REST) != 0U); - } - - return assignmentExpression; -} - void ETSParser::ParseTrailingBlock(ir::CallExpression *callExpr) { if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { @@ -4234,49 +1715,6 @@ ir::FunctionDeclaration *ETSParser::ParseFunctionDeclaration(bool canBeAnonymous return funcDecl; } -std::pair ETSParser::ParseMemberModifiers() -{ - auto memberModifiers = ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC; - - if (Lexer()->TryEatTokenType(lexer::TokenType::KEYW_EXPORT)) { - const auto savedPos = Lexer()->Save(); - if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_DEFAULT)) { - memberModifiers |= ir::ModifierFlags::DEFAULT_EXPORT; - } else if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_TYPE)) { - if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { - Lexer()->Rewind(savedPos); - } - memberModifiers |= ir::ModifierFlags::EXPORT_TYPE; - } else { - memberModifiers |= ir::ModifierFlags::EXPORT; - } - } - - lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); - - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE) { - CheckDeclare(); - memberModifiers |= ir::ModifierFlags::DECLARE; - } - const auto tokenType = Lexer()->GetToken().KeywordType(); - if (tokenType == lexer::TokenType::KEYW_ASYNC || tokenType == lexer::TokenType::KEYW_NATIVE) { - bool isAsync = tokenType == lexer::TokenType::KEYW_ASYNC; - - if (isAsync) { - memberModifiers |= ir::ModifierFlags::ASYNC; - } else { - memberModifiers |= ir::ModifierFlags::NATIVE; - } - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) { - ThrowSyntaxError( - {isAsync ? "'async'" : "'native'", " flags must be used for functions only at top-level."}); - } - } - return std::make_pair(memberModifiers, startLoc); -} - //================================================================================================// // ExternalSourceParser class //================================================================================================// diff --git a/ets2panda/parser/ETSparser.h b/ets2panda/parser/ETSparser.h index 61c6cae57da54975686abb30ad968d53bc29ee6d..d5d8c6dd0435ad1ec729cc2df55b2f41e958f9ea 100644 --- a/ets2panda/parser/ETSparser.h +++ b/ets2panda/parser/ETSparser.h @@ -268,6 +268,7 @@ private: ir::MethodDefinition *ParseInterfaceMethod(ir::ModifierFlags flags, ir::MethodDefinitionKind methodKind); std::tuple ParseClassMemberAccessModifiers(); ir::ModifierFlags ParseClassFieldModifiers(bool seenStatic); + ir::ModifierFlags ParseClassMethodModifierFlag(); ir::ModifierFlags ParseClassMethodModifiers(bool seenStatic); ir::MethodDefinition *ParseClassMethodDefinition(ir::Identifier *methodName, ir::ModifierFlags modifiers, ir::Identifier *className = nullptr); @@ -289,7 +290,6 @@ private: ir::TypeNode *ParseBaseTypeReference(TypeAnnotationParsingOptions *options); ir::TypeNode *ParsePrimitiveType(TypeAnnotationParsingOptions *options, ir::PrimitiveType type); ir::TypeNode *ParseUnionType(ir::TypeNode *firstType); - ir::TSIntersectionType *ParseIntersectionType(ir::Expression *type); ir::TypeNode *GetTypeAnnotationOfPrimitiveType(lexer::TokenType tokenType, TypeAnnotationParsingOptions *options); ir::TypeNode *ParseWildcardType(TypeAnnotationParsingOptions *options); ir::TypeNode *ParseFunctionType(); @@ -304,6 +304,8 @@ private: void ThrowIfVarDeclaration(VariableParsingFlags flags) override; std::optional GetDefaultParamPosition(ArenaVector params); + + ir::TypeNode *ParsePotentialFunctionalType(TypeAnnotationParsingOptions *options, lexer::SourcePosition startLoc); std::pair GetTypeAnnotationFromToken(TypeAnnotationParsingOptions *options); ir::TypeNode *ParseLiteralIdent(TypeAnnotationParsingOptions *options); void ParseRightParenthesis(TypeAnnotationParsingOptions *options, ir::TypeNode *&typeAnnotation, @@ -378,6 +380,7 @@ private: ir::Expression *ParseAwaitExpression(); ir::TSTypeParameter *ParseTypeParameter(TypeAnnotationParsingOptions *options) override; + bool IsStringEnum(); ir::TSEnumDeclaration *ParseEnumMembers(ir::Identifier *key, const lexer::SourcePosition &enumStart, bool isConst, bool isStatic) override; void ParseNumberEnum(ArenaVector &members); diff --git a/ets2panda/parser/ETSparserClasses.cpp b/ets2panda/parser/ETSparserClasses.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cea03077a946bc93727260416ff539177251c4c9 --- /dev/null +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -0,0 +1,1096 @@ +/** + * Copyright (c) 2021-2024 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. + */ + +#include "ETSparser.h" +#include "ETSNolintParser.h" +#include + +#include "macros.h" +#include "parser/parserFlags.h" +#include "parser/parserStatusContext.h" +#include "util/helpers.h" +#include "util/language.h" +#include "utils/arena_containers.h" +#include "varbinder/varbinder.h" +#include "varbinder/ETSBinder.h" +#include "lexer/lexer.h" +#include "lexer/ETSLexer.h" +#include "checker/types/ets/etsEnumType.h" +#include "ir/astNode.h" +#include "ir/base/classDefinition.h" +#include "ir/base/decorator.h" +#include "ir/base/catchClause.h" +#include "ir/base/classProperty.h" +#include "ir/base/scriptFunction.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/classStaticBlock.h" +#include "ir/base/spreadElement.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/functionExpression.h" +#include "ir/expressions/dummyNode.h" +#include "ir/module/importDeclaration.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/importSpecifier.h" +#include "ir/module/exportSpecifier.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/statements/assertStatement.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/ifStatement.h" +#include "ir/statements/labelledStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/whileStatement.h" +#include "ir/statements/forOfStatement.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/breakStatement.h" +#include "ir/statements/debuggerStatement.h" +#include "ir/ets/etsLaunchExpression.h" +#include "ir/ets/etsClassLiteral.h" +#include "ir/ets/etsPrimitiveType.h" +#include "ir/ets/etsPackageDeclaration.h" +#include "ir/ets/etsReExportDeclaration.h" +#include "ir/ets/etsWildcardType.h" +#include "ir/ets/etsNewArrayInstanceExpression.h" +#include "ir/ets/etsTuple.h" +#include "ir/ets/etsFunctionType.h" +#include "ir/ets/etsNewClassInstanceExpression.h" +#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" +#include "ir/ets/etsScript.h" +#include "ir/ets/etsTypeReference.h" +#include "ir/ets/etsTypeReferencePart.h" +#include "ir/ets/etsNullishTypes.h" +#include "ir/ets/etsUnionType.h" +#include "ir/ets/etsImportSource.h" +#include "ir/ets/etsImportDeclaration.h" +#include "ir/ets/etsStructDeclaration.h" +#include "ir/ets/etsParameterExpression.h" +#include "ir/module/importNamespaceSpecifier.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsEnumDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsInterfaceBody.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsEnumMember.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsNonNullExpression.h" +#include "ir/ts/tsThisType.h" +#include "generated/signatures.h" + +namespace ark::es2panda::parser { +class FunctionContext; + +using namespace std::literals::string_literals; + +static bool IsClassModifier(lexer::TokenType type) +{ + return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_ABSTRACT || + type == lexer::TokenType::KEYW_FINAL; +} + +ir::ModifierFlags ETSParser::ParseClassModifiers() +{ + ir::ModifierFlags flags = ir::ModifierFlags::NONE; + + while (IsClassModifier(Lexer()->GetToken().KeywordType())) { + ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; + + lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); + if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { + ThrowSyntaxError("Keyword must not contain escaped characters"); + } + + switch (Lexer()->GetToken().KeywordType()) { + case lexer::TokenType::KEYW_STATIC: { + currentFlag = ir::ModifierFlags::STATIC; + break; + } + case lexer::TokenType::KEYW_FINAL: { + currentFlag = ir::ModifierFlags::FINAL; + break; + } + case lexer::TokenType::KEYW_ABSTRACT: { + currentFlag = ir::ModifierFlags::ABSTRACT; + break; + } + default: { + UNREACHABLE(); + } + } + + if ((flags & currentFlag) != 0) { + ThrowSyntaxError("Duplicated modifier is not allowed"); + } + + Lexer()->NextToken(); + flags |= currentFlag; + } + + return flags; +} + +std::tuple ETSParser::ParseClassImplementsElement() +{ + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | + TypeAnnotationParsingOptions::ALLOW_WILDCARD; + return {ParseTypeReference(&options), nullptr}; +} + +ir::Expression *ETSParser::ParseSuperClassReference() +{ + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) { + Lexer()->NextToken(); + + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | + TypeAnnotationParsingOptions::ALLOW_WILDCARD; + return ParseTypeReference(&options); + } + + return nullptr; +} + +ir::TypeNode *ETSParser::ParseInterfaceExtendsElement() +{ + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | + TypeAnnotationParsingOptions::ALLOW_WILDCARD; + return ParseTypeReference(&options); +} + +static bool IsClassMemberAccessModifier(lexer::TokenType type) +{ + return type == lexer::TokenType::KEYW_PUBLIC || type == lexer::TokenType::KEYW_PRIVATE || + type == lexer::TokenType::KEYW_PROTECTED || type == lexer::TokenType::KEYW_INTERNAL; +} + +std::tuple ETSParser::ParseClassMemberAccessModifiers() +{ + if (!IsClassMemberAccessModifier(Lexer()->GetToken().Type())) { + return {ir::ModifierFlags::PUBLIC, false}; + } + + char32_t nextCp = Lexer()->Lookahead(); + if (!(nextCp != lexer::LEX_CHAR_EQUALS && nextCp != lexer::LEX_CHAR_COLON && + nextCp != lexer::LEX_CHAR_LEFT_PAREN)) { + return {ir::ModifierFlags::NONE, false}; + } + + lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); + if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { + ThrowSyntaxError("Keyword must not contain escaped characters"); + } + + ir::ModifierFlags accessFlag = ir::ModifierFlags::NONE; + + switch (Lexer()->GetToken().KeywordType()) { + case lexer::TokenType::KEYW_PUBLIC: { + accessFlag = ir::ModifierFlags::PUBLIC; + break; + } + case lexer::TokenType::KEYW_PRIVATE: { + accessFlag = ir::ModifierFlags::PRIVATE; + break; + } + case lexer::TokenType::KEYW_PROTECTED: { + accessFlag = ir::ModifierFlags::PROTECTED; + break; + } + case lexer::TokenType::KEYW_INTERNAL: { + Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); + if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_PROTECTED) { + accessFlag = ir::ModifierFlags::INTERNAL; + return {accessFlag, true}; + } + accessFlag = ir::ModifierFlags::INTERNAL_PROTECTED; + break; + } + default: { + UNREACHABLE(); + } + } + if (((GetContext().Status() & ParserStatus::FUNCTION) != 0) && + (accessFlag == ir::ModifierFlags::PUBLIC || accessFlag == ir::ModifierFlags::PRIVATE || + accessFlag == ir::ModifierFlags::PROTECTED)) { + ThrowSyntaxError("Local class declaration members can not have access modifies", Lexer()->GetToken().Start()); + } + + Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); + return {accessFlag, true}; +} + +static bool IsClassFieldModifier(lexer::TokenType type) +{ + return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_READONLY; +} + +ir::ModifierFlags ETSParser::ParseClassFieldModifiers(bool seenStatic) +{ + ir::ModifierFlags flags = seenStatic ? ir::ModifierFlags::STATIC : ir::ModifierFlags::NONE; + + while (IsClassFieldModifier(Lexer()->GetToken().KeywordType())) { + char32_t nextCp = Lexer()->Lookahead(); + if (!(nextCp != lexer::LEX_CHAR_EQUALS && nextCp != lexer::LEX_CHAR_COLON)) { + return flags; + } + + ir::ModifierFlags currentFlag; + + lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); + if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { + ThrowSyntaxError("Keyword must not contain escaped characters"); + } + + switch (Lexer()->GetToken().KeywordType()) { + case lexer::TokenType::KEYW_STATIC: { + currentFlag = ir::ModifierFlags::STATIC; + break; + } + case lexer::TokenType::KEYW_READONLY: { + currentFlag = ir::ModifierFlags::READONLY; + break; + } + default: { + UNREACHABLE(); + } + } + + if ((flags & currentFlag) != 0) { + ThrowSyntaxError("Duplicated modifier is not allowed"); + } + + Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); + flags |= currentFlag; + } + + return flags; +} + +bool ETSParser::IsClassMethodModifier(lexer::TokenType type) noexcept +{ + switch (type) { + case lexer::TokenType::KEYW_STATIC: + case lexer::TokenType::KEYW_FINAL: + case lexer::TokenType::KEYW_NATIVE: + case lexer::TokenType::KEYW_ASYNC: + case lexer::TokenType::KEYW_OVERRIDE: + case lexer::TokenType::KEYW_ABSTRACT: { + return true; + } + default: { + break; + } + } + + return false; +} + +// Helper method for ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seenStatic) +ir::ModifierFlags ETSParser::ParseClassMethodModifierFlag() +{ + ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; + + switch (Lexer()->GetToken().KeywordType()) { + case lexer::TokenType::KEYW_STATIC: { + currentFlag = ir::ModifierFlags::STATIC; + break; + } + case lexer::TokenType::KEYW_FINAL: { + currentFlag = ir::ModifierFlags::FINAL; + break; + } + case lexer::TokenType::KEYW_NATIVE: { + currentFlag = ir::ModifierFlags::NATIVE; + break; + } + case lexer::TokenType::KEYW_ASYNC: { + currentFlag = ir::ModifierFlags::ASYNC; + break; + } + case lexer::TokenType::KEYW_OVERRIDE: { + currentFlag = ir::ModifierFlags::OVERRIDE; + break; + } + case lexer::TokenType::KEYW_ABSTRACT: { + currentFlag = ir::ModifierFlags::ABSTRACT; + break; + } + case lexer::TokenType::KEYW_DECLARE: { + currentFlag = ir::ModifierFlags::DECLARE; + break; + } + default: { + UNREACHABLE(); + } + } + + return currentFlag; +} + +ir::ModifierFlags ETSParser::ParseClassMethodModifiers(bool seenStatic) +{ + ir::ModifierFlags flags = seenStatic ? ir::ModifierFlags::STATIC : ir::ModifierFlags::NONE; + + while (IsClassMethodModifier(Lexer()->GetToken().KeywordType())) { + char32_t nextCp = Lexer()->Lookahead(); + if (!(nextCp != lexer::LEX_CHAR_LEFT_PAREN)) { + return flags; + } + + ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; + + lexer::TokenFlags tokenFlags = Lexer()->GetToken().Flags(); + if ((tokenFlags & lexer::TokenFlags::HAS_ESCAPE) != 0) { + ThrowSyntaxError("Keyword must not contain escaped characters"); + } + + currentFlag = ParseClassMethodModifierFlag(); + if ((flags & currentFlag) != 0) { + ThrowSyntaxError("Duplicated modifier is not allowed"); + } + + Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); + flags |= currentFlag; + if ((flags & ir::ModifierFlags::ASYNC) != 0) { + if ((flags & ir::ModifierFlags::NATIVE) != 0) { + ThrowSyntaxError("Native method cannot be async"); + } else if ((flags & ir::ModifierFlags::ABSTRACT) != 0) { + ThrowSyntaxError("Abstract method cannot be async"); + } + } + } + + return flags; +} + +// NOLINTNEXTLINE(google-default-arguments) +void ETSParser::ParseClassFieldDefinition(ir::Identifier *fieldName, ir::ModifierFlags modifiers, + ArenaVector *declarations) +{ + lexer::SourcePosition endLoc = fieldName->End(); + ir::TypeNode *typeAnnotation = nullptr; + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + bool optionalField = false; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { + Lexer()->NextToken(); // eat '?' + optionalField = true; + } + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + typeAnnotation = ParseTypeAnnotation(&options); + endLoc = typeAnnotation->End(); + } + + ir::Expression *initializer = nullptr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + Lexer()->NextToken(); // eat '=' + initializer = ParseExpression(); + } else if (typeAnnotation == nullptr) { + ThrowSyntaxError("Field type annotation expected"); + } + + bool isDeclare = (modifiers & ir::ModifierFlags::DECLARE) != 0; + + if (isDeclare && initializer != nullptr) { + ThrowSyntaxError("Initializers are not allowed in ambient contexts."); + } + + auto *field = AllocNode(fieldName, initializer, typeAnnotation, modifiers, Allocator(), false); + field->SetRange({fieldName->Start(), initializer != nullptr ? initializer->End() : endLoc}); + if (optionalField) { + field->AddModifier(ir::ModifierFlags::OPTIONAL); + } + + declarations->push_back(field); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { + Lexer()->NextToken(); + ir::Identifier *nextName = ExpectIdentifier(false, true); + ParseClassFieldDefinition(nextName, modifiers, declarations); + } +} + +ir::MethodDefinition *ETSParser::ParseClassMethodDefinition(ir::Identifier *methodName, ir::ModifierFlags modifiers, + ir::Identifier *className) +{ + auto newStatus = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ALLOW_SUPER; + auto methodKind = ir::MethodDefinitionKind::METHOD; + + if (className != nullptr) { + methodKind = ir::MethodDefinitionKind::EXTENSION_METHOD; + newStatus |= ParserStatus::IN_EXTENSION_FUNCTION; + } + + if ((modifiers & ir::ModifierFlags::CONSTRUCTOR) != 0) { + newStatus = ParserStatus::CONSTRUCTOR_FUNCTION | ParserStatus::ALLOW_SUPER | ParserStatus::ALLOW_SUPER_CALL; + methodKind = ir::MethodDefinitionKind::CONSTRUCTOR; + } + + if ((modifiers & ir::ModifierFlags::ASYNC) != 0) { + newStatus |= ParserStatus::ASYNC_FUNCTION; + } + + if ((modifiers & ir::ModifierFlags::STATIC) == 0) { + newStatus |= ParserStatus::ALLOW_THIS_TYPE; + } + + ir::ScriptFunction *func = ParseFunction(newStatus, className); + func->SetIdent(methodName); + auto *funcExpr = AllocNode(func); + funcExpr->SetRange(func->Range()); + func->AddModifier(modifiers); + + if (className != nullptr) { + func->AddFlag(ir::ScriptFunctionFlags::INSTANCE_EXTENSION_METHOD); + } + auto *method = AllocNode(methodKind, methodName->Clone(Allocator(), nullptr)->AsExpression(), + funcExpr, modifiers, Allocator(), false); + method->SetRange(funcExpr->Range()); + func->Id()->SetReference(); + return method; +} + +ir::MethodDefinition *ETSParser::ParseClassMethod(ClassElementDescriptor *desc, + const ArenaVector &properties, + ir::Expression *propName, lexer::SourcePosition *propEnd) +{ + if (desc->methodKind != ir::MethodDefinitionKind::SET && + (desc->newStatus & ParserStatus::CONSTRUCTOR_FUNCTION) == 0) { + desc->newStatus |= ParserStatus::NEED_RETURN_TYPE; + } + + ir::ScriptFunction *func = ParseFunction(desc->newStatus); + if (propName->IsIdentifier()) { + func->SetIdent(propName->AsIdentifier()->Clone(Allocator(), nullptr)); + func->Id()->SetReference(); + } + + auto *funcExpr = AllocNode(func); + funcExpr->SetRange(func->Range()); + + if (desc->methodKind == ir::MethodDefinitionKind::SET) { + ValidateClassSetter(desc, properties, propName, func); + } else if (desc->methodKind == ir::MethodDefinitionKind::GET) { + ValidateClassGetter(desc, properties, propName, func); + } + + *propEnd = func->End(); + func->AddFlag(ir::ScriptFunctionFlags::METHOD); + auto *method = + AllocNode(desc->methodKind, propName->Clone(Allocator(), nullptr)->AsExpression(), + funcExpr, desc->modifiers, Allocator(), desc->isComputed); + method->SetRange(funcExpr->Range()); + + return method; +} + +ir::AstNode *ETSParser::ParseClassElement(const ArenaVector &properties, + ir::ClassDefinitionModifiers modifiers, + [[maybe_unused]] ir::ModifierFlags flags) +{ + auto startLoc = Lexer()->GetToken().Start(); + auto savedPos = Lexer()->Save(); // NOLINT(clang-analyzer-deadcode.DeadStores) + + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC && + Lexer()->Lookahead() == lexer::LEX_CHAR_LEFT_BRACE) { + return ParseClassStaticBlock(); + } + + auto [memberModifiers, isStepToken] = ParseClassMemberAccessModifiers(); + + if (InAmbientContext()) { + memberModifiers |= ir::ModifierFlags::DECLARE; + } + + bool seenStatic = false; + char32_t nextCp = Lexer()->Lookahead(); + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC && nextCp != lexer::LEX_CHAR_EQUALS && + nextCp != lexer::LEX_CHAR_COLON && nextCp != lexer::LEX_CHAR_LEFT_PAREN && + nextCp != lexer::LEX_CHAR_LESS_THAN) { + Lexer()->NextToken(); + memberModifiers |= ir::ModifierFlags::STATIC; + seenStatic = true; + } + + if (IsClassFieldModifier(Lexer()->GetToken().KeywordType())) { + memberModifiers |= ParseClassFieldModifiers(seenStatic); + } else if (IsClassMethodModifier(Lexer()->GetToken().Type())) { + memberModifiers |= ParseClassMethodModifiers(seenStatic); + } + + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::KEYW_INTERFACE: + case lexer::TokenType::KEYW_CLASS: + case lexer::TokenType::KEYW_ENUM: { + return ParseInnerTypeDeclaration(memberModifiers, savedPos, isStepToken, seenStatic); + } + case lexer::TokenType::KEYW_CONSTRUCTOR: { + return ParseInnerConstructorDeclaration(memberModifiers, startLoc); + } + case lexer::TokenType::KEYW_PUBLIC: + case lexer::TokenType::KEYW_PRIVATE: + case lexer::TokenType::KEYW_PROTECTED: { + ThrowSyntaxError("Access modifier must precede field and method modifiers."); + break; + } + default: { + break; + } + } + + return ParseInnerRest(properties, modifiers, memberModifiers, startLoc); +} + +ir::MethodDefinition *ETSParser::ParseClassGetterSetterMethod(const ArenaVector &properties, + const ir::ClassDefinitionModifiers modifiers, + const ir::ModifierFlags memberModifiers) +{ + ClassElementDescriptor desc(Allocator()); + desc.methodKind = Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ? ir::MethodDefinitionKind::GET + : ir::MethodDefinitionKind::SET; + Lexer()->NextToken(); // eat get/set + auto *methodName = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + if (desc.methodKind == ir::MethodDefinitionKind::GET) { + methodName->SetAccessor(); + } else { + methodName->SetMutator(); + } + + Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); + + desc.newStatus = ParserStatus::ALLOW_SUPER; + desc.hasSuperClass = (modifiers & ir::ClassDefinitionModifiers::HAS_SUPER) != 0U; + desc.propStart = Lexer()->GetToken().Start(); + desc.modifiers = memberModifiers; + + lexer::SourcePosition propEnd = methodName->End(); + ir::MethodDefinition *method = ParseClassMethod(&desc, properties, methodName, &propEnd); + method->Function()->AddModifier(desc.modifiers); + method->SetRange({desc.propStart, propEnd}); + if (desc.methodKind == ir::MethodDefinitionKind::GET) { + method->Function()->AddFlag(ir::ScriptFunctionFlags::GETTER); + } else { + method->Function()->AddFlag(ir::ScriptFunctionFlags::SETTER); + } + + return method; +} + +ir::MethodDefinition *ETSParser::ParseInterfaceGetterSetterMethod(const ir::ModifierFlags modifiers) +{ + auto methodKind = Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET ? ir::MethodDefinitionKind::GET + : ir::MethodDefinitionKind::SET; + Lexer()->NextToken(); // eat get/set + ExpectToken(lexer::TokenType::LITERAL_IDENT, false); + ir::MethodDefinition *method = ParseInterfaceMethod(modifiers, methodKind); + method->AddModifier(ir::ModifierFlags::PUBLIC); + method->SetRange({Lexer()->GetToken().Start(), method->Id()->End()}); + if (methodKind == ir::MethodDefinitionKind::GET) { + method->Id()->SetAccessor(); + method->Function()->AddFlag(ir::ScriptFunctionFlags::GETTER); + } else { + method->Id()->SetMutator(); + method->Function()->AddFlag(ir::ScriptFunctionFlags::SETTER); + } + method->AddModifier(ir::ModifierFlags::PUBLIC); + + method->Function()->SetIdent(method->Id()->Clone(Allocator(), nullptr)); + method->Function()->AddModifier(method->Modifiers()); + + return method; +} + +ir::TSInterfaceDeclaration *ETSParser::ParseInterfaceBody(ir::Identifier *name, bool isStatic) +{ + GetContext().Status() |= ParserStatus::ALLOW_THIS_TYPE; + + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { + auto options = + TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE; + typeParamDecl = ParseTypeParameterDeclaration(&options); + } + + ArenaVector extends(Allocator()->Adapter()); + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) { + extends = ParseInterfaceExtendsClause(); + } + + lexer::SourcePosition bodyStart = Lexer()->GetToken().Start(); + auto members = ParseTypeLiteralOrInterface(); + + for (auto &member : members) { + if (member->Type() == ir::AstNodeType::CLASS_DECLARATION || + member->Type() == ir::AstNodeType::STRUCT_DECLARATION || + member->Type() == ir::AstNodeType::TS_ENUM_DECLARATION || + member->Type() == ir::AstNodeType::TS_INTERFACE_DECLARATION) { + ThrowSyntaxError( + "Local type declaration (class, struct, interface and enum) support is not yet implemented."); + } + } + + auto *body = AllocNode(std::move(members)); + body->SetRange({bodyStart, Lexer()->GetToken().End()}); + + const auto isExternal = IsExternal(); + auto *interfaceDecl = AllocNode( + Allocator(), std::move(extends), + ir::TSInterfaceDeclaration::ConstructorData {name, typeParamDecl, body, isStatic, isExternal, + GetContext().GetLanguage()}); + + Lexer()->NextToken(); + GetContext().Status() &= ~ParserStatus::ALLOW_THIS_TYPE; + + return interfaceDecl; +} + +ir::Statement *ETSParser::ParseInterfaceDeclaration(bool isStatic) +{ + lexer::SourcePosition interfaceStart = Lexer()->GetToken().Start(); + Lexer()->NextToken(); // eat interface keyword + + auto *id = ExpectIdentifier(false, true); + + auto *declNode = ParseInterfaceBody(id, isStatic); + + declNode->SetRange({interfaceStart, Lexer()->GetToken().End()}); + return declNode; +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::ClassDefinition *ETSParser::ParseClassDefinition(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags) +{ + Lexer()->NextToken(); + + ir::Identifier *identNode = ParseClassIdent(modifiers); + + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LESS_THAN) { + auto options = + TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_DECLARATION_SITE_VARIANCE; + typeParamDecl = ParseTypeParameterDeclaration(&options); + } + + // Parse SuperClass + auto [superClass, superTypeParams] = ParseSuperClass(); + + if (superClass != nullptr) { + modifiers |= ir::ClassDefinitionModifiers::HAS_SUPER; + GetContext().Status() |= ParserStatus::ALLOW_SUPER; + } + + if (InAmbientContext()) { + flags |= ir::ModifierFlags::DECLARE; + } + + // Parse implements clause + ArenaVector implements(Allocator()->Adapter()); + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_IMPLEMENTS) { + Lexer()->NextToken(); + implements = ParseClassImplementClause(); + } + + ArenaVector properties(Allocator()->Adapter()); + ir::MethodDefinition *ctor = nullptr; + lexer::SourceRange bodyRange; + + if ((flags & ir::ModifierFlags::DECLARE) != 0U && + Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { + // without ClassBody + bodyRange = lexer::SourceRange {Lexer()->GetToken().Start(), Lexer()->GetToken().Start()}; + } else { + ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE, false); + + // Parse ClassBody + std::tie(ctor, properties, bodyRange) = ParseClassBody(modifiers, flags); + } + + auto *classDefinition = AllocNode( + util::StringView(), identNode, typeParamDecl, superTypeParams, std::move(implements), ctor, superClass, + std::move(properties), modifiers, flags, GetContext().GetLanguage()); + + classDefinition->SetRange(bodyRange); + + GetContext().Status() &= ~ParserStatus::ALLOW_SUPER; + + return classDefinition; +} + +static bool IsInterfaceMethodModifier(lexer::TokenType type) +{ + // NOTE (psiket) Rewrite this + return type == lexer::TokenType::KEYW_STATIC || type == lexer::TokenType::KEYW_PRIVATE || + type == lexer::TokenType::KEYW_PROTECTED || type == lexer::TokenType::KEYW_PUBLIC; +} + +ir::ModifierFlags ETSParser::ParseInterfaceMethodModifiers() +{ + ir::ModifierFlags flags = ir::ModifierFlags::NONE; + + while (IsInterfaceMethodModifier(Lexer()->GetToken().Type())) { + ir::ModifierFlags currentFlag = ir::ModifierFlags::NONE; + + if ((GetContext().Status() & ParserStatus::FUNCTION) != 0) { + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PUBLIC || + Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PROTECTED || + Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PRIVATE) { + ThrowSyntaxError("Local interface declaration members can not have access modifies", + Lexer()->GetToken().Start()); + } + } else if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PUBLIC || + Lexer()->GetToken().Type() == lexer::TokenType::KEYW_PROTECTED) { + break; + } + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::KEYW_STATIC: { + currentFlag = ir::ModifierFlags::STATIC; + break; + } + case lexer::TokenType::KEYW_PRIVATE: { + currentFlag = ir::ModifierFlags::PRIVATE; + break; + } + default: { + UNREACHABLE(); + } + } + + char32_t nextCp = Lexer()->Lookahead(); + if (nextCp == lexer::LEX_CHAR_COLON || nextCp == lexer::LEX_CHAR_LEFT_PAREN || + nextCp == lexer::LEX_CHAR_EQUALS) { + break; + } + + if ((flags & currentFlag) != 0) { + ThrowSyntaxError("Duplicated modifier is not allowed"); + } + + Lexer()->NextToken(); + flags |= currentFlag; + } + + return flags; +} + +ir::ClassProperty *ETSParser::ParseInterfaceField() +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT); + auto *name = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + name->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + bool optionalField = false; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { + Lexer()->NextToken(); // eat '?' + optionalField = true; + } + + ir::TypeNode *typeAnnotation = nullptr; + if (!Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) { + ThrowSyntaxError("Interface fields must have type annotation."); + } + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + typeAnnotation = ParseTypeAnnotation(&options); + + name->SetTsTypeAnnotation(typeAnnotation); + typeAnnotation->SetParent(name); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EQUAL) { + ThrowSyntaxError("Initializers are not allowed on interface properties."); + } + + ir::ModifierFlags fieldModifiers = ir::ModifierFlags::PUBLIC; + + if (InAmbientContext()) { + fieldModifiers |= ir::ModifierFlags::DECLARE; + } + + auto *field = AllocNode(name, nullptr, typeAnnotation->Clone(Allocator(), nullptr), + fieldModifiers, Allocator(), false); + if (optionalField) { + field->AddModifier(ir::ModifierFlags::OPTIONAL); + } + field->SetEnd(Lexer()->GetToken().End()); + + return field; +} + +ir::MethodDefinition *ETSParser::ParseInterfaceMethod(ir::ModifierFlags flags, ir::MethodDefinitionKind methodKind) +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT); + auto *name = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + name->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + + FunctionContext functionContext(this, ParserStatus::FUNCTION); + + lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); + + auto [signature, throwMarker] = ParseFunctionSignature(ParserStatus::NEED_RETURN_TYPE); + + ir::BlockStatement *body = nullptr; + + bool isDeclare = InAmbientContext(); + if (isDeclare) { + flags |= ir::ModifierFlags::DECLARE; + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { + if (methodKind == ir::MethodDefinitionKind::SET || methodKind == ir::MethodDefinitionKind::GET) { + ThrowSyntaxError("Getter and setter methods must be abstracts in the interface body", startLoc); + } + body = ParseBlockStatement(); + } else if ((flags & (ir::ModifierFlags::PRIVATE | ir::ModifierFlags::STATIC)) != 0 && !isDeclare) { + ThrowSyntaxError("Private or static interface methods must have body", startLoc); + } + + functionContext.AddFlag(throwMarker); + + if ((GetContext().Status() & ParserStatus::FUNCTION_HAS_RETURN_STATEMENT) != 0) { + functionContext.AddFlag(ir::ScriptFunctionFlags::HAS_RETURN); + GetContext().Status() ^= ParserStatus::FUNCTION_HAS_RETURN_STATEMENT; + } + + auto *func = AllocNode( + Allocator(), ir::ScriptFunction::ScriptFunctionData {body, std::move(signature), functionContext.Flags(), flags, + true, GetContext().GetLanguage()}); + + if ((flags & ir::ModifierFlags::STATIC) == 0 && body == nullptr) { + func->AddModifier(ir::ModifierFlags::ABSTRACT); + } + func->SetRange({startLoc, body != nullptr ? body->End() + : func->ReturnTypeAnnotation() != nullptr ? func->ReturnTypeAnnotation()->End() + : func->Params().empty() ? Lexer()->GetToken().End() + : (*func->Params().end())->End()}); + + auto *funcExpr = AllocNode(func); + funcExpr->SetRange(func->Range()); + func->AddFlag(ir::ScriptFunctionFlags::METHOD); + + func->SetIdent(name); + auto *method = AllocNode(ir::MethodDefinitionKind::METHOD, + name->Clone(Allocator(), nullptr)->AsExpression(), funcExpr, flags, + Allocator(), false); + method->SetRange(funcExpr->Range()); + + func->Id()->SetReference(); + + ConsumeSemicolon(method); + + return method; +} + +ir::AstNode *ETSParser::ParseTypeLiteralOrInterfaceMember() +{ + auto startLoc = Lexer()->GetToken().Start(); + ir::ModifierFlags methodFlags = ParseInterfaceMethodModifiers(); + if (methodFlags != ir::ModifierFlags::NONE) { + if ((methodFlags & ir::ModifierFlags::PRIVATE) == 0) { + methodFlags |= ir::ModifierFlags::PUBLIC; + } + + auto *method = ParseInterfaceMethod(methodFlags, ir::MethodDefinitionKind::METHOD); + method->SetStart(startLoc); + return method; + } + + if (Lexer()->Lookahead() != lexer::LEX_CHAR_LEFT_PAREN && Lexer()->Lookahead() != lexer::LEX_CHAR_LESS_THAN && + (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_GET || + Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_SET)) { + return ParseInterfaceGetterSetterMethod(methodFlags); + } + + if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_READONLY)) { + auto *field = ParseInterfaceField(); + field->SetStart(startLoc); + field->AddModifier(ir::ModifierFlags::READONLY); + return field; + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { + char32_t nextCp = Lexer()->Lookahead(); + if (nextCp == lexer::LEX_CHAR_LEFT_PAREN || nextCp == lexer::LEX_CHAR_LESS_THAN) { + auto *method = ParseInterfaceMethod(ir::ModifierFlags::PUBLIC, ir::MethodDefinitionKind::METHOD); + method->SetStart(startLoc); + return method; + } + + auto *field = ParseInterfaceField(); + field->SetStart(startLoc); + return field; + } + + return ParseTypeDeclaration(true); +} + +bool ETSParser::CheckClassElement(ir::AstNode *property, [[maybe_unused]] ir::MethodDefinition *&ctor, + [[maybe_unused]] ArenaVector &properties) +{ + if (property->IsClassStaticBlock()) { + if (std::any_of(properties.cbegin(), properties.cend(), + [](const auto *prop) { return prop->IsClassStaticBlock(); })) { + ThrowSyntaxError("Only one static block is allowed", property->Start()); + } + + auto *id = AllocNode(compiler::Signatures::CCTOR, Allocator()); + property->AsClassStaticBlock()->Function()->SetIdent(id); + } + + if (property->IsTSInterfaceBody()) { + return CheckClassElementInterfaceBody(property, properties); + } + + if (!property->IsMethodDefinition()) { + return false; + } + + auto const *const method = property->AsMethodDefinition(); + auto const *const function = method->Function(); + + // Check the special '$_get' and '$_set' methods using for object's index access + if (method->Kind() == ir::MethodDefinitionKind::METHOD) { + CheckPredefinedMethods(function, property->Start()); + } + + return false; // resolve overloads later on scopes stage +} + +void ETSParser::CheckPredefinedMethods(ir::ScriptFunction const *function, const lexer::SourcePosition &position) const +{ + auto const name = function->Id()->Name(); + + auto const checkAsynchronous = [this, function, &name, &position]() -> void { + if (function->IsAsyncFunc()) { + ThrowSyntaxError(std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()} + + std::string {"' cannot be asynchronous."}, + position); + } + }; + + if (name.Is(compiler::Signatures::GET_INDEX_METHOD)) { + checkAsynchronous(); + + bool isValid = function->Params().size() == 1U; + if (isValid) { + auto const *const param = function->Params()[0]->AsETSParameterExpression(); + isValid = !param->IsDefault() && !param->IsRestParameter(); + } + + if (!isValid) { + ThrowSyntaxError(std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()} + + std::string {"' should have exactly one required parameter."}, + position); + } + } else if (name.Is(compiler::Signatures::SET_INDEX_METHOD)) { + checkAsynchronous(); + + bool isValid = function->Params().size() == 2U; + if (isValid) { + auto const *const param1 = function->Params()[0]->AsETSParameterExpression(); + auto const *const param2 = function->Params()[1]->AsETSParameterExpression(); + isValid = !param1->IsDefault() && !param1->IsRestParameter() && !param2->IsDefault() && + !param2->IsRestParameter(); + } + + if (!isValid) { + ThrowSyntaxError(std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()} + + std::string {"' should have exactly two required parameters."}, + position); + } + } else if (name.Is(compiler::Signatures::ITERATOR_METHOD)) { + checkAsynchronous(); + + if (!function->Params().empty()) { + ThrowSyntaxError(std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()} + + std::string {"' should not have parameters."}, + position); + } + } +} + +void ETSParser::CreateImplicitConstructor([[maybe_unused]] ir::MethodDefinition *&ctor, + ArenaVector &properties, + [[maybe_unused]] ir::ClassDefinitionModifiers modifiers, + const lexer::SourcePosition &startLoc) +{ + if (std::any_of(properties.cbegin(), properties.cend(), [](ir::AstNode *prop) { + return prop->IsMethodDefinition() && prop->AsMethodDefinition()->IsConstructor(); + })) { + return; + } + + if ((modifiers & ir::ClassDefinitionModifiers::ANONYMOUS) != 0) { + return; + } + + auto *methodDef = BuildImplicitConstructor(ir::ClassDefinitionModifiers::SET_CTOR_ID, startLoc); + properties.push_back(methodDef); +} + +std::pair ETSParser::ParseMemberModifiers() +{ + auto memberModifiers = ir::ModifierFlags::STATIC | ir::ModifierFlags::PUBLIC; + + if (Lexer()->TryEatTokenType(lexer::TokenType::KEYW_EXPORT)) { + const auto savedPos = Lexer()->Save(); + if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_DEFAULT)) { + memberModifiers |= ir::ModifierFlags::DEFAULT_EXPORT; + } else if (Lexer()->TryEatTokenKeyword(lexer::TokenType::KEYW_TYPE)) { + if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { + Lexer()->Rewind(savedPos); + } + memberModifiers |= ir::ModifierFlags::EXPORT_TYPE; + } else { + memberModifiers |= ir::ModifierFlags::EXPORT; + } + } + + lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); + + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE) { + CheckDeclare(); + memberModifiers |= ir::ModifierFlags::DECLARE; + } + const auto tokenType = Lexer()->GetToken().KeywordType(); + if (tokenType == lexer::TokenType::KEYW_ASYNC || tokenType == lexer::TokenType::KEYW_NATIVE) { + bool isAsync = tokenType == lexer::TokenType::KEYW_ASYNC; + + if (isAsync) { + memberModifiers |= ir::ModifierFlags::ASYNC; + } else { + memberModifiers |= ir::ModifierFlags::NATIVE; + } + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) { + ThrowSyntaxError( + {isAsync ? "'async'" : "'native'", " flags must be used for functions only at top-level."}); + } + } + return std::make_pair(memberModifiers, startLoc); +} + +} // namespace ark::es2panda::parser diff --git a/ets2panda/parser/ETSparserEnums.cpp b/ets2panda/parser/ETSparserEnums.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0b6ee3dfd74c7818abe8553a10c655703d3966e --- /dev/null +++ b/ets2panda/parser/ETSparserEnums.cpp @@ -0,0 +1,322 @@ +/** + * Copyright (c) 2021-2024 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. + */ + +#include "ETSparser.h" +#include "ETSNolintParser.h" +#include + +#include "macros.h" +#include "parser/parserFlags.h" +#include "parser/parserStatusContext.h" +#include "util/helpers.h" +#include "util/language.h" +#include "utils/arena_containers.h" +#include "varbinder/varbinder.h" +#include "varbinder/ETSBinder.h" +#include "lexer/lexer.h" +#include "lexer/ETSLexer.h" +#include "checker/types/ets/etsEnumType.h" +#include "ir/astNode.h" +#include "ir/base/classDefinition.h" +#include "ir/base/decorator.h" +#include "ir/base/catchClause.h" +#include "ir/base/classProperty.h" +#include "ir/base/scriptFunction.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/classStaticBlock.h" +#include "ir/base/spreadElement.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/functionExpression.h" +#include "ir/statements/functionDeclaration.h" +#include "ir/statements/expressionStatement.h" +#include "ir/statements/classDeclaration.h" +#include "ir/statements/variableDeclarator.h" +#include "ir/statements/variableDeclaration.h" +#include "ir/expressions/dummyNode.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/thisExpression.h" +#include "ir/expressions/typeofExpression.h" +#include "ir/expressions/memberExpression.h" +#include "ir/expressions/updateExpression.h" +#include "ir/expressions/arrowFunctionExpression.h" +#include "ir/expressions/unaryExpression.h" +#include "ir/expressions/yieldExpression.h" +#include "ir/expressions/awaitExpression.h" +#include "ir/expressions/literals/nullLiteral.h" +#include "ir/expressions/literals/numberLiteral.h" +#include "ir/expressions/literals/stringLiteral.h" +#include "ir/expressions/literals/undefinedLiteral.h" +#include "ir/module/importDeclaration.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/importSpecifier.h" +#include "ir/module/exportSpecifier.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/statements/assertStatement.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/ifStatement.h" +#include "ir/statements/labelledStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/whileStatement.h" +#include "ir/statements/forOfStatement.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/breakStatement.h" +#include "ir/statements/debuggerStatement.h" +#include "ir/ets/etsLaunchExpression.h" +#include "ir/ets/etsClassLiteral.h" +#include "ir/ets/etsPrimitiveType.h" +#include "ir/ets/etsPackageDeclaration.h" +#include "ir/ets/etsReExportDeclaration.h" +#include "ir/ets/etsWildcardType.h" +#include "ir/ets/etsNewArrayInstanceExpression.h" +#include "ir/ets/etsTuple.h" +#include "ir/ets/etsFunctionType.h" +#include "ir/ets/etsNewClassInstanceExpression.h" +#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" +#include "ir/ets/etsScript.h" +#include "ir/ets/etsTypeReference.h" +#include "ir/ets/etsTypeReferencePart.h" +#include "ir/ets/etsNullishTypes.h" +#include "ir/ets/etsUnionType.h" +#include "ir/ets/etsImportSource.h" +#include "ir/ets/etsImportDeclaration.h" +#include "ir/ets/etsStructDeclaration.h" +#include "ir/ets/etsParameterExpression.h" +#include "ir/module/importNamespaceSpecifier.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsEnumDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsInterfaceBody.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsEnumMember.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsNonNullExpression.h" +#include "ir/ts/tsThisType.h" +#include "generated/signatures.h" + +namespace ark::es2panda::parser { +class FunctionContext; + +using namespace std::literals::string_literals; + +// NOLINTNEXTLINE(google-default-arguments) +ir::Statement *ETSParser::ParseEnumDeclaration(bool isConst, bool isStatic) +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ENUM); + + if ((GetContext().Status() & parser::ParserStatus::FUNCTION) != 0U) { + ThrowSyntaxError("Local enum declaration support is not yet implemented."); + } + + lexer::SourcePosition enumStart = Lexer()->GetToken().Start(); + Lexer()->NextToken(); // eat enum keyword + + auto *key = ExpectIdentifier(false, true); + + auto *declNode = ParseEnumMembers(key, enumStart, isConst, isStatic); + + return declNode; +} + +// NOLINTBEGIN(cert-err58-cpp) +static std::string const DUPLICATE_ENUM_VALUE = "Duplicate enum initialization value "s; +static std::string const INVALID_ENUM_TYPE = "Invalid enum initialization type"s; +static std::string const INVALID_ENUM_VALUE = "Invalid enum initialization value"s; +static std::string const MISSING_COMMA_IN_ENUM = "Missing comma between enum constants"s; +static std::string const TRAILING_COMMA_IN_ENUM = "Trailing comma is not allowed in enum constant list"s; +// NOLINTEND(cert-err58-cpp) + +// Helper for ETSParser::ParseEnumMembers() +bool ETSParser::IsStringEnum() +{ + // Get the underlying type of enum (number or string). It is defined from the first element ONLY! + Lexer()->NextToken(); + auto tokenType = Lexer()->GetToken().Type(); + while (tokenType != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE && tokenType != lexer::TokenType::PUNCTUATOR_COMMA) { + if (tokenType == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + Lexer()->NextToken(); + if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_STRING) { + return true; + } + } + Lexer()->NextToken(); + tokenType = Lexer()->GetToken().Type(); + } + return false; +} + +ir::TSEnumDeclaration *ETSParser::ParseEnumMembers(ir::Identifier *const key, const lexer::SourcePosition &enumStart, + const bool isConst, const bool isStatic) +{ + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { + ThrowSyntaxError("'{' expected"); + } + + Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat '{' + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { + ThrowSyntaxError("An enum must have at least one enum constant"); + } + + // Get the underlying type of enum (number or string). It is defined from the first element ONLY! + auto const pos = Lexer()->Save(); + const bool stringTypeEnum = IsStringEnum(); + Lexer()->Rewind(pos); + + ArenaVector members(Allocator()->Adapter()); + + if (stringTypeEnum) { + ParseStringEnum(members); + } else { + ParseNumberEnum(members); + } + + auto *const enumDeclaration = AllocNode( + Allocator(), key, std::move(members), + ir::TSEnumDeclaration::ConstructorFlags {isConst, isStatic, InAmbientContext()}); + enumDeclaration->SetRange({enumStart, Lexer()->GetToken().End()}); + + Lexer()->NextToken(); // eat '}' + + return enumDeclaration; +} + +void ETSParser::ParseNumberEnum(ArenaVector &members) +{ + checker::ETSEnumType::ValueType currentValue {}; + + // Lambda to parse enum member (maybe with initializer) + auto const parseMember = [this, &members, ¤tValue]() { + auto *const ident = ExpectIdentifier(false, true); + + ir::NumberLiteral *ordinal; + lexer::SourcePosition endLoc; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + // Case when user explicitly set the value for enumeration constant + + bool minusSign = false; + + Lexer()->NextToken(); + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PLUS) { + Lexer()->NextToken(); + } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS) { + minusSign = true; + Lexer()->NextToken(); + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NUMBER) { + ThrowSyntaxError(INVALID_ENUM_TYPE); + } + + ordinal = ParseNumberLiteral()->AsNumberLiteral(); + if (minusSign) { + ordinal->Number().Negate(); + } + if (!ordinal->Number().CanGetValue()) { + ThrowSyntaxError(INVALID_ENUM_VALUE); + } + + currentValue = ordinal->Number().GetValue(); + + endLoc = ordinal->End(); + } else { + // Default enumeration constant value. Equal to 0 for the first item and = previous_value + 1 for all + // the others. + + ordinal = AllocNode(lexer::Number(currentValue)); + + endLoc = ident->End(); + } + + auto *const member = AllocNode(ident, ordinal); + member->SetRange({ident->Start(), endLoc}); + members.emplace_back(member); + + ++currentValue; + }; + + parseMember(); + + while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) { + ThrowSyntaxError(MISSING_COMMA_IN_ENUM); + } + + Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ',' + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { + break; + } + + parseMember(); + } +} + +void ETSParser::ParseStringEnum(ArenaVector &members) +{ + // Lambda to parse enum member (maybe with initializer) + auto const parseMember = [this, &members]() { + auto *const ident = ExpectIdentifier(); + + ir::StringLiteral *itemValue; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + // Case when user explicitly set the value for enumeration constant + + Lexer()->NextToken(); + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { + ThrowSyntaxError(INVALID_ENUM_TYPE); + } + + itemValue = ParseStringLiteral(); + } else { + // Default item value is not allowed for string type enumerations! + ThrowSyntaxError("All items of string-type enumeration should be explicitly initialized."); + } + + auto *const member = AllocNode(ident, itemValue); + member->SetRange({ident->Start(), itemValue->End()}); + members.emplace_back(member); + }; + + parseMember(); + + while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) { + ThrowSyntaxError(MISSING_COMMA_IN_ENUM); + } + + Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ',' + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { + ThrowSyntaxError(TRAILING_COMMA_IN_ENUM); + } + + parseMember(); + } +} + +} // namespace ark::es2panda::parser diff --git a/ets2panda/parser/ETSparserExpressions.cpp b/ets2panda/parser/ETSparserExpressions.cpp new file mode 100644 index 0000000000000000000000000000000000000000..858bd3814efa4d31055494571aef80e5368cbea2 --- /dev/null +++ b/ets2panda/parser/ETSparserExpressions.cpp @@ -0,0 +1,813 @@ +/** + * Copyright (c) 2021-2024 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. + */ + +#include "ETSparser.h" +#include "ETSNolintParser.h" +#include + +#include "macros.h" +#include "parser/parserFlags.h" +#include "parser/parserStatusContext.h" +#include "util/helpers.h" +#include "util/language.h" +#include "utils/arena_containers.h" +#include "varbinder/varbinder.h" +#include "varbinder/ETSBinder.h" +#include "lexer/lexer.h" +#include "lexer/ETSLexer.h" +#include "checker/types/ets/etsEnumType.h" +#include "ir/astNode.h" +#include "ir/base/classDefinition.h" +#include "ir/base/decorator.h" +#include "ir/base/catchClause.h" +#include "ir/base/classProperty.h" +#include "ir/base/scriptFunction.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/classStaticBlock.h" +#include "ir/base/spreadElement.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/functionExpression.h" +#include "ir/statements/functionDeclaration.h" +#include "ir/statements/expressionStatement.h" +#include "ir/statements/classDeclaration.h" +#include "ir/statements/variableDeclarator.h" +#include "ir/statements/variableDeclaration.h" +#include "ir/expressions/dummyNode.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/thisExpression.h" +#include "ir/expressions/typeofExpression.h" +#include "ir/expressions/memberExpression.h" +#include "ir/expressions/updateExpression.h" +#include "ir/expressions/arrowFunctionExpression.h" +#include "ir/expressions/unaryExpression.h" +#include "ir/expressions/yieldExpression.h" +#include "ir/expressions/awaitExpression.h" +#include "ir/expressions/literals/nullLiteral.h" +#include "ir/expressions/literals/numberLiteral.h" +#include "ir/expressions/literals/stringLiteral.h" +#include "ir/expressions/literals/undefinedLiteral.h" +#include "ir/module/importDeclaration.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/importSpecifier.h" +#include "ir/module/exportSpecifier.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/statements/assertStatement.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/ifStatement.h" +#include "ir/statements/labelledStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/whileStatement.h" +#include "ir/statements/forOfStatement.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/breakStatement.h" +#include "ir/statements/debuggerStatement.h" +#include "ir/ets/etsLaunchExpression.h" +#include "ir/ets/etsClassLiteral.h" +#include "ir/ets/etsPrimitiveType.h" +#include "ir/ets/etsPackageDeclaration.h" +#include "ir/ets/etsReExportDeclaration.h" +#include "ir/ets/etsWildcardType.h" +#include "ir/ets/etsNewArrayInstanceExpression.h" +#include "ir/ets/etsTuple.h" +#include "ir/ets/etsFunctionType.h" +#include "ir/ets/etsNewClassInstanceExpression.h" +#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" +#include "ir/ets/etsScript.h" +#include "ir/ets/etsTypeReference.h" +#include "ir/ets/etsTypeReferencePart.h" +#include "ir/ets/etsNullishTypes.h" +#include "ir/ets/etsUnionType.h" +#include "ir/ets/etsImportSource.h" +#include "ir/ets/etsImportDeclaration.h" +#include "ir/ets/etsStructDeclaration.h" +#include "ir/ets/etsParameterExpression.h" +#include "ir/module/importNamespaceSpecifier.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsEnumDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsInterfaceBody.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsEnumMember.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsNonNullExpression.h" +#include "ir/ts/tsThisType.h" +#include "generated/signatures.h" + +namespace ark::es2panda::parser { +class FunctionContext; + +using namespace std::literals::string_literals; + +ir::Expression *ETSParser::ParseLaunchExpression(ExpressionParseFlags flags) +{ + lexer::SourcePosition start = Lexer()->GetToken().Start(); + Lexer()->NextToken(); // eat launch + + ir::Expression *expr = ParseLeftHandSideExpression(flags); + if (!expr->IsCallExpression()) { + ThrowSyntaxError("Only call expressions are allowed after 'launch'", expr->Start()); + } + auto call = expr->AsCallExpression(); + auto *launchExpression = AllocNode(call); + launchExpression->SetRange({start, call->End()}); + + return launchExpression; +} + +// NOLINTBEGIN(modernize-avoid-c-arrays) +static constexpr char const NO_DEFAULT_FOR_REST[] = "Rest parameter cannot have the default value."; +// NOLINTEND(modernize-avoid-c-arrays) + +ir::Expression *ETSParser::ParseFunctionParameterExpression(ir::AnnotatedExpression *const paramIdent, + ir::ETSUndefinedType *defaultUndef) +{ + ir::ETSParameterExpression *paramExpression; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + if (paramIdent->IsRestElement()) { + ThrowSyntaxError(NO_DEFAULT_FOR_REST); + } + + auto const lexerPos = Lexer()->Save().Iterator(); + Lexer()->NextToken(); // eat '=' + + if (defaultUndef != nullptr) { + ThrowSyntaxError("Not enable default value with default undefined"); + } + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS || + Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { + ThrowSyntaxError("You didn't set the value."); + } + + paramExpression = AllocNode(paramIdent->AsIdentifier(), ParseExpression()); + + std::string value = Lexer()->SourceView(lexerPos.Index(), Lexer()->Save().Iterator().Index()).Mutf8(); + while (value.back() == ' ') { + value.pop_back(); + } + if (value.back() == ')' || value.back() == ',') { + value.pop_back(); + } + paramExpression->SetLexerSaved(util::UString(value, Allocator()).View()); + + paramExpression->SetRange({paramIdent->Start(), paramExpression->Initializer()->End()}); + } else if (paramIdent->IsIdentifier()) { + auto *typeAnnotation = paramIdent->AsIdentifier()->TypeAnnotation(); + + const auto typeAnnotationValue = [this, typeAnnotation, + defaultUndef]() -> std::pair { + if (typeAnnotation == nullptr) { + return std::make_pair(nullptr, ""); + } + return std::make_pair(defaultUndef != nullptr ? AllocNode() : nullptr, "undefined"); + }(); + + paramExpression = + AllocNode(paramIdent->AsIdentifier(), std::get<0>(typeAnnotationValue)); + if (defaultUndef != nullptr) { + paramExpression->SetLexerSaved(util::UString(std::get<1>(typeAnnotationValue), Allocator()).View()); + } + paramExpression->SetRange({paramIdent->Start(), paramIdent->End()}); + } else { + paramExpression = AllocNode(paramIdent->AsRestElement(), nullptr); + paramExpression->SetRange({paramIdent->Start(), paramIdent->End()}); + } + return paramExpression; +} + +ir::Expression *ETSParser::ResolveArgumentUnaryExpr(ExpressionParseFlags flags) +{ + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_TILDE: + case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: + case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: + case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: + case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: + case lexer::TokenType::KEYW_TYPEOF: { + return ParseUnaryOrPrefixUpdateExpression(); + } + default: { + return ParseLeftHandSideExpression(flags); + } + } +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ETSParser::ParseUnaryOrPrefixUpdateExpression(ExpressionParseFlags flags) +{ + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::PUNCTUATOR_PLUS_PLUS: + case lexer::TokenType::PUNCTUATOR_MINUS_MINUS: + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::PUNCTUATOR_TILDE: + case lexer::TokenType::PUNCTUATOR_DOLLAR_DOLLAR: + case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: + case lexer::TokenType::KEYW_TYPEOF: { + break; + } + case lexer::TokenType::KEYW_LAUNCH: { + return ParseLaunchExpression(flags); + } + default: { + return ParseLeftHandSideExpression(flags); + } + } + + lexer::TokenType operatorType = Lexer()->GetToken().Type(); + auto start = Lexer()->GetToken().Start(); + Lexer()->NextToken(); + + ir::Expression *argument = ResolveArgumentUnaryExpr(flags); + + if (lexer::Token::IsUpdateToken(operatorType)) { + if (!argument->IsIdentifier() && !argument->IsMemberExpression()) { + ThrowSyntaxError("Invalid left-hand side in prefix operation"); + } + } + + lexer::SourcePosition end = argument->End(); + + ir::Expression *returnExpr = nullptr; + if (lexer::Token::IsUpdateToken(operatorType)) { + returnExpr = AllocNode(argument, operatorType, true); + } else if (operatorType == lexer::TokenType::KEYW_TYPEOF) { + returnExpr = AllocNode(argument); + } else { + returnExpr = AllocNode(argument, operatorType); + } + + returnExpr->SetRange({start, end}); + + return returnExpr; +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ETSParser::ParseDefaultPrimaryExpression(ExpressionParseFlags flags) +{ + auto startLoc = Lexer()->GetToken().Start(); + auto savedPos = Lexer()->Save(); + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | + TypeAnnotationParsingOptions::DISALLOW_UNION; + ir::TypeNode *potentialType = ParseTypeAnnotation(&options); + + if (potentialType != nullptr) { + if (potentialType->IsTSArrayType()) { + return potentialType; + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { + Lexer()->NextToken(); // eat '.' + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword()) { + Lexer()->NextToken(); // eat 'class' and 'struct' + auto *classLiteral = AllocNode(potentialType); + classLiteral->SetRange({startLoc, Lexer()->GetToken().End()}); + return classLiteral; + } + } + + Lexer()->Rewind(savedPos); + + Lexer()->NextToken(); + bool pretendArrow = Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW; + Lexer()->Rewind(savedPos); + + if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT && !pretendArrow) { + return ParsePrimaryExpressionIdent(flags); + } + + ThrowSyntaxError({"Unexpected token '", lexer::TokenToString(Lexer()->GetToken().Type()), "'."}); + return nullptr; +} + +ir::Expression *ETSParser::ParsePrimaryExpressionWithLiterals(ExpressionParseFlags flags) +{ + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::LITERAL_TRUE: + case lexer::TokenType::LITERAL_FALSE: { + return ParseBooleanLiteral(); + } + case lexer::TokenType::LITERAL_NULL: { + return ParseNullLiteral(); + } + case lexer::TokenType::KEYW_UNDEFINED: { + return ParseUndefinedLiteral(); + } + case lexer::TokenType::LITERAL_NUMBER: { + return ParseCoercedNumberLiteral(); + } + case lexer::TokenType::LITERAL_STRING: { + return ParseStringLiteral(); + } + case lexer::TokenType::LITERAL_CHAR: { + return ParseCharLiteral(); + } + default: { + return ParseDefaultPrimaryExpression(flags); + } + } +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ETSParser::ParsePrimaryExpression(ExpressionParseFlags flags) +{ + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { + return ParseCoverParenthesizedExpressionAndArrowParameterList(flags); + } + case lexer::TokenType::KEYW_THIS: { + return ParseThisExpression(); + } + case lexer::TokenType::KEYW_SUPER: { + return ParseSuperExpression(); + } + case lexer::TokenType::KEYW_NEW: { + return ParseNewExpression(); + } + case lexer::TokenType::KEYW_ASYNC: { + return ParseAsyncExpression(); + } + case lexer::TokenType::KEYW_AWAIT: { + return ParseAwaitExpression(); + } + case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { + return ParseArrayExpression(CarryPatternFlags(flags)); + } + case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { + return ParseObjectExpression(CarryPatternFlags(flags)); + } + case lexer::TokenType::PUNCTUATOR_BACK_TICK: { + return ParseTemplateLiteral(); + } + case lexer::TokenType::KEYW_TYPE: { + ThrowSyntaxError("Type alias is allowed only as top-level declaration"); + } + case lexer::TokenType::PUNCTUATOR_FORMAT: { + return ParseExpressionFormatPlaceholder(); + } + case lexer::TokenType::KEYW_TYPEOF: { + return ParseUnaryOrPrefixUpdateExpression(); + } + default: { + return ParsePrimaryExpressionWithLiterals(flags); + } + } +} + +bool IsPunctuartorSpecialCharacter(lexer::TokenType tokenType) +{ + switch (tokenType) { + case lexer::TokenType::PUNCTUATOR_COLON: + case lexer::TokenType::PUNCTUATOR_COMMA: + case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: + case lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET: + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: + return true; + default: + return false; + } +} + +bool ETSParser::IsArrowFunctionExpressionStart() +{ + const auto savedPos = Lexer()->Save(); + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); + Lexer()->NextToken(); + auto tokenType = Lexer()->GetToken().Type(); + + size_t openBrackets = 1; + bool expectIdentifier = true; + while (tokenType != lexer::TokenType::EOS && openBrackets > 0) { + switch (tokenType) { + case lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS: + --openBrackets; + break; + case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: + ++openBrackets; + break; + case lexer::TokenType::PUNCTUATOR_COMMA: + expectIdentifier = true; + break; + case lexer::TokenType::PUNCTUATOR_SEMI_COLON: + Lexer()->Rewind(savedPos); + return false; + default: + if (!expectIdentifier) { + break; + } + if (tokenType != lexer::TokenType::LITERAL_IDENT && + tokenType != lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { + Lexer()->Rewind(savedPos); + return false; + } + expectIdentifier = false; + } + Lexer()->NextToken(); + tokenType = Lexer()->GetToken().Type(); + } + + while (tokenType != lexer::TokenType::EOS && tokenType != lexer::TokenType::PUNCTUATOR_ARROW) { + if (lexer::Token::IsPunctuatorToken(tokenType) && !IsPunctuartorSpecialCharacter(tokenType)) { + break; + } + Lexer()->NextToken(); + tokenType = Lexer()->GetToken().Type(); + } + Lexer()->Rewind(savedPos); + return tokenType == lexer::TokenType::PUNCTUATOR_ARROW; +} + +ir::ArrowFunctionExpression *ETSParser::ParseArrowFunctionExpression() +{ + auto newStatus = ParserStatus::ARROW_FUNCTION; + auto *func = ParseFunction(newStatus); + auto *arrowFuncNode = AllocNode(func); + arrowFuncNode->SetRange(func->Range()); + return arrowFuncNode; +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ETSParser::ParseCoverParenthesizedExpressionAndArrowParameterList(ExpressionParseFlags flags) +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); + if (IsArrowFunctionExpressionStart()) { + return ParseArrowFunctionExpression(); + } + + lexer::SourcePosition start = Lexer()->GetToken().Start(); + Lexer()->NextToken(); + + ExpressionParseFlags newFlags = ExpressionParseFlags::ACCEPT_COMMA; + if ((flags & ExpressionParseFlags::INSTANCEOF) != 0) { + newFlags |= ExpressionParseFlags::INSTANCEOF; + }; + + ir::Expression *expr = ParseExpression(newFlags); + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + ThrowSyntaxError("Unexpected token, expected ')'"); + } + + expr->SetGrouped(); + expr->SetRange({start, Lexer()->GetToken().End()}); + Lexer()->NextToken(); + + return expr; +} + +ir::Expression *ETSParser::ParsePostPrimaryExpression(ir::Expression *primaryExpr, lexer::SourcePosition startLoc, + bool ignoreCallExpression, + [[maybe_unused]] bool *isChainExpression) +{ + ir::Expression *returnExpression = primaryExpr; + + while (true) { + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::PUNCTUATOR_QUESTION_DOT: { + if (*isChainExpression) { + break; // terminate current chain + } + *isChainExpression = true; + Lexer()->NextToken(); // eat ?. + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { + returnExpression = ParseElementAccess(returnExpression, true); + continue; + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { + returnExpression = ParseCallExpression(returnExpression, true, false); + continue; + } + + returnExpression = ParsePropertyAccess(returnExpression, true); + continue; + } + case lexer::TokenType::PUNCTUATOR_PERIOD: { + Lexer()->NextToken(); // eat period + + returnExpression = ParsePropertyAccess(returnExpression); + continue; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { + returnExpression = ParseElementAccess(returnExpression); + continue; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + if (ParsePotentialGenericFunctionCall(returnExpression, &returnExpression, startLoc, + ignoreCallExpression)) { + break; + } + + continue; + } + case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { + if (ignoreCallExpression) { + break; + } + returnExpression = ParseCallExpression(returnExpression, false, false); + continue; + } + case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { + const bool shouldBreak = ParsePotentialNonNullExpression(&returnExpression, startLoc); + if (shouldBreak) { + break; + } + + continue; + } + case lexer::TokenType::PUNCTUATOR_FORMAT: { + ThrowUnexpectedToken(lexer::TokenType::PUNCTUATOR_FORMAT); + } + default: { + break; + } + } + + break; + } + + return returnExpression; +} + +ir::Expression *ETSParser::ParsePotentialAsExpression(ir::Expression *primaryExpr) +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_AS); + Lexer()->NextToken(); + + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *type = ParseTypeAnnotation(&options); + + auto *asExpression = AllocNode(primaryExpr, type, false); + asExpression->SetRange(primaryExpr->Range()); + return asExpression; +} + +// Extracted from 'ParseNewExpression()' to reduce function's size +ir::ClassDefinition *ETSParser::CreateClassDefinitionForNewExpression(ArenaVector &arguments, + ir::TypeNode *typeReference, + ir::TypeNode *baseTypeReference) +{ + lexer::SourcePosition endLoc = typeReference->End(); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { + if (baseTypeReference != nullptr) { + ThrowSyntaxError("Can not use 'new' on primitive types.", baseTypeReference->Start()); + } + + Lexer()->NextToken(); + + while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + ir::Expression *argument = ParseExpression(); + arguments.push_back(argument); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { + Lexer()->NextToken(); + continue; + } + } + + endLoc = Lexer()->GetToken().End(); + Lexer()->NextToken(); + } + + ir::ClassDefinition *classDefinition {}; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { + ArenaVector implements(Allocator()->Adapter()); + auto modifiers = ir::ClassDefinitionModifiers::ANONYMOUS | ir::ClassDefinitionModifiers::HAS_SUPER; + auto [ctor, properties, bodyRange] = ParseClassBody(modifiers); + + auto newIdent = AllocNode("#0", Allocator()); + classDefinition = AllocNode( + "#0", newIdent, nullptr, nullptr, std::move(implements), ctor, // remove name + typeReference->Clone(Allocator(), nullptr), std::move(properties), modifiers, ir::ModifierFlags::NONE, + Language(Language::Id::ETS)); + + classDefinition->SetRange(bodyRange); + } + + return classDefinition; +} + +ir::Expression *ETSParser::ParseNewExpression() +{ + lexer::SourcePosition start = Lexer()->GetToken().Start(); + + Lexer()->NextToken(); // eat new + + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *baseTypeReference = ParseBaseTypeReference(&options); + ir::TypeNode *typeReference = baseTypeReference; + if (typeReference == nullptr) { + options |= TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | TypeAnnotationParsingOptions::ALLOW_WILDCARD; + typeReference = ParseTypeReference(&options); + } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { + ThrowSyntaxError("Invalid { after base types."); + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { + Lexer()->NextToken(); + ir::Expression *dimension = ParseExpression(); + + auto endLoc = Lexer()->GetToken().End(); + ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET); + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { + auto *arrInstance = AllocNode(typeReference, dimension); + arrInstance->SetRange({start, endLoc}); + return arrInstance; + } + + ArenaVector dimensions(Allocator()->Adapter()); + dimensions.push_back(dimension); + + do { + Lexer()->NextToken(); + dimensions.push_back(ParseExpression()); + + endLoc = Lexer()->GetToken().End(); + ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET); + } while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET); + + auto *multiArray = AllocNode(typeReference, std::move(dimensions)); + multiArray->SetRange({start, endLoc}); + return multiArray; + } + + ArenaVector arguments(Allocator()->Adapter()); + ir::ClassDefinition *classDefinition = + CreateClassDefinitionForNewExpression(arguments, typeReference, baseTypeReference); + + auto *newExprNode = + AllocNode(typeReference, std::move(arguments), classDefinition); + newExprNode->SetRange({start, Lexer()->GetToken().End()}); + + return newExprNode; +} + +ir::Expression *ETSParser::ParseAsyncExpression() +{ + Lexer()->NextToken(); // eat 'async' + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS || + !IsArrowFunctionExpressionStart()) { + ThrowSyntaxError("Unexpected token. expected '('"); + } + + auto newStatus = ParserStatus::NEED_RETURN_TYPE | ParserStatus::ARROW_FUNCTION | ParserStatus::ASYNC_FUNCTION; + auto *func = ParseFunction(newStatus); + auto *arrowFuncNode = AllocNode(func); + arrowFuncNode->SetRange(func->Range()); + return arrowFuncNode; +} + +ir::Expression *ETSParser::ParseAwaitExpression() +{ + lexer::SourcePosition start = Lexer()->GetToken().Start(); + Lexer()->NextToken(); + ir::Expression *argument = ParseExpression(); + auto *awaitExpression = AllocNode(argument); + awaitExpression->SetRange({start, Lexer()->GetToken().End()}); + return awaitExpression; +} + +ir::ThisExpression *ETSParser::ParseThisExpression() +{ + auto *thisExpression = TypedParser::ParseThisExpression(); + + if (Lexer()->GetToken().NewLine()) { + return thisExpression; + } + + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::PUNCTUATOR_PERIOD: + case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: + case lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS: + case lexer::TokenType::PUNCTUATOR_SEMI_COLON: + case lexer::TokenType::PUNCTUATOR_COLON: + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: + case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: + case lexer::TokenType::PUNCTUATOR_COMMA: + case lexer::TokenType::PUNCTUATOR_QUESTION_MARK: + case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: + case lexer::TokenType::KEYW_INSTANCEOF: + case lexer::TokenType::KEYW_AS: { + break; + } + default: { + ThrowUnexpectedToken(Lexer()->GetToken().Type()); + break; + } + } + + return thisExpression; +} + +ir::Expression *ETSParser::ParsePotentialExpressionSequence(ir::Expression *expr, ExpressionParseFlags flags) +{ + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA && + (flags & ExpressionParseFlags::ACCEPT_COMMA) != 0 && (flags & ExpressionParseFlags::IN_FOR) != 0U) { + return ParseSequenceExpression(expr, (flags & ExpressionParseFlags::ACCEPT_REST) != 0); + } + + return expr; +} + +bool ETSParser::ParsePotentialNonNullExpression(ir::Expression **expression, const lexer::SourcePosition startLoc) +{ + if (expression == nullptr || Lexer()->GetToken().NewLine()) { + return true; + } + + const auto nonNullExpr = AllocNode(*expression); + nonNullExpr->SetRange({startLoc, Lexer()->GetToken().End()}); + + *expression = nonNullExpr; + + Lexer()->NextToken(); + + return false; +} + +void ETSParser::ValidateInstanceOfExpression(ir::Expression *expr) +{ + ValidateGroupedExpression(expr); + lexer::TokenType tokenType = Lexer()->GetToken().Type(); + if (tokenType == lexer::TokenType::PUNCTUATOR_LESS_THAN) { + auto options = TypeAnnotationParsingOptions::NO_OPTS; + + // Run checks to validate type declarations + // Should provide helpful messages with incorrect declarations like the following: + // `instanceof A;` + ThrowSyntaxError("Invalid right-hand side in 'instanceof' expression"); + } +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *ETSParser::ParseExpression(ExpressionParseFlags flags) +{ + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_YIELD && + (flags & ExpressionParseFlags::DISALLOW_YIELD) == 0U) { + ir::YieldExpression *yieldExpr = ParseYieldExpression(); + + return ParsePotentialExpressionSequence(yieldExpr, flags); + } + + ir::Expression *unaryExpressionNode = ParseUnaryOrPrefixUpdateExpression(flags); + if ((flags & ExpressionParseFlags::INSTANCEOF) != 0) { + ValidateInstanceOfExpression(unaryExpressionNode); + } + + ir::Expression *assignmentExpression = ParseAssignmentExpression(unaryExpressionNode, flags); + + if (Lexer()->GetToken().NewLine()) { + return assignmentExpression; + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA && + (flags & ExpressionParseFlags::ACCEPT_COMMA) != 0U && (flags & ExpressionParseFlags::IN_FOR) != 0U) { + return ParseSequenceExpression(assignmentExpression, (flags & ExpressionParseFlags::ACCEPT_REST) != 0U); + } + + return assignmentExpression; +} + +} // namespace ark::es2panda::parser diff --git a/ets2panda/parser/ETSparserStatements.cpp b/ets2panda/parser/ETSparserStatements.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81961f9bc38acc9b3ed7f057cc9f05d5d63e6aa5 --- /dev/null +++ b/ets2panda/parser/ETSparserStatements.cpp @@ -0,0 +1,340 @@ +/** + * Copyright (c) 2021-2024 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. + */ + +#include "ETSparser.h" +#include "ETSNolintParser.h" +#include + +#include "macros.h" +#include "parser/parserFlags.h" +#include "parser/parserStatusContext.h" +#include "util/helpers.h" +#include "util/language.h" +#include "utils/arena_containers.h" +#include "varbinder/varbinder.h" +#include "varbinder/ETSBinder.h" +#include "lexer/lexer.h" +#include "lexer/ETSLexer.h" +#include "checker/types/ets/etsEnumType.h" +#include "ir/astNode.h" +#include "ir/base/classDefinition.h" +#include "ir/base/decorator.h" +#include "ir/base/catchClause.h" +#include "ir/base/classProperty.h" +#include "ir/base/scriptFunction.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/classStaticBlock.h" +#include "ir/base/spreadElement.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/functionExpression.h" +#include "ir/statements/functionDeclaration.h" +#include "ir/statements/expressionStatement.h" +#include "ir/statements/classDeclaration.h" +#include "ir/statements/variableDeclarator.h" +#include "ir/statements/variableDeclaration.h" +#include "ir/expressions/dummyNode.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/thisExpression.h" +#include "ir/expressions/typeofExpression.h" +#include "ir/expressions/memberExpression.h" +#include "ir/expressions/updateExpression.h" +#include "ir/expressions/arrowFunctionExpression.h" +#include "ir/expressions/unaryExpression.h" +#include "ir/expressions/yieldExpression.h" +#include "ir/expressions/awaitExpression.h" +#include "ir/expressions/literals/nullLiteral.h" +#include "ir/expressions/literals/numberLiteral.h" +#include "ir/expressions/literals/stringLiteral.h" +#include "ir/expressions/literals/undefinedLiteral.h" +#include "ir/module/importDeclaration.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/importSpecifier.h" +#include "ir/module/exportSpecifier.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/statements/assertStatement.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/ifStatement.h" +#include "ir/statements/labelledStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/whileStatement.h" +#include "ir/statements/forOfStatement.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/breakStatement.h" +#include "ir/statements/debuggerStatement.h" +#include "ir/ets/etsLaunchExpression.h" +#include "ir/ets/etsClassLiteral.h" +#include "ir/ets/etsPrimitiveType.h" +#include "ir/ets/etsPackageDeclaration.h" +#include "ir/ets/etsReExportDeclaration.h" +#include "ir/ets/etsWildcardType.h" +#include "ir/ets/etsNewArrayInstanceExpression.h" +#include "ir/ets/etsTuple.h" +#include "ir/ets/etsFunctionType.h" +#include "ir/ets/etsNewClassInstanceExpression.h" +#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h" +#include "ir/ets/etsScript.h" +#include "ir/ets/etsTypeReference.h" +#include "ir/ets/etsTypeReferencePart.h" +#include "ir/ets/etsNullishTypes.h" +#include "ir/ets/etsUnionType.h" +#include "ir/ets/etsImportSource.h" +#include "ir/ets/etsImportDeclaration.h" +#include "ir/ets/etsStructDeclaration.h" +#include "ir/ets/etsParameterExpression.h" +#include "ir/module/importNamespaceSpecifier.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsEnumDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsInterfaceBody.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsEnumMember.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsNonNullExpression.h" +#include "ir/ts/tsThisType.h" +#include "generated/signatures.h" + +namespace ark::es2panda::parser { +class FunctionContext; + +using namespace std::literals::string_literals; + +ArenaVector ETSParser::ParseTopLevelStatements() +{ + ArenaVector statements(Allocator()->Adapter()); + while (Lexer()->GetToken().Type() != lexer::TokenType::EOS) { + if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_SEMI_COLON)) { + continue; + } + auto stmt = ParseTopLevelStatement(); + GetContext().Status() &= ~ParserStatus::IN_AMBIENT_CONTEXT; + if (stmt != nullptr) { + statements.emplace_back(stmt); + } + } + + return statements; +} + +ir::Statement *ETSParser::ParseTopLevelDeclStatement(StatementParsingFlags flags) +{ + auto [memberModifiers, startLoc] = ParseMemberModifiers(); + if ((memberModifiers & (ir::ModifierFlags::EXPORTED)) != 0U && + (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY || + Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE)) { + return ParseExport(startLoc, memberModifiers); + } + + ir::Statement *result = nullptr; + auto token = Lexer()->GetToken(); + switch (token.Type()) { + case lexer::TokenType::KEYW_FUNCTION: { + result = ParseFunctionDeclaration(false, memberModifiers); + result->SetStart(startLoc); + break; + } + case lexer::TokenType::KEYW_CONST: { + memberModifiers |= ir::ModifierFlags::CONST; + [[fallthrough]]; + } + case lexer::TokenType::KEYW_LET: { + result = ParseStatement(flags); + break; + } + case lexer::TokenType::KEYW_NAMESPACE: + case lexer::TokenType::KEYW_STATIC: + case lexer::TokenType::KEYW_ABSTRACT: + case lexer::TokenType::KEYW_FINAL: + case lexer::TokenType::KEYW_ENUM: + case lexer::TokenType::KEYW_INTERFACE: + case lexer::TokenType::KEYW_CLASS: { + result = ParseTypeDeclaration(false); + break; + } + case lexer::TokenType::LITERAL_IDENT: { + result = ParseIdentKeyword(); + break; + } + default: { + } + } + if (result != nullptr) { + if ((memberModifiers & ir::ModifierFlags::EXPORT_TYPE) != 0U && + !(result->IsClassDeclaration() || result->IsTSInterfaceDeclaration() || + result->IsTSTypeAliasDeclaration())) { + ThrowSyntaxError("Can only type export class or interface!"); + } + result->AddModifier(memberModifiers); + } + return result; +} + +ir::Statement *ETSParser::ParseTopLevelStatement() +{ + const auto flags = StatementParsingFlags::ALLOW_LEXICAL; + static const std::unordered_set ALLOWED_TOP_LEVEL_STMTS = { + lexer::TokenType::PUNCTUATOR_LEFT_BRACE, + lexer::TokenType::PUNCTUATOR_SEMI_COLON, + lexer::TokenType::KEYW_ASSERT, + lexer::TokenType::KEYW_IF, + lexer::TokenType::KEYW_DO, + lexer::TokenType::KEYW_FOR, + lexer::TokenType::KEYW_TRY, + lexer::TokenType::KEYW_WHILE, + lexer::TokenType::KEYW_BREAK, + lexer::TokenType::KEYW_CONTINUE, + lexer::TokenType::KEYW_THROW, + lexer::TokenType::KEYW_SWITCH, + lexer::TokenType::KEYW_DEBUGGER, + lexer::TokenType::LITERAL_IDENT, + }; + + auto result = ParseTopLevelDeclStatement(flags); + if (result == nullptr) { + auto const tokenType = Lexer()->GetToken().Type(); + if (ALLOWED_TOP_LEVEL_STMTS.count(tokenType) != 0U) { + result = ParseStatement(flags); + } else { + ThrowUnexpectedToken(tokenType); + } + } + return result; +} + +ArenaVector ETSParser::ParseTopLevelDeclaration() +{ + auto topStatements = ParseTopLevelStatements(); + Lexer()->NextToken(); + return topStatements; +} + +void ETSParser::ValidateLabeledStatement(lexer::TokenType type) +{ + if (type != lexer::TokenType::KEYW_DO && type != lexer::TokenType::KEYW_WHILE && + type != lexer::TokenType::KEYW_FOR && type != lexer::TokenType::KEYW_SWITCH) { + ThrowSyntaxError("Label must be followed by a loop statement", Lexer()->GetToken().Start()); + } +} + +void ETSParser::ValidateForInStatement() +{ + ThrowUnexpectedToken(lexer::TokenType::KEYW_IN); +} + +ir::DebuggerStatement *ETSParser::ParseDebuggerStatement() +{ + ThrowUnexpectedToken(lexer::TokenType::KEYW_DEBUGGER); +} + +ir::Statement *ETSParser::ParseFunctionStatement([[maybe_unused]] const StatementParsingFlags flags) +{ + ASSERT((flags & StatementParsingFlags::GLOBAL) == 0); + ThrowSyntaxError("Nested functions are not allowed"); +} + +ir::Statement *ETSParser::ParseAssertStatement() +{ + lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); + Lexer()->NextToken(); + + ir::Expression *test = ParseExpression(); + lexer::SourcePosition endLoc = test->End(); + ir::Expression *second = nullptr; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + second = ParseExpression(); + endLoc = second->End(); + } + + auto *asStatement = AllocNode(test, second); + asStatement->SetRange({startLoc, endLoc}); + ConsumeSemicolon(asStatement); + + return asStatement; +} + +ir::Statement *ETSParser::ParseTryStatement() +{ + lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); + Lexer()->NextToken(); // eat the 'try' keyword + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { + ThrowSyntaxError("Unexpected token, expected '{'"); + } + + ir::BlockStatement *body = ParseBlockStatement(); + + ArenaVector catchClauses(Allocator()->Adapter()); + + while (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_CATCH) { + ir::CatchClause *clause {}; + + clause = ParseCatchClause(); + + catchClauses.push_back(clause); + } + + ir::BlockStatement *finalizer = nullptr; + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_FINALLY) { + Lexer()->NextToken(); // eat 'finally' keyword + + finalizer = ParseBlockStatement(); + } + + if (catchClauses.empty() && finalizer == nullptr) { + ThrowSyntaxError("A try statement should contain either finally clause or at least one catch clause.", + startLoc); + } + + lexer::SourcePosition endLoc = finalizer != nullptr ? finalizer->End() : catchClauses.back()->End(); + + ArenaVector> finalizerInsertions(Allocator()->Adapter()); + + auto *tryStatement = AllocNode(body, std::move(catchClauses), finalizer, finalizerInsertions); + tryStatement->SetRange({startLoc, endLoc}); + ConsumeSemicolon(tryStatement); + + return tryStatement; +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::ClassDeclaration *ETSParser::ParseClassStatement([[maybe_unused]] StatementParsingFlags flags, + ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags modFlags) +{ + return ParseClassDeclaration(modifiers | ir::ClassDefinitionModifiers::ID_REQUIRED | + ir::ClassDefinitionModifiers::CLASS_DECL | ir::ClassDefinitionModifiers::LOCAL, + modFlags); +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::ETSStructDeclaration *ETSParser::ParseStructStatement([[maybe_unused]] StatementParsingFlags flags, + [[maybe_unused]] ir::ClassDefinitionModifiers modifiers, + [[maybe_unused]] ir::ModifierFlags modFlags) +{ + ThrowSyntaxError("Illegal start of expression", Lexer()->GetToken().Start()); +} + +} // namespace ark::es2panda::parser diff --git a/ets2panda/parser/ETSparserTypes.cpp b/ets2panda/parser/ETSparserTypes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..363251ae1c42bdd6dcc9970a39fe29f265a4396d --- /dev/null +++ b/ets2panda/parser/ETSparserTypes.cpp @@ -0,0 +1,437 @@ +/** + * Copyright (c) 2021-2024 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. + */ + +#include "ETSparser.h" +#include "ETSNolintParser.h" +#include + +#include "macros.h" +#include "parser/parserFlags.h" +#include "parser/parserStatusContext.h" +#include "util/helpers.h" +#include "util/language.h" +#include "utils/arena_containers.h" +#include "varbinder/varbinder.h" +#include "varbinder/ETSBinder.h" +#include "lexer/lexer.h" +#include "lexer/ETSLexer.h" +#include "ir/astNode.h" +#include "ir/base/decorator.h" +#include "ir/base/catchClause.h" +#include "ir/base/scriptFunction.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/spreadElement.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/functionExpression.h" +#include "ir/expressions/dummyNode.h" +#include "ir/module/importDeclaration.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/importSpecifier.h" +#include "ir/module/exportSpecifier.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/ets/etsPrimitiveType.h" +#include "ir/ets/etsPackageDeclaration.h" +#include "ir/ets/etsReExportDeclaration.h" +#include "ir/ets/etsWildcardType.h" +#include "ir/ets/etsTuple.h" +#include "ir/ets/etsFunctionType.h" +#include "ir/ets/etsScript.h" +#include "ir/ets/etsTypeReference.h" +#include "ir/ets/etsTypeReferencePart.h" +#include "ir/ets/etsNullishTypes.h" +#include "ir/ets/etsUnionType.h" +#include "ir/ets/etsImportSource.h" +#include "ir/ets/etsImportDeclaration.h" +#include "ir/ets/etsStructDeclaration.h" +#include "ir/module/importNamespaceSpecifier.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsInterfaceBody.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsTypeParameter.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsTypeParameterDeclaration.h" +#include "ir/ts/tsThisType.h" +#include "generated/signatures.h" + +namespace ark::es2panda::parser { +class FunctionContext; + +using namespace std::literals::string_literals; + +ir::TypeNode *ETSParser::ParseFunctionReturnType([[maybe_unused]] ParserStatus status) +{ + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + if ((status & ParserStatus::CONSTRUCTOR_FUNCTION) != 0U) { + ThrowSyntaxError("Type annotation isn't allowed for constructor."); + } + Lexer()->NextToken(); // eat ':' + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | + TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE | + TypeAnnotationParsingOptions::RETURN_TYPE; + return ParseTypeAnnotation(&options); + } + + return nullptr; +} + +ir::TypeNode *ETSParser::ParsePrimitiveType(TypeAnnotationParsingOptions *options, ir::PrimitiveType type) +{ + if (((*options) & TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE) != 0) { + ThrowSyntaxError("Primitive type is not allowed here."); + } + + auto *typeAnnotation = AllocNode(type); + typeAnnotation->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + return typeAnnotation; +} + +ir::TypeNode *ETSParser::ParseUnionType(ir::TypeNode *const firstType) +{ + ArenaVector types(Allocator()->Adapter()); + types.push_back(firstType->AsTypeNode()); + + while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { + Lexer()->NextToken(); // eat '|' + + auto options = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_UNION; + types.push_back(ParseTypeAnnotation(&options)); + } + + auto const endLoc = types.back()->End(); + auto *const unionType = AllocNode(std::move(types)); + unionType->SetRange({firstType->Start(), endLoc}); + return unionType; +} + +ir::TypeNode *ETSParser::GetTypeAnnotationOfPrimitiveType([[maybe_unused]] lexer::TokenType tokenType, + TypeAnnotationParsingOptions *options) +{ + ir::TypeNode *typeAnnotation = nullptr; + switch (tokenType) { + case lexer::TokenType::KEYW_BOOLEAN: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BOOLEAN); + break; + case lexer::TokenType::KEYW_DOUBLE: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::DOUBLE); + break; + case lexer::TokenType::KEYW_BYTE: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::BYTE); + break; + case lexer::TokenType::KEYW_FLOAT: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::FLOAT); + break; + case lexer::TokenType::KEYW_SHORT: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::SHORT); + break; + case lexer::TokenType::KEYW_INT: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::INT); + break; + case lexer::TokenType::KEYW_CHAR: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::CHAR); + break; + case lexer::TokenType::KEYW_LONG: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::LONG); + break; + case lexer::TokenType::KEYW_VOID: + typeAnnotation = ParsePrimitiveType(options, ir::PrimitiveType::VOID); + break; + default: + typeAnnotation = ParseTypeReference(options); + break; + } + return typeAnnotation; +} + +ir::TypeNode *ETSParser::ParseWildcardType(TypeAnnotationParsingOptions *options) +{ + const auto varianceStartLoc = Lexer()->GetToken().Start(); + const auto varianceEndLoc = Lexer()->GetToken().End(); + const auto varianceModifier = ParseTypeVarianceModifier(options); + + auto *typeReference = [this, &varianceModifier, options]() -> ir::ETSTypeReference * { + if (varianceModifier == ir::ModifierFlags::OUT && + (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_GREATER_THAN || + Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA)) { + // unbounded 'out' + return nullptr; + } + return ParseTypeReference(options)->AsETSTypeReference(); + }(); + + auto *wildcardType = AllocNode(typeReference, varianceModifier); + wildcardType->SetRange({varianceStartLoc, typeReference == nullptr ? varianceEndLoc : typeReference->End()}); + + return wildcardType; +} + +ir::TypeNode *ETSParser::ParseFunctionType() +{ + auto startLoc = Lexer()->GetToken().Start(); + auto params = ParseFunctionParams(); + + auto *const returnTypeAnnotation = [this]() -> ir::TypeNode * { + ExpectToken(lexer::TokenType::PUNCTUATOR_ARROW); + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + return ParseTypeAnnotation(&options); + }(); + + ir::ScriptFunctionFlags throwMarker = ParseFunctionThrowMarker(false); + + auto *funcType = AllocNode( + ir::FunctionSignature(nullptr, std::move(params), returnTypeAnnotation), throwMarker); + const auto endLoc = returnTypeAnnotation->End(); + funcType->SetRange({startLoc, endLoc}); + + return funcType; +} + +ir::TypeNode *ETSParser::ParseETSTupleType(TypeAnnotationParsingOptions *const options) +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET); + + const auto startLoc = Lexer()->GetToken().Start(); + Lexer()->NextToken(); // eat '[' + + ArenaVector tupleTypeList(Allocator()->Adapter()); + auto *const tupleType = AllocNode(Allocator()); + + bool spreadTypePresent = false; + + while (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { + // Parse named parameter if name presents + if ((Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) && + (Lexer()->Lookahead() == lexer::LEX_CHAR_COLON)) { + ExpectIdentifier(); + Lexer()->NextToken(); // eat ':' + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { + if (spreadTypePresent) { + ThrowSyntaxError("Only one spread type declaration allowed, at the last index"); + } + + spreadTypePresent = true; + Lexer()->NextToken(); // eat '...' + } else if (spreadTypePresent) { + // This can't be implemented to any index, with type consistency. If a spread type is in the middle of + // the tuple, then bounds check can't be made for element access, so the type of elements after the + // spread can't be determined in compile time. + ThrowSyntaxError("Spread type must be at the last index in the tuple type"); + } + + auto *const currentTypeAnnotation = ParseTypeAnnotation(options); + currentTypeAnnotation->SetParent(tupleType); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { + // NOTE(mmartin): implement optional types for tuples + ThrowSyntaxError("Optional types in tuples are not yet implemented."); + } + + if (spreadTypePresent) { + if (!currentTypeAnnotation->IsTSArrayType()) { + ThrowSyntaxError("Spread type must be an array type"); + } + + tupleType->SetSpreadType(currentTypeAnnotation); + } else { + tupleTypeList.push_back(currentTypeAnnotation); + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { + Lexer()->NextToken(); // eat comma + continue; + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { + ThrowSyntaxError("Comma is mandatory between elements in a tuple type declaration"); + } + } + + Lexer()->NextToken(); // eat ']' + + tupleType->SetTypeAnnotationsList(tupleTypeList); + const auto endLoc = Lexer()->GetToken().End(); + tupleType->SetRange({startLoc, endLoc}); + + return tupleType; +} + +// Helper function for ETSParser::GetTypeAnnotationFromToken(...) method +ir::TypeNode *ETSParser::ParsePotentialFunctionalType(TypeAnnotationParsingOptions *options, + lexer::SourcePosition startLoc) +{ + if (((*options) & TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE) == 0 && + (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS || + Lexer()->Lookahead() == lexer::LEX_CHAR_COLON)) { + auto typeAnnotation = ParseFunctionType(); + typeAnnotation->SetStart(startLoc); + + if (auto position = GetDefaultParamPosition(typeAnnotation->AsETSFunctionType()->Params())) { + ThrowSyntaxError("Default parameters can not be used in functional type", position.value()); + } + + return typeAnnotation; + } + + auto savePos = Lexer()->Save(); + ParseTypeAnnotation(options); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { + ThrowSyntaxError("Default parameters can not be used in functional type"); + } + + Lexer()->Rewind(savePos); + return nullptr; +} + +// Just to reduce the size of ParseTypeAnnotation(...) method +std::pair ETSParser::GetTypeAnnotationFromToken(TypeAnnotationParsingOptions *options) +{ + ir::TypeNode *typeAnnotation = nullptr; + + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::LITERAL_IDENT: { + typeAnnotation = ParseLiteralIdent(options); + if (((*options) & TypeAnnotationParsingOptions::POTENTIAL_CLASS_LITERAL) != 0 && + (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_CLASS || IsStructKeyword())) { + return std::make_pair(typeAnnotation, false); + } + break; + } + case lexer::TokenType::LITERAL_NULL: { + typeAnnotation = AllocNode(); + typeAnnotation->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + break; + } + case lexer::TokenType::KEYW_UNDEFINED: { + typeAnnotation = AllocNode(); + typeAnnotation->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { + auto startLoc = Lexer()->GetToken().Start(); + lexer::LexerPosition savedPos = Lexer()->Save(); + Lexer()->NextToken(); // eat '(' + + typeAnnotation = ParsePotentialFunctionalType(options, startLoc); + if (typeAnnotation != nullptr) { + return std::make_pair(typeAnnotation, false); + } + + typeAnnotation = ParseTypeAnnotation(options); + typeAnnotation->SetStart(startLoc); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { + typeAnnotation = ParseUnionType(typeAnnotation); + } + + ParseRightParenthesis(options, typeAnnotation, savedPos); + break; + } + case lexer::TokenType::PUNCTUATOR_FORMAT: { + typeAnnotation = ParseTypeFormatPlaceholder(); + break; + } + case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { + typeAnnotation = ParseETSTupleType(options); + break; + } + case lexer::TokenType::KEYW_THIS: { + typeAnnotation = ParseThisType(options); + break; + } + default: { + break; + } + } + + return std::make_pair(typeAnnotation, true); +} + +ir::TypeNode *ETSParser::ParseThisType(TypeAnnotationParsingOptions *options) +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS); + + // A syntax error should be thrown if + // - the usage of 'this' as a type is not allowed in the current context, or + // - 'this' is not used as a return type, or + // - the current context is an arrow function (might be inside a method of a class where 'this' is allowed). + if (((*options & TypeAnnotationParsingOptions::THROW_ERROR) != 0) && + (((GetContext().Status() & ParserStatus::ALLOW_THIS_TYPE) == 0) || + ((*options & TypeAnnotationParsingOptions::RETURN_TYPE) == 0) || + ((GetContext().Status() & ParserStatus::ARROW_FUNCTION) != 0))) { + ThrowSyntaxError("A 'this' type is available only as return type in a non-static method of a class or struct."); + } + + auto *thisType = AllocNode(); + thisType->SetRange(Lexer()->GetToken().Loc()); + + Lexer()->NextToken(); // eat 'this' + + return thisType; +} + +ir::TypeNode *ETSParser::ParseTypeAnnotation(TypeAnnotationParsingOptions *options) +{ + bool const throwError = ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0; + + auto [typeAnnotation, needFurtherProcessing] = GetTypeAnnotationFromToken(options); + + if (typeAnnotation == nullptr) { + if (throwError) { + ThrowSyntaxError("Invalid Type"); + } + return nullptr; + } + + if (!needFurtherProcessing) { + return typeAnnotation; + } + + const lexer::SourcePosition &startPos = Lexer()->GetToken().Start(); + + while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { + Lexer()->NextToken(); // eat '[' + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET) { + if (throwError) { + ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET); + } + return nullptr; + } + + Lexer()->NextToken(); // eat ']' + typeAnnotation = AllocNode(typeAnnotation); + typeAnnotation->SetRange({startPos, Lexer()->GetToken().End()}); + } + + if (((*options) & TypeAnnotationParsingOptions::DISALLOW_UNION) == 0 && + Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_BITWISE_OR) { + return ParseUnionType(typeAnnotation); + } + + return typeAnnotation; +} + +} // namespace ark::es2panda::parser diff --git a/ets2panda/parser/TSparser.cpp b/ets2panda/parser/TSparser.cpp index f15dd0d9402d424c0f4dba8707ecc8f671500c05..0173a3725255616a40a9d257196fca94054c65ed 100644 --- a/ets2panda/parser/TSparser.cpp +++ b/ets2panda/parser/TSparser.cpp @@ -15,6 +15,8 @@ #include "TSparser.h" +#include "parser/parserStatusContext.h" +#include "macros.h" #include "parserFlags.h" #include "util/helpers.h" #include "varbinder/privateBinding.h" @@ -222,201 +224,6 @@ ir::TSTypeAliasDeclaration *TSParser::ParseTypeAliasDeclaration() return typeAliasDecl; } -// NOLINTNEXTLINE(google-default-arguments) -ir::Statement *TSParser::ParseStatement(StatementParsingFlags flags) -{ - return ParseDeclareAndDecorators(flags); -} - -ir::Expression *TSParser::ParsePotentialAsExpression(ir::Expression *expr) -{ - if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_AS) { - return nullptr; - } - - Lexer()->NextToken(); // eat 'as' - TypeAnnotationParsingOptions options = - TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_CONST; - ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options); - - bool isConst = false; - if (typeAnnotation->IsTSTypeReference() && typeAnnotation->AsTSTypeReference()->TypeName()->IsIdentifier()) { - const util::StringView &refName = typeAnnotation->AsTSTypeReference()->TypeName()->AsIdentifier()->Name(); - if (refName.Is("const")) { - isConst = true; - } - } - - lexer::SourcePosition startLoc = expr->Start(); - auto *asExpr = AllocNode(expr, typeAnnotation, isConst); - asExpr->SetRange({startLoc, Lexer()->GetToken().End()}); - - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_AS) { - return ParsePotentialAsExpression(asExpr); - } - - return asExpr; -} - -void TSParser::ParseOptionalFunctionParameter(ir::AnnotatedExpression *returnNode, bool isRest) -{ - bool isOptional = false; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { - if (isRest) { - ThrowSyntaxError("A rest parameter cannot be optional"); - } - - switch (returnNode->Type()) { - case ir::AstNodeType::IDENTIFIER: { - returnNode->AsIdentifier()->SetOptional(true); - break; - } - case ir::AstNodeType::OBJECT_PATTERN: - case ir::AstNodeType::ARRAY_PATTERN: { - if (!InAmbientContext() && ((GetContext().Status() & ParserStatus::FUNCTION) != 0)) { - ThrowSyntaxError("A binding pattern parameter cannot be optional in an implementation signature."); - } - - if (returnNode->IsObjectPattern()) { - returnNode->AsObjectPattern()->SetOptional(true); - break; - } - - returnNode->AsArrayPattern()->SetOptional(true); - break; - } - case ir::AstNodeType::REST_ELEMENT: { - returnNode->AsRestElement()->SetOptional(true); - break; - } - default: { - UNREACHABLE(); - } - } - - isOptional = true; - Lexer()->NextToken(); // eat '?' - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - returnNode->SetTsTypeAnnotation(ParseTypeAnnotation(&options)); - } - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { - return; - } - - if (isRest) { - ThrowSyntaxError("A rest parameter cannot have an initializer"); - } - - if (returnNode->IsIdentifier() && isOptional) { - ThrowSyntaxError("Parameter cannot have question mark and initializer"); - } -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *TSParser::ParsePatternElement(ExpressionParseFlags flags, bool allowDefault) -{ - ir::AnnotatedExpression *returnNode = nullptr; - bool isOptional = false; - - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { - returnNode = ParseArrayExpression(ExpressionParseFlags::MUST_BE_PATTERN); - isOptional = returnNode->AsArrayPattern()->IsOptional(); - break; - } - case lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD: { - if ((flags & ExpressionParseFlags::IN_REST) != 0) { - ThrowSyntaxError("Unexpected token"); - } - - returnNode = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN); - break; - } - case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { - returnNode = - ParseObjectExpression(ExpressionParseFlags::MUST_BE_PATTERN | ExpressionParseFlags::OBJECT_PATTERN); - isOptional = returnNode->AsObjectPattern()->IsOptional(); - break; - } - case lexer::TokenType::LITERAL_IDENT: { - returnNode = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - returnNode->AsIdentifier()->SetReference(); - - if (returnNode->AsIdentifier()->Decorators().empty()) { - returnNode->SetRange(Lexer()->GetToken().Loc()); - } else { - returnNode->SetRange( - {returnNode->AsIdentifier()->Decorators().front()->Start(), Lexer()->GetToken().End()}); - } - - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { - isOptional = true; - - if ((flags & ExpressionParseFlags::IN_REST) != 0) { - ThrowSyntaxError("A rest parameter cannot be optional"); - } - - returnNode->AsIdentifier()->SetOptional(true); - Lexer()->NextToken(); - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - returnNode->SetTsTypeAnnotation(ParseTypeAnnotation(&options)); - } - break; - } - default: { - ThrowSyntaxError("Unexpected token, expected an identifier."); - } - } - - if ((returnNode->IsObjectPattern() || returnNode->IsArrayPattern()) && !InAmbientContext() && - ((GetContext().Status() & ParserStatus::FUNCTION) != 0) && isOptional) { - ThrowSyntaxError("A binding pattern parameter cannot be optional in an implementation signature."); - } - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { - return returnNode; - } - - if ((flags & ExpressionParseFlags::IN_REST) != 0) { - ThrowSyntaxError("A rest parameter cannot have an initializer."); - } - - if (!allowDefault) { - ThrowSyntaxError("Invalid destructuring assignment target"); - } - - if (isOptional) { - ThrowSyntaxError("Parameter cannot have question mark and initializer"); - } - - Lexer()->NextToken(); - - if (((GetContext().Status() & ParserStatus::GENERATOR_FUNCTION) != 0) && - Lexer()->GetToken().Type() == lexer::TokenType::KEYW_YIELD) { - ThrowSyntaxError("Yield is not allowed in generator parameters"); - } - - ir::Expression *rightNode = ParseExpression(); - - auto *assignmentExpression = AllocNode( - ir::AstNodeType::ASSIGNMENT_PATTERN, returnNode, rightNode, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - assignmentExpression->SetRange({returnNode->Start(), rightNode->End()}); - - return assignmentExpression; -} - bool TSParser::CurrentLiteralIsBasicType() const { switch (Lexer()->GetToken().KeywordType()) { @@ -906,29 +713,18 @@ ir::TypeNode *TSParser::ParseTypeReferenceOrQuery(bool parseQuery) if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET && Lexer()->Lookahead() != lexer::LEX_CHAR_RIGHT_SQUARE) { - ir::TypeNode *typeRef {}; - if (parseQuery) { - typeRef = AllocNode(typeName); - } else { - typeRef = AllocNode(typeName, typeParamInst); - } + ir::TypeNode *typeRef = parseQuery ? AllocNode(typeName)->AsTypeNode() + : AllocNode(typeName, typeParamInst)->AsTypeNode(); typeRef->SetRange({referenceStartLoc, Lexer()->GetToken().End()}); return ParseIndexAccessType(typeRef); } - ir::TypeNode *returnNode = nullptr; - - lexer::SourcePosition referenceEndLoc = typeName->End(); - - if (parseQuery) { - returnNode = AllocNode(typeName); - } else { - returnNode = AllocNode(typeName, typeParamInst); - } + ir::TypeNode *returnNode = parseQuery ? AllocNode(typeName)->AsTypeNode() + : AllocNode(typeName, typeParamInst)->AsTypeNode(); - returnNode->SetRange({referenceStartLoc, referenceEndLoc}); + returnNode->SetRange({referenceStartLoc, typeName->End()}); return returnNode; } @@ -1230,130 +1026,116 @@ ir::TSIntersectionType *TSParser::ParseIntersectionType(ir::Expression *type, bo return intersectionType; } -ir::TypeNode *TSParser::ParseBasicType() -{ - ir::TypeNode *typeAnnotation = nullptr; +class TSParser::ParseBasicTypeHelper { + friend ir::TypeNode *TSParser::ParseBasicType(); - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS) { - Lexer()->NextToken(); +private: + static ir::TypeNode *GetTypeAnnotationFromLiteral(TSParser *parser, lexer::Lexer *lexer) + { + switch (lexer->GetToken().KeywordType()) { + case lexer::TokenType::LITERAL_NUMBER: { + if ((lexer->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) != 0) { + auto *bigintNode = parser->AllocNode(lexer->GetToken().BigInt()); + bigintNode->SetRange(lexer->GetToken().Loc()); - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NUMBER) { - ThrowSyntaxError("Type expected"); - } - } - switch (Lexer()->GetToken().KeywordType()) { - case lexer::TokenType::LITERAL_NUMBER: { - if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::NUMBER_BIGINT) != 0) { - auto *bigintNode = AllocNode(Lexer()->GetToken().BigInt()); - bigintNode->SetRange(Lexer()->GetToken().Loc()); + return parser->AllocNode(bigintNode); + } + auto *numberNode = parser->AllocNode(lexer->GetToken().GetNumber()); + numberNode->SetRange(lexer->GetToken().Loc()); - typeAnnotation = AllocNode(bigintNode); - } else { - auto *numberNode = AllocNode(Lexer()->GetToken().GetNumber()); - numberNode->SetRange(Lexer()->GetToken().Loc()); + return parser->AllocNode(numberNode); + } + case lexer::TokenType::LITERAL_STRING: { + auto *stringNode = parser->AllocNode(lexer->GetToken().String()); + stringNode->SetRange(lexer->GetToken().Loc()); - typeAnnotation = AllocNode(numberNode); + return parser->AllocNode(stringNode); } - break; - } - case lexer::TokenType::LITERAL_STRING: { - auto *stringNode = AllocNode(Lexer()->GetToken().String()); - stringNode->SetRange(Lexer()->GetToken().Loc()); + case lexer::TokenType::LITERAL_TRUE: { + auto *booleanLiteral = parser->AllocNode(true); + booleanLiteral->SetRange(lexer->GetToken().Loc()); - typeAnnotation = AllocNode(stringNode); - break; - } - case lexer::TokenType::LITERAL_TRUE: { - auto *booleanLiteral = AllocNode(true); - booleanLiteral->SetRange(Lexer()->GetToken().Loc()); + return parser->AllocNode(booleanLiteral); + } + case lexer::TokenType::LITERAL_FALSE: { + auto *booleanLiteral = parser->AllocNode(false); + booleanLiteral->SetRange(lexer->GetToken().Loc()); - typeAnnotation = AllocNode(booleanLiteral); - break; + return parser->AllocNode(booleanLiteral); + } + case lexer::TokenType::LITERAL_NULL: { + return parser->AllocNode(); + } + default: { + return nullptr; + } } - case lexer::TokenType::LITERAL_FALSE: { - auto *booleanLiteral = AllocNode(false); - booleanLiteral->SetRange(Lexer()->GetToken().Loc()); + } - typeAnnotation = AllocNode(booleanLiteral); - break; - } - case lexer::TokenType::KEYW_ANY: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_BOOLEAN: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_NUMBER: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_STRING: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_UNKNOWN: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_VOID: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::LITERAL_NULL: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_UNDEFINED: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_NEVER: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_OBJECT: { - typeAnnotation = AllocNode(); - break; - } - case lexer::TokenType::KEYW_BIGINT: { - typeAnnotation = AllocNode(); - break; + static ir::TypeNode *GetTypeAnnotation(TSParser *parser, lexer::Lexer *lexer) + { + switch (lexer->GetToken().KeywordType()) { + case lexer::TokenType::LITERAL_NUMBER: + case lexer::TokenType::LITERAL_STRING: + case lexer::TokenType::LITERAL_TRUE: + case lexer::TokenType::LITERAL_FALSE: + case lexer::TokenType::LITERAL_NULL: { + return GetTypeAnnotationFromLiteral(parser, lexer); + } + case lexer::TokenType::KEYW_ANY: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_BOOLEAN: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_NUMBER: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_STRING: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_UNKNOWN: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_VOID: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_UNDEFINED: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_NEVER: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_OBJECT: { + return parser->AllocNode(); + } + case lexer::TokenType::KEYW_BIGINT: { + return parser->AllocNode(); + } + default: { + parser->ThrowSyntaxError("Unexpected type"); + } } - default: { - ThrowSyntaxError("Unexpected type"); + } +}; +ir::TypeNode *TSParser::ParseBasicType() +{ + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS) { + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NUMBER) { + ThrowSyntaxError("Type expected"); } } + ir::TypeNode *typeAnnotation = ParseBasicTypeHelper::GetTypeAnnotation(this, Lexer()); + typeAnnotation->SetRange(Lexer()->GetToken().Loc()); Lexer()->NextToken(); return typeAnnotation; } -ir::TSTypeReference *TSParser::ParseConstExpression() -{ - auto *identRef = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - identRef->SetReference(); - identRef->SetRange(Lexer()->GetToken().Loc()); - - auto *typeReference = AllocNode(identRef, nullptr); - typeReference->SetRange(Lexer()->GetToken().Loc()); - - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA && - Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON && - Lexer()->GetToken().Type() != lexer::TokenType::EOS && - Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET && - ((Lexer()->GetToken().Flags() & lexer::TokenFlags::NEW_LINE) == 0)) { - ThrowSyntaxError("Unexpected token."); - } - - return typeReference; -} - ir::TypeNode *TSParser::ParseParenthesizedOrFunctionType(ir::TypeNode *typeAnnotation, bool throwError) { if (typeAnnotation != nullptr) { @@ -1467,80 +1249,130 @@ ir::TypeNode *TSParser::ParseFunctionType(lexer::SourcePosition startLoc, bool i return funcType; } -ir::TypeNode *TSParser::ParseTypeAnnotationElement(ir::TypeNode *typeAnnotation, TypeAnnotationParsingOptions *options) -{ - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { - if (((*options) & - (TypeAnnotationParsingOptions::IN_UNION | TypeAnnotationParsingOptions::IN_INTERSECTION)) != 0) { - break; - } +class TSParser::ParseTypeAnnotationElementHelper { + friend ir::TypeNode *TSParser::ParseTypeAnnotationElement(ir::TypeNode *typeAnnotation, + TypeAnnotationParsingOptions *options); - return ParseUnionType(typeAnnotation, ((*options) & TypeAnnotationParsingOptions::RESTRICT_EXTENDS) != 0); - } - case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { - if (((*options) & TypeAnnotationParsingOptions::IN_INTERSECTION) != 0) { - break; +private: + static ir::TypeNode *ParseKeywordTokens(TSParser *parser, lexer::Lexer *lexer, ir::TypeNode *typeAnnotation, + TypeAnnotationParsingOptions *options) + { + switch (lexer->GetToken().Type()) { + case lexer::TokenType::KEYW_NEW: { + return parser->ParseParenthesizedOrFunctionType( + typeAnnotation, ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0); } + case lexer::TokenType::KEYW_TYPEOF: { + if (typeAnnotation != nullptr) { + break; + } - return ParseIntersectionType(typeAnnotation, ((*options) & TypeAnnotationParsingOptions::IN_UNION) != 0, - ((*options) & TypeAnnotationParsingOptions::RESTRICT_EXTENDS) != 0); - } - case lexer::TokenType::PUNCTUATOR_LESS_THAN: - case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: - case lexer::TokenType::KEYW_NEW: { - return ParseParenthesizedOrFunctionType(typeAnnotation, - ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0); - } - case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { - if (typeAnnotation != nullptr) { - if (Lexer()->Lookahead() == lexer::LEX_CHAR_RIGHT_SQUARE) { - return ParseArrayType(typeAnnotation); + return parser->ParseTypeReferenceOrQuery(true); + } + case lexer::TokenType::KEYW_IMPORT: { + if (typeAnnotation != nullptr) { + break; + } + return parser->ParseImportType(lexer->GetToken().Start()); + } + case lexer::TokenType::KEYW_CONST: { + if (((*options) & TypeAnnotationParsingOptions::ALLOW_CONST) == 0) { + break; } - return ParseIndexAccessType(typeAnnotation); + (*options) &= ~TypeAnnotationParsingOptions::ALLOW_CONST; + return parser->ParseConstExpression(); } + case lexer::TokenType::KEYW_EXTENDS: { + if (((*options) & + (TypeAnnotationParsingOptions::IN_UNION | TypeAnnotationParsingOptions::IN_INTERSECTION)) != 0) { + break; + } - return ParseTupleType(); - } - case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { - return ParseTypeLiteralOrMappedType(typeAnnotation); - } - case lexer::TokenType::PUNCTUATOR_MINUS: - case lexer::TokenType::LITERAL_NUMBER: - case lexer::TokenType::LITERAL_STRING: - case lexer::TokenType::LITERAL_FALSE: - case lexer::TokenType::LITERAL_TRUE: - case lexer::TokenType::LITERAL_NULL: - case lexer::TokenType::KEYW_VOID: { - if (typeAnnotation != nullptr) { + if (typeAnnotation == nullptr) { + return parser->ParseIdentifierReference(); + } + + return parser->ParseConditionalType(typeAnnotation, + ((*options) & TypeAnnotationParsingOptions::RESTRICT_EXTENDS) != 0); + } + case lexer::TokenType::KEYW_THIS: { + return parser->ParseThisTypeOrTypePredicate( + typeAnnotation, ((*options) & TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE) != 0, + ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0); + } + default: { break; } - - return ParseBasicType(); } - case lexer::TokenType::KEYW_TYPEOF: { - if (typeAnnotation != nullptr) { - break; + return nullptr; + } + + static ir::TypeNode *ParsePunctuatorTokens(TSParser *parser, lexer::Lexer *lexer, ir::TypeNode *typeAnnotation, + TypeAnnotationParsingOptions *options) + { + switch (lexer->GetToken().Type()) { + case lexer::TokenType::PUNCTUATOR_BITWISE_OR: { + if (((*options) & + (TypeAnnotationParsingOptions::IN_UNION | TypeAnnotationParsingOptions::IN_INTERSECTION)) != 0) { + break; + } + + return parser->ParseUnionType(typeAnnotation, + ((*options) & TypeAnnotationParsingOptions::RESTRICT_EXTENDS) != 0); } + case lexer::TokenType::PUNCTUATOR_BITWISE_AND: { + if (((*options) & TypeAnnotationParsingOptions::IN_INTERSECTION) != 0) { + break; + } - return ParseTypeReferenceOrQuery(true); - } - case lexer::TokenType::KEYW_IMPORT: { - if (typeAnnotation != nullptr) { - break; + return parser->ParseIntersectionType( + typeAnnotation, ((*options) & TypeAnnotationParsingOptions::IN_UNION) != 0, + ((*options) & TypeAnnotationParsingOptions::RESTRICT_EXTENDS) != 0); + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { + return parser->ParseParenthesizedOrFunctionType( + typeAnnotation, ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0); } + case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { + if (typeAnnotation != nullptr) { + if (lexer->Lookahead() == lexer::LEX_CHAR_RIGHT_SQUARE) { + return parser->ParseArrayType(typeAnnotation); + } - lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); - return ParseImportType(startLoc); + return parser->ParseIndexAccessType(typeAnnotation); + } + + return parser->ParseTupleType(); + } + case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { + return parser->ParseTypeLiteralOrMappedType(typeAnnotation); + } + default: { + break; + } } - case lexer::TokenType::KEYW_CONST: { - if (((*options) & TypeAnnotationParsingOptions::ALLOW_CONST) == 0) { + + return nullptr; + } +}; + +ir::TypeNode *TSParser::ParseTypeAnnotationElement(ir::TypeNode *typeAnnotation, TypeAnnotationParsingOptions *options) +{ + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::PUNCTUATOR_MINUS: + case lexer::TokenType::LITERAL_NUMBER: + case lexer::TokenType::LITERAL_STRING: + case lexer::TokenType::LITERAL_FALSE: + case lexer::TokenType::LITERAL_TRUE: + case lexer::TokenType::LITERAL_NULL: + case lexer::TokenType::KEYW_VOID: { + if (typeAnnotation != nullptr) { break; } - (*options) &= ~TypeAnnotationParsingOptions::ALLOW_CONST; - return ParseConstExpression(); + return ParseBasicType(); } case lexer::TokenType::LITERAL_IDENT: { if (IsStartOfAbstractConstructorType()) { @@ -1551,25 +1383,19 @@ ir::TypeNode *TSParser::ParseTypeAnnotationElement(ir::TypeNode *typeAnnotation, return ParseTypeReferenceOrTypePredicate( typeAnnotation, ((*options) & TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE) != 0); } - case lexer::TokenType::KEYW_EXTENDS: { - if (((*options) & - (TypeAnnotationParsingOptions::IN_UNION | TypeAnnotationParsingOptions::IN_INTERSECTION)) != 0) { - break; + default: { + ir::TypeNode *parsedValue = + ParseTypeAnnotationElementHelper::ParseKeywordTokens(this, Lexer(), typeAnnotation, options); + if (parsedValue != nullptr) { + return parsedValue; } - if (typeAnnotation == nullptr) { - return ParseIdentifierReference(); + parsedValue = + ParseTypeAnnotationElementHelper::ParsePunctuatorTokens(this, Lexer(), typeAnnotation, options); + if (parsedValue != nullptr) { + return parsedValue; } - return ParseConditionalType(typeAnnotation, - ((*options) & TypeAnnotationParsingOptions::RESTRICT_EXTENDS) != 0); - } - case lexer::TokenType::KEYW_THIS: { - return ParseThisTypeOrTypePredicate( - typeAnnotation, ((*options) & TypeAnnotationParsingOptions::CAN_BE_TS_TYPE_PREDICATE) != 0, - ((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0); - } - default: { break; } } @@ -1581,101 +1407,6 @@ ir::TypeNode *TSParser::ParseTypeAnnotationElement(ir::TypeNode *typeAnnotation, return nullptr; } -// NOLINTNEXTLINE(google-default-arguments) -ir::ObjectExpression *TSParser::ParseObjectExpression(ExpressionParseFlags flags) -{ - ir::ObjectExpression *objExpression = ParserImpl::ParseObjectExpression(flags); - ParsePotentialOptionalFunctionParameter(objExpression); - return objExpression; -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::ArrayExpression *TSParser::ParseArrayExpression(ExpressionParseFlags flags) -{ - ir::ArrayExpression *arrayExpression = ParserImpl::ParseArrayExpression(flags); - ParsePotentialOptionalFunctionParameter(arrayExpression); - return arrayExpression; -} - -ir::ArrowFunctionExpression *TSParser::ParsePotentialArrowExpression(ir::Expression **returnExpression, - const lexer::SourcePosition &startLoc) -{ - ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; - - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::KEYW_FUNCTION: { - *returnExpression = ParseFunctionExpression(ParserStatus::ASYNC_FUNCTION); - (*returnExpression)->SetStart(startLoc); - break; - } - case lexer::TokenType::LITERAL_IDENT: { - ir::Expression *identRef = ParsePrimaryExpression(); - ASSERT(identRef->IsIdentifier()); - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { - ThrowSyntaxError("Unexpected token, expected '=>'"); - } - - ir::ArrowFunctionExpression *arrowFuncExpr = ParseArrowFunctionExpression(identRef, nullptr, nullptr, true); - arrowFuncExpr->SetStart(startLoc); - - return arrowFuncExpr; - } - case lexer::TokenType::PUNCTUATOR_ARROW: { - ir::ArrowFunctionExpression *arrowFuncExpr = - ParseArrowFunctionExpression(*returnExpression, nullptr, nullptr, true); - arrowFuncExpr->SetStart(startLoc); - return arrowFuncExpr; - } - case lexer::TokenType::PUNCTUATOR_LESS_THAN: { - const auto savedPos = Lexer()->Save(); - - auto options = TypeAnnotationParsingOptions::NO_OPTS; - typeParamDecl = ParseTypeParameterDeclaration(&options); - if (typeParamDecl == nullptr) { - Lexer()->Rewind(savedPos); - return nullptr; - } - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { - ThrowSyntaxError("'(' expected"); - } - - [[fallthrough]]; - } - case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { - ir::CallExpression *callExpression = ParseCallExpression(*returnExpression, false); - - ir::TypeNode *returnTypeAnnotation = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - returnTypeAnnotation = ParseTypeAnnotation(&options); - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW) { - ir::ArrowFunctionExpression *arrowFuncExpr = - ParseArrowFunctionExpression(callExpression, typeParamDecl, returnTypeAnnotation, true); - arrowFuncExpr->SetStart(startLoc); - - return arrowFuncExpr; - } - - if (returnTypeAnnotation != nullptr || typeParamDecl != nullptr) { - ThrowSyntaxError("'=>' expected"); - } - - *returnExpression = callExpression; - break; - } - default: { - break; - } - } - - return nullptr; -} - bool TSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, ir::Expression **returnExpression, const lexer::SourcePosition &startLoc, bool ignoreCallExpression) { @@ -1725,18 +1456,6 @@ bool TSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, ir return true; } -bool TSParser::ParsePotentialNonNullExpression(ir::Expression **returnExpression, lexer::SourcePosition startLoc) -{ - if (returnExpression == nullptr || Lexer()->GetToken().NewLine()) { - return true; - } - - *returnExpression = AllocNode(*returnExpression); - (*returnExpression)->SetRange({startLoc, Lexer()->GetToken().End()}); - Lexer()->NextToken(); - return false; -} - bool TSParser::IsNamedFunctionExpression() { return Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS && @@ -1756,15 +1475,6 @@ ir::Identifier *TSParser::ParsePrimaryExpressionIdent([[maybe_unused]] Expressio return identNode; } -void TSParser::ValidateArrowFunctionRestParameter(ir::SpreadElement *restElement) -{ - ParseOptionalFunctionParameter(restElement, true); - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - ThrowSyntaxError("')' expected"); - } -} - ir::TSSignatureDeclaration *TSParser::ParseSignatureMember(bool isCallSignature) { lexer::SourcePosition memberStartLoc = Lexer()->GetToken().Start(); @@ -1945,21 +1655,13 @@ void TSParser::CreateTSVariableForProperty(ir::AstNode *node, const ir::Expressi ir::AstNode *TSParser::ParsePropertyOrMethodSignature(const lexer::SourcePosition &startLoc, bool isReadonly) { auto [key, isComputed] = ParseInterfacePropertyKey(); + varbinder::VariableFlags flags = isReadonly ? varbinder::VariableFlags::READONLY : varbinder::VariableFlags::NONE; bool isOptional = false; if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { isOptional = true; - Lexer()->NextToken(); // eat '?' - } - - varbinder::VariableFlags flags = varbinder::VariableFlags::NONE; - - if (isOptional) { flags |= varbinder::VariableFlags::OPTIONAL; - } - - if (isReadonly) { - flags |= varbinder::VariableFlags::READONLY; + Lexer()->NextToken(); // eat '?' } if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS || @@ -1975,9 +1677,7 @@ ir::AstNode *TSParser::ParsePropertyOrMethodSignature(const lexer::SourcePositio typeParamDecl = ParseTypeParameterDeclaration(&options); } - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { - ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); - } + ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS, false); FunctionParameterContext funcParamContext(&GetContext()); auto params = ParseFunctionParams(); @@ -2133,73 +1833,6 @@ ArenaVector TSParser::ParseFunctionParams() return params; } -ir::TSParameterProperty *TSParser::CreateParameterProperty(ir::Expression *parameter, ir::ModifierFlags modifiers) -{ - auto accessibility = ir::AccessibilityOption::NO_OPTS; - bool readonly = false; - bool isStatic = false; - bool isExport = false; - - if ((modifiers & ir::ModifierFlags::PRIVATE) != 0) { - accessibility = ir::AccessibilityOption::PRIVATE; - } else if ((modifiers & ir::ModifierFlags::PUBLIC) != 0) { - accessibility = ir::AccessibilityOption::PUBLIC; - } else if ((modifiers & ir::ModifierFlags::PROTECTED) != 0) { - accessibility = ir::AccessibilityOption::PROTECTED; - } - - if ((modifiers & ir::ModifierFlags::READONLY) != 0) { - readonly = true; - } - - if ((modifiers & ir::ModifierFlags::STATIC) != 0) { - isStatic = true; - } - - // NOTE(Csaba Repasi): Handle export property of TSParameterProperty - - return AllocNode(accessibility, parameter, readonly, isStatic, isExport); -} - -ir::Expression *TSParser::ParseFunctionParameter() -{ - if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS) { - Lexer()->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT); - } - - lexer::SourcePosition parameterStart = Lexer()->GetToken().Start(); - ir::ModifierFlags modifiers = ParseModifiers(); - // NOTE(Csaba Repasi): throw error if using strick mode reserved keyword here - if (((GetContext().Status() & ParserStatus::CONSTRUCTOR_FUNCTION) == 0) && modifiers != ir::ModifierFlags::NONE) { - ThrowSyntaxError("A parameter property is only allowed in a constructor implementation.", parameterStart); - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { - CheckRestrictedBinding(); - } - - ir::Expression *functionParameter = ParsePatternElement(ExpressionParseFlags::NO_OPTS, true); - - if (modifiers != ir::ModifierFlags::NONE && functionParameter->IsRestElement()) { - ThrowSyntaxError("A parameter property cannot be declared using a rest parameter.", parameterStart); - } - - if (modifiers != ir::ModifierFlags::NONE && - (functionParameter->IsArrayPattern() || functionParameter->IsObjectPattern() || - (functionParameter->IsAssignmentPattern() && - (functionParameter->AsAssignmentPattern()->Left()->IsArrayPattern() || - functionParameter->AsAssignmentPattern()->Left()->IsObjectPattern())))) { - ThrowSyntaxError("A parameter property may not be declared using a binding pattern.", parameterStart); - } - - if (modifiers != ir::ModifierFlags::NONE) { - functionParameter = CreateParameterProperty(functionParameter, modifiers); - functionParameter->SetRange({parameterStart, functionParameter->AsTSParameterProperty()->Parameter()->End()}); - } - - return functionParameter; -} - ir::TypeNode *TSParser::ParseClassKeyAnnotation() { if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { @@ -2466,44 +2099,6 @@ std::tuple TSParser::Pa return {letDeclare, body, endLoc, isOverload}; } -ir::Expression *TSParser::ParseModuleReference() -{ - ir::Expression *result = nullptr; - - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_REQUIRE && - Lexer()->Lookahead() == lexer::LEX_CHAR_LEFT_PAREN) { - lexer::SourcePosition start = Lexer()->GetToken().Start(); - Lexer()->NextToken(); // eat 'require' - Lexer()->NextToken(); // eat '(' - - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { - ThrowSyntaxError("String literal expected."); - } - - result = AllocNode(Lexer()->GetToken().String()); - result->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - ThrowSyntaxError("')' expected."); - } - - result = AllocNode(result); - result->SetRange({start, Lexer()->GetToken().End()}); - Lexer()->NextToken(); // eat ')' - } else { - result = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - result->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { - result = ParseQualifiedReference(result); - } - } - - return result; -} - ir::AstNode *TSParser::ParseImportDefaultSpecifier(ArenaVector *specifiers) { ir::Identifier *local = ParseNamedImport(Lexer()->GetToken()); @@ -2533,197 +2128,6 @@ ir::AstNode *TSParser::ParseImportDefaultSpecifier(ArenaVector *s return nullptr; } -ir::TSImportEqualsDeclaration *TSParser::ParseTsImportEqualsDeclaration(const lexer::SourcePosition &startLoc, - bool isExport) -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_IMPORT); - Lexer()->NextToken(); - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { - ThrowSyntaxError("Unexpected token"); - } - - auto *id = AllocNode(Lexer()->GetToken().Ident(), Allocator()); - id->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); // eat id name - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { - ThrowSyntaxError("'=' expected"); - } - Lexer()->NextToken(); // eat substitution - - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { - ThrowSyntaxError("identifier expected"); - } - - auto *importEqualsDecl = AllocNode(id, ParseModuleReference(), isExport); - importEqualsDecl->SetRange({startLoc, Lexer()->GetToken().End()}); - - ConsumeSemicolon(importEqualsDecl); - - return importEqualsDecl; -} - -ir::Statement *TSParser::ParseExportDeclaration(StatementParsingFlags flags) -{ - lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); - Lexer()->NextToken(); // eat `export` keyword - - switch (Lexer()->GetToken().Type()) { - case lexer::TokenType::KEYW_DEFAULT: { - return ParseExportDefaultDeclaration(startLoc); - } - case lexer::TokenType::PUNCTUATOR_MULTIPLY: { - return ParseExportAllDeclaration(startLoc); - } - case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { - return ParseExportNamedSpecifiers(startLoc); - } - case lexer::TokenType::KEYW_IMPORT: { - return ParseTsImportEqualsDeclaration(startLoc, true); - } - case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: { - return ParseExportDefaultDeclaration(startLoc, true); - } - default: { - ir::ExportNamedDeclaration *exportDecl = ParseNamedExportDeclaration(startLoc); - - if (exportDecl->Decl()->IsVariableDeclaration() && ((flags & StatementParsingFlags::GLOBAL) == 0) && - exportDecl->Parent() != nullptr && !exportDecl->Parent()->IsTSModuleBlock() && - !GetContext().IsModule()) { - ThrowSyntaxError("Modifiers cannot appear here'"); - } - - return exportDecl; - } - } -} - -ir::Expression *TSParser::ParseArrowFunctionRestParameter(lexer::SourcePosition start) -{ - ir::SpreadElement *restElement = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN); - - restElement->SetGrouped(); - restElement->SetStart(start); - - ValidateArrowFunctionRestParameter(restElement); - - Lexer()->NextToken(); - - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - ir::TypeNode *returnTypeAnnotation = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - returnTypeAnnotation = ParseTypeAnnotation(&options); - } - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { - ThrowSyntaxError("Unexpected token"); - } - - return ParseArrowFunctionExpression(restElement, nullptr, returnTypeAnnotation, false); -} - -ir::Expression *TSParser::ParseArrowFunctionNoParameter(lexer::SourcePosition start) -{ - Lexer()->NextToken(); - - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - ir::TypeNode *returnTypeAnnotation = nullptr; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - returnTypeAnnotation = ParseTypeAnnotation(&options); - } - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { - ThrowSyntaxError("Unexpected token"); - } - - auto *arrowExpr = ParseArrowFunctionExpression(nullptr, nullptr, returnTypeAnnotation, false); - arrowExpr->SetStart(start); - arrowExpr->AsArrowFunctionExpression()->Function()->SetStart(start); - - return arrowExpr; -} - -// NOLINTNEXTLINE(google-default-arguments) -ir::Expression *TSParser::ParseCoverParenthesizedExpressionAndArrowParameterList( - [[maybe_unused]] ExpressionParseFlags flags) -{ - ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); - lexer::SourcePosition start = Lexer()->GetToken().Start(); - Lexer()->NextToken(); - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { - return ParseArrowFunctionRestParameter(start); - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - return ParseArrowFunctionNoParameter(start); - } - - ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::ACCEPT_REST | - ExpressionParseFlags::POTENTIALLY_IN_PATTERN); - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { - ThrowSyntaxError("Unexpected token, expected ')'"); - } - - expr->SetGrouped(); - expr->SetRange({start, Lexer()->GetToken().End()}); - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - auto savedPos = Lexer()->Save(); - Lexer()->NextToken(); // eat ':' - options = TypeAnnotationParsingOptions::NO_OPTS; - ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options); - - if (returnTypeAnnotation == nullptr) { - Lexer()->Rewind(savedPos); - return expr; - } - - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { - Lexer()->Rewind(savedPos); - return expr; - } - - return ParseArrowFunctionExpression(expr, nullptr, returnTypeAnnotation, false); - } - - return expr; -} - -ir::Statement *TSParser::ParseConstStatement(StatementParsingFlags flags) -{ - lexer::SourcePosition constVarStar = Lexer()->GetToken().Start(); - Lexer()->NextToken(); - - if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ENUM) { - return ParseEnumDeclaration(true); - } - - if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) { - ThrowSyntaxError("Lexical declaration is not allowed in single statement context"); - } - - auto *variableDecl = ParseVariableDeclaration(VariableParsingFlags::CONST | VariableParsingFlags::NO_SKIP_VAR_KIND); - variableDecl->SetStart(constVarStar); - ConsumeSemicolon(variableDecl); - - return variableDecl; -} - -ir::Statement *TSParser::ParsePotentialConstEnum(VariableParsingFlags flags) -{ - if ((flags & VariableParsingFlags::CONST) == 0) { - ThrowSyntaxError("Variable declaration expected."); - } - - return ParseEnumDeclaration(true); -} - void TSParser::ParseCatchParamTypeAnnotation([[maybe_unused]] ir::AnnotatedExpression *param) { if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { @@ -2738,19 +2142,6 @@ void TSParser::ParseCatchParamTypeAnnotation([[maybe_unused]] ir::AnnotatedExpre } } -ir::AnnotatedExpression *TSParser::ParseVariableDeclaratorKey(VariableParsingFlags flags) -{ - ir::AnnotatedExpression *init = ParserImpl::ParseVariableDeclaratorKey(flags); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { - Lexer()->NextToken(); // eat ':' - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - init->SetTsTypeAnnotation(ParseTypeAnnotation(&options)); - } - - return init; -} - void TSParser::ThrowPossibleOutOfBoundaryJumpError(bool allowBreak) { if (((GetContext().Status() & ParserStatus::FUNCTION) != 0) && !allowBreak) { @@ -2785,165 +2176,4 @@ void TSParser::ThrowIfBodyEmptyError(ir::Statement *consequent) } } -// NOLINTNEXTLINE(google-default-arguments) -ir::ExportDefaultDeclaration *TSParser::ParseExportDefaultDeclaration(const lexer::SourcePosition &startLoc, - bool isExportEquals) -{ - Lexer()->NextToken(); // eat `default` keyword or `=` - - ir::AstNode *declNode = nullptr; - bool eatSemicolon = false; - - switch (Lexer()->GetToken().KeywordType()) { - case lexer::TokenType::KEYW_FUNCTION: { - declNode = ParseFunctionDeclaration(true); - break; - } - case lexer::TokenType::KEYW_CLASS: { - declNode = ParseClassDeclaration(ir::ClassDefinitionModifiers::ID_REQUIRED); - break; - } - case lexer::TokenType::KEYW_INTERFACE: { - declNode = ParseInterfaceDeclaration(false); - break; - } - case lexer::TokenType::KEYW_ASYNC: { - if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) == 0) { - Lexer()->NextToken(); // eat `async` - declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); - break; - } - [[fallthrough]]; - } - default: { - declNode = ParseExpression(); - eatSemicolon = true; - break; - } - } - - lexer::SourcePosition endLoc = declNode->End(); - auto *exportDeclaration = AllocNode(declNode, isExportEquals); - exportDeclaration->SetRange({startLoc, endLoc}); - - if (eatSemicolon) { - ConsumeSemicolon(exportDeclaration); - } - - return exportDeclaration; -} - -ir::ExportNamedDeclaration *TSParser::ParseNamedExportDeclaration(const lexer::SourcePosition &startLoc) -{ - ir::Statement *decl = nullptr; - - ir::ClassDefinitionModifiers classModifiers = ir::ClassDefinitionModifiers::ID_REQUIRED; - ir::ModifierFlags flags = ir::ModifierFlags::NONE; - - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE) { - CheckDeclare(); - } - - if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_ABSTRACT) { - Lexer()->NextToken(); // eat 'abstract' - flags |= ir::ModifierFlags::ABSTRACT; - } - - switch (Lexer()->GetToken().KeywordType()) { - case lexer::TokenType::KEYW_VAR: { - decl = ParseVariableDeclaration(VariableParsingFlags::VAR); - break; - } - case lexer::TokenType::KEYW_CONST: { - decl = ParseVariableDeclaration(VariableParsingFlags::CONST); - break; - } - case lexer::TokenType::KEYW_LET: { - decl = ParseVariableDeclaration(VariableParsingFlags::LET); - break; - } - case lexer::TokenType::KEYW_FUNCTION: { - decl = ParseFunctionDeclaration(false, ParserStatus::NO_OPTS); - break; - } - case lexer::TokenType::KEYW_CLASS: { - decl = ParseClassDeclaration(classModifiers, flags); - break; - } - case lexer::TokenType::KEYW_ENUM: { - decl = ParseEnumDeclaration(); - break; - } - case lexer::TokenType::KEYW_INTERFACE: { - decl = ParseInterfaceDeclaration(false); - break; - } - case lexer::TokenType::KEYW_TYPE: { - decl = ParseTypeAliasDeclaration(); - break; - } - case lexer::TokenType::KEYW_GLOBAL: - case lexer::TokenType::KEYW_MODULE: - case lexer::TokenType::KEYW_NAMESPACE: { - decl = ParseModuleDeclaration(); - break; - } - default: { - if (!Lexer()->GetToken().IsAsyncModifier()) { - ThrowSyntaxError("Unexpected token"); - } - - Lexer()->NextToken(); // eat `async` keyword - decl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); - } - } - - if (decl->IsVariableDeclaration()) { - ConsumeSemicolon(decl); - } - - lexer::SourcePosition endLoc = decl->End(); - ArenaVector specifiers(Allocator()->Adapter()); - auto *exportDeclaration = AllocNode(Allocator(), decl, std::move(specifiers)); - exportDeclaration->SetRange({startLoc, endLoc}); - - return exportDeclaration; -} - -ir::Statement *TSParser::ParseImportDeclaration([[maybe_unused]] StatementParsingFlags flags) -{ - char32_t nextChar = Lexer()->Lookahead(); - if (nextChar == lexer::LEX_CHAR_LEFT_PAREN || nextChar == lexer::LEX_CHAR_DOT) { - return ParseExpressionStatement(); - } - - lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); - Lexer()->NextToken(); // eat import - - ArenaVector specifiers(Allocator()->Adapter()); - - ir::StringLiteral *source = nullptr; - - if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { - ir::AstNode *astNode = ParseImportSpecifiers(&specifiers); - if (astNode != nullptr) { - ASSERT(astNode->IsTSImportEqualsDeclaration()); - astNode->SetRange({startLoc, Lexer()->GetToken().End()}); - ConsumeSemicolon(astNode->AsTSImportEqualsDeclaration()); - return astNode->AsTSImportEqualsDeclaration(); - } - source = ParseFromClause(true); - } else { - source = ParseFromClause(false); - } - - lexer::SourcePosition endLoc = source->End(); - auto *importDeclaration = AllocNode(source, std::move(specifiers)); - importDeclaration->SetRange({startLoc, endLoc}); - - ConsumeSemicolon(importDeclaration); - - return importDeclaration; -} - } // namespace ark::es2panda::parser diff --git a/ets2panda/parser/TSparser.h b/ets2panda/parser/TSparser.h index 4c492cf97b3185f083682d581bc5601a3be47ae6..971d4b42ef00ee001d2e23b7716ccb6d30be75ec 100644 --- a/ets2panda/parser/TSparser.h +++ b/ets2panda/parser/TSparser.h @@ -39,8 +39,11 @@ private: bool IsStartOfAbstractConstructorType() const; bool CurrentLiteralIsBasicType() const; ir::TypeNode *ParseTypeAnnotationElement(ir::TypeNode *typeAnnotation, TypeAnnotationParsingOptions *options); + class ParseTypeAnnotationElementHelper; + class ParsePotentialArrowExpressionHelper; ir::TypeNode *ParseTypeOperatorOrTypeReference(); ir::TypeNode *ParseIdentifierReference(); + class ParseBasicTypeHelper; ir::TypeNode *ParseBasicType(); ir::TSTypeReference *ParseConstExpression(); ir::TSIntersectionType *ParseIntersectionType(ir::Expression *type, bool inUnion, bool restrictExtends); @@ -78,6 +81,7 @@ private: // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParseStatement(StatementParsingFlags flags = StatementParsingFlags::NONE) override; + ir::AnnotatedExpression *ParsePatternElementGetReturnNode(ExpressionParseFlags &flags, bool &isOptional); // NOLINTNEXTLINE(google-default-arguments) ir::Expression *ParsePatternElement(ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS, bool allowDefault = true) override; @@ -140,6 +144,7 @@ private: // NOLINTNEXTLINE(google-default-arguments) ir::ExportDefaultDeclaration *ParseExportDefaultDeclaration(const lexer::SourcePosition &startLoc, bool isExportEquals = false) override; + ir::Statement *GetDeclarationForNamedExport(ir::ClassDefinitionModifiers &classModifiers, ir::ModifierFlags &flags); ir::ExportNamedDeclaration *ParseNamedExportDeclaration(const lexer::SourcePosition &startLoc) override; ir::Statement *ParseImportDeclaration(StatementParsingFlags flags) override; void ValidateIndexSignatureTypeAnnotation(ir::TypeNode *typeAnnotation) override; diff --git a/ets2panda/parser/TypedParser.cpp b/ets2panda/parser/TypedParser.cpp index 45b5d4dfa6ad3add659f400eb7520adecc9b9239..892b2dd2268c77a0447d05d17944dd26ac6bf499 100644 --- a/ets2panda/parser/TypedParser.cpp +++ b/ets2panda/parser/TypedParser.cpp @@ -15,6 +15,7 @@ #include "TypedParser.h" +#include "parser/parserStatusContext.h" #include "varbinder/privateBinding.h" #include "lexer/lexer.h" #include "ir/base/classDefinition.h" diff --git a/ets2panda/parser/expressionParser.cpp b/ets2panda/parser/expressionParser.cpp index 67468ab682f9c20e069afa94914cc9ab66112ab5..39e4dc506d4485056db588fe703b0140a1520edc 100644 --- a/ets2panda/parser/expressionParser.cpp +++ b/ets2panda/parser/expressionParser.cpp @@ -73,6 +73,7 @@ #include +#include "parser/parserStatusContext.h" #include "parserImpl.h" namespace ark::es2panda::parser { @@ -214,6 +215,13 @@ ir::ArrayExpression *ParserImpl::ParseArrayExpression(ExpressionParseFlags flags arrayExpressionNode->SetDeclaration(); } + ParseArrayExpressionErrorCheck(arrayExpressionNode, flags, inPattern); + return arrayExpressionNode; +} + +void ParserImpl::ParseArrayExpressionErrorCheck(ir::ArrayExpression *arrayExpressionNode, + const ExpressionParseFlags flags, const bool inPattern) +{ if ((flags & ExpressionParseFlags::POTENTIALLY_IN_PATTERN) == 0) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION && !arrayExpressionNode->ConvertibleToArrayPattern()) { @@ -225,8 +233,6 @@ ir::ArrayExpression *ParserImpl::ParseArrayExpression(ExpressionParseFlags flags } } } - - return arrayExpressionNode; } ParserStatus ParserImpl::ValidateArrowParameter(ir::Expression *expr, [[maybe_unused]] bool *seenOptional) @@ -248,9 +254,8 @@ ParserStatus ParserImpl::ValidateArrowParameter(ir::Expression *expr, [[maybe_un return ParserStatus::NO_OPTS; } case ir::AstNodeType::OBJECT_EXPRESSION: { - ir::ObjectExpression *objectPattern = expr->AsObjectExpression(); - - if (!objectPattern->ConvertibleToObjectPattern()) { + if (ir::ObjectExpression *objectPattern = expr->AsObjectExpression(); + !objectPattern->ConvertibleToObjectPattern()) { ThrowSyntaxError("Invalid destructuring assignment target"); } @@ -258,9 +263,8 @@ ParserStatus ParserImpl::ValidateArrowParameter(ir::Expression *expr, [[maybe_un return ParserStatus::HAS_COMPLEX_PARAM; } case ir::AstNodeType::ARRAY_EXPRESSION: { - ir::ArrayExpression *arrayPattern = expr->AsArrayExpression(); - - if (!arrayPattern->ConvertibleToArrayPattern()) { + if (ir::ArrayExpression *arrayPattern = expr->AsArrayExpression(); + !arrayPattern->ConvertibleToArrayPattern()) { ThrowSyntaxError("Invalid destructuring assignment target"); } @@ -268,19 +272,7 @@ ParserStatus ParserImpl::ValidateArrowParameter(ir::Expression *expr, [[maybe_un return ParserStatus::HAS_COMPLEX_PARAM; } case ir::AstNodeType::ASSIGNMENT_EXPRESSION: { - auto *assignmentExpr = expr->AsAssignmentExpression(); - if (assignmentExpr->Right()->IsYieldExpression()) { - ThrowSyntaxError("yield is not allowed in arrow function parameters"); - } - - if (assignmentExpr->Right()->IsAwaitExpression()) { - ThrowSyntaxError("await is not allowed in arrow function parameters"); - } - - if (!assignmentExpr->ConvertibleToAssignmentPattern()) { - ThrowSyntaxError("Invalid destructuring assignment target"); - } - + ValidateArrowParameterAssignment(expr->AsAssignmentExpression()); ValidateArrowParameterBindings(expr); return ParserStatus::HAS_COMPLEX_PARAM; } @@ -292,6 +284,17 @@ ParserStatus ParserImpl::ValidateArrowParameter(ir::Expression *expr, [[maybe_un return ParserStatus::NO_OPTS; } +void ParserImpl::ValidateArrowParameterAssignment(ir::AssignmentExpression *expr) +{ + if (expr->Right()->IsYieldExpression()) { + ThrowSyntaxError("yield is not allowed in arrow function parameters"); + } else if (expr->Right()->IsAwaitExpression()) { + ThrowSyntaxError("await is not allowed in arrow function parameters"); + } else if (!expr->ConvertibleToAssignmentPattern()) { + ThrowSyntaxError("Invalid destructuring assignment target"); + } +} + ir::ArrowFunctionExpression *ParserImpl::ParseArrowFunctionExpressionBody(ArrowFunctionContext *arrowFunctionContext, ArrowFunctionDescriptor *desc, ir::TSTypeParameterDeclaration *typeParamDecl, @@ -592,6 +595,46 @@ ir::Expression *ParserImpl::ParseAssignmentExpression(ir::Expression *lhsExpress return ParseArrowFunctionExpression(lhsExpression, nullptr, nullptr, false); } + case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: { + ValidateAssignmentTarget(flags, lhsExpression); + + lexer_->NextToken(); + ir::Expression *assignmentExpression = ParseExpression(CarryPatternFlags(flags)); + + auto *binaryAssignmentExpression = + AllocNode(lhsExpression, assignmentExpression, tokenType); + + binaryAssignmentExpression->SetRange({lhsExpression->Start(), assignmentExpression->End()}); + return binaryAssignmentExpression; + } + case lexer::TokenType::KEYW_AS: { + if (auto asExpression = ParsePotentialAsExpression(lhsExpression); asExpression != nullptr) { + return ParseAssignmentExpression(asExpression); + } + break; + } + default: { + auto expression = ParseAssignmentBinaryExpression(tokenType, lhsExpression, flags); + if (expression == nullptr) { + expression = ParseAssignmentEqualExpression(tokenType, lhsExpression, flags); + } + + if (expression != nullptr) { + return expression; + } + + break; + } + } + + return lhsExpression; +} + +ir::Expression *ParserImpl::ParseAssignmentBinaryExpression(const lexer::TokenType tokenType, + ir::Expression *lhsExpression, + const ExpressionParseFlags flags) +{ + switch (tokenType) { case lexer::TokenType::KEYW_IN: { if ((flags & ExpressionParseFlags::STOP_AT_IN) != 0) { break; @@ -623,22 +666,20 @@ ir::Expression *ParserImpl::ParseAssignmentExpression(ir::Expression *lhsExpress case lexer::TokenType::PUNCTUATOR_MOD: case lexer::TokenType::KEYW_INSTANCEOF: case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: { - ir::Expression *binaryExpression = ParseBinaryExpression(lhsExpression); - - return ParseAssignmentExpression(binaryExpression); + return ParseAssignmentExpression(ParseBinaryExpression(lhsExpression)); } - case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: { - ValidateAssignmentTarget(flags, lhsExpression); - - lexer_->NextToken(); - ir::Expression *assignmentExpression = ParseExpression(CarryPatternFlags(flags)); + default: + break; + } - auto *binaryAssignmentExpression = - AllocNode(lhsExpression, assignmentExpression, tokenType); + return nullptr; +} - binaryAssignmentExpression->SetRange({lhsExpression->Start(), assignmentExpression->End()}); - return binaryAssignmentExpression; - } +ir::Expression *ParserImpl::ParseAssignmentEqualExpression(const lexer::TokenType tokenType, + ir::Expression *lhsExpression, + const ExpressionParseFlags flags) +{ + switch (tokenType) { case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: @@ -665,18 +706,11 @@ ir::Expression *ParserImpl::ParseAssignmentExpression(ir::Expression *lhsExpress binaryAssignmentExpression->SetRange({lhsExpression->Start(), assignmentExpression->End()}); return binaryAssignmentExpression; } - case lexer::TokenType::KEYW_AS: { - auto asExpression = ParsePotentialAsExpression(lhsExpression); - if (asExpression != nullptr) { - return ParseAssignmentExpression(asExpression); - } - break; - } default: break; } - return lhsExpression; + return nullptr; } ir::TemplateLiteral *ParserImpl::ParseTemplateLiteral() @@ -1092,7 +1126,43 @@ ir::Expression *ParserImpl::ParsePrimaryExpression(ExpressionParseFlags flags) return ParsePrimaryExpressionWithLiterals(flags); } -static size_t GetOperatorPrecedence(const lexer::TokenType operatorType) +static constexpr size_t GetOperatorPrecedenceArithmeticAndComparison(const lexer::TokenType operatorType) +{ + switch (operatorType) { + case lexer::TokenType::PUNCTUATOR_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: + case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: + case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { + constexpr auto PRECEDENCE = 8; + return PRECEDENCE; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: + case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN: + case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: + case lexer::TokenType::KEYW_INSTANCEOF: + case lexer::TokenType::KEYW_IN: { + constexpr auto PRECEDENCE = 9; + return PRECEDENCE; + } + case lexer::TokenType::PUNCTUATOR_PLUS: + case lexer::TokenType::PUNCTUATOR_MINUS: { + constexpr auto PRECEDENCE = 12; + return PRECEDENCE; + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: + case lexer::TokenType::PUNCTUATOR_DIVIDE: + case lexer::TokenType::PUNCTUATOR_MOD: { + constexpr auto PRECEDENCE = 13; + return PRECEDENCE; + } + default: { + UNREACHABLE(); + } + } +} + +static constexpr size_t GetOperatorPrecedence(const lexer::TokenType operatorType) { ASSERT(operatorType == lexer::TokenType::KEYW_AS || lexer::Token::IsBinaryToken(operatorType)); @@ -1121,22 +1191,6 @@ static size_t GetOperatorPrecedence(const lexer::TokenType operatorType) constexpr auto PRECEDENCE = 7; return PRECEDENCE; } - case lexer::TokenType::PUNCTUATOR_EQUAL: - case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: - case lexer::TokenType::PUNCTUATOR_STRICT_EQUAL: - case lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL: { - constexpr auto PRECEDENCE = 8; - return PRECEDENCE; - } - case lexer::TokenType::PUNCTUATOR_LESS_THAN: - case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: - case lexer::TokenType::PUNCTUATOR_GREATER_THAN: - case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: - case lexer::TokenType::KEYW_INSTANCEOF: - case lexer::TokenType::KEYW_IN: { - constexpr auto PRECEDENCE = 9; - return PRECEDENCE; - } case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: { @@ -1147,23 +1201,12 @@ static size_t GetOperatorPrecedence(const lexer::TokenType operatorType) constexpr auto PRECEDENCE = 11; return PRECEDENCE; } - case lexer::TokenType::PUNCTUATOR_PLUS: - case lexer::TokenType::PUNCTUATOR_MINUS: { - constexpr auto PRECEDENCE = 12; - return PRECEDENCE; - } - case lexer::TokenType::PUNCTUATOR_MULTIPLY: - case lexer::TokenType::PUNCTUATOR_DIVIDE: - case lexer::TokenType::PUNCTUATOR_MOD: { - const auto precedence = 13; - return precedence; - } case lexer::TokenType::PUNCTUATOR_EXPONENTIATION: { constexpr auto PRECEDENCE = 14; return PRECEDENCE; } default: { - UNREACHABLE(); + return GetOperatorPrecedenceArithmeticAndComparison(operatorType); } } } @@ -1562,81 +1605,94 @@ ir::MemberExpression *ParserImpl::ParsePropertyAccess(ir::Expression *primaryExp ir::Expression *ParserImpl::ParsePostPrimaryExpression(ir::Expression *primaryExpr, lexer::SourcePosition startLoc, bool ignoreCallExpression, bool *isChainExpression) { - ir::Expression *returnExpression = primaryExpr; - + ir::Expression *returnExpr = primaryExpr; while (true) { switch (lexer_->GetToken().Type()) { - case lexer::TokenType::PUNCTUATOR_QUESTION_DOT: { - *isChainExpression = true; - lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ?. - returnExpression = ParseOptionalChain(returnExpression); - continue; - } - case lexer::TokenType::PUNCTUATOR_PERIOD: { - lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat period - - if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_HASH_MARK) { - returnExpression = ParsePrivatePropertyAccess(returnExpression); - continue; - } - - returnExpression = ParsePropertyAccess(returnExpression); - continue; - } case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { - returnExpression = ParseElementAccess(returnExpression); + returnExpr = ParseElementAccess(returnExpr); continue; } case lexer::TokenType::LITERAL_IDENT: { - auto *asExpression = ParsePotentialAsExpression(returnExpression); - - if (asExpression != nullptr) { + if (auto *asExpression = ParsePotentialAsExpression(returnExpr); asExpression != nullptr) { return asExpression; } break; } case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: case lexer::TokenType::PUNCTUATOR_LESS_THAN: { - if (ParsePotentialGenericFunctionCall(primaryExpr, &returnExpression, startLoc, ignoreCallExpression)) { + if (ParsePotentialGenericFunctionCall(primaryExpr, &returnExpr, startLoc, ignoreCallExpression)) { break; } - continue; } case lexer::TokenType::PUNCTUATOR_BACK_TICK: { - ir::TemplateLiteral *propertyNode = ParseTemplateLiteral(); - lexer::SourcePosition endLoc = propertyNode->End(); - - returnExpression = AllocNode(returnExpression, propertyNode, nullptr); - returnExpression->SetRange({startLoc, endLoc}); + returnExpr = ParsePostPrimaryExpressionBackTick(returnExpr, startLoc); continue; } case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { if (ignoreCallExpression) { break; } - returnExpression = ParseCallExpression(returnExpression, false); + returnExpr = ParseCallExpression(returnExpr, false); continue; } case lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK: { - const bool shouldBreak = ParsePotentialNonNullExpression(&returnExpression, startLoc); - if (shouldBreak) { + if (ParsePotentialNonNullExpression(&returnExpr, startLoc)) { break; } - continue; } default: { - break; + auto tmp = ParsePostPrimaryExpressionDot(returnExpr, lexer_->GetToken().Type(), isChainExpression); + if (tmp != nullptr) { + returnExpr = tmp; + continue; + } } } - break; } + return returnExpr; +} + +ir::Expression *ParserImpl::ParsePostPrimaryExpressionBackTick(ir::Expression *returnExpression, + const lexer::SourcePosition startLoc) +{ + ir::TemplateLiteral *propertyNode = ParseTemplateLiteral(); + lexer::SourcePosition endLoc = propertyNode->End(); + + returnExpression = AllocNode(returnExpression, propertyNode, nullptr); + returnExpression->SetRange({startLoc, endLoc}); return returnExpression; } +ir::Expression *ParserImpl::ParsePostPrimaryExpressionDot(ir::Expression *returnExpression, + const lexer::TokenType tokenType, bool *isChainExpression) +{ + switch (tokenType) { + case lexer::TokenType::PUNCTUATOR_QUESTION_DOT: { + *isChainExpression = true; + lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat ?. + return ParseOptionalChain(returnExpression); + } + case lexer::TokenType::PUNCTUATOR_PERIOD: { + lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat period + + if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_HASH_MARK) { + return ParsePrivatePropertyAccess(returnExpression); + } + + return ParsePropertyAccess(returnExpression); + } + default: { + break; + } + } + + return nullptr; +} + void ParserImpl::ValidateUpdateExpression(ir::Expression *returnExpression, bool isChainExpression) { if ((!returnExpression->IsMemberExpression() && !returnExpression->IsIdentifier() && @@ -1761,6 +1817,19 @@ ir::Expression *ParserImpl::ParsePatternElement(ExpressionParseFlags flags, bool return returnNode; } + ParsePatternElementErrorCheck(flags, allowDefault); + + ir::Expression *rightNode = ParseExpression(); + + auto *assignmentExpression = AllocNode( + ir::AstNodeType::ASSIGNMENT_PATTERN, returnNode, rightNode, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + assignmentExpression->SetRange({returnNode->Start(), rightNode->End()}); + + return assignmentExpression; +} + +void ParserImpl::ParsePatternElementErrorCheck(const ExpressionParseFlags flags, const bool allowDefault) +{ if ((flags & ExpressionParseFlags::IN_REST) != 0) { ThrowSyntaxError("Unexpected token, expected ')'"); } @@ -1778,14 +1847,6 @@ ir::Expression *ParserImpl::ParsePatternElement(ExpressionParseFlags flags, bool if (context_.IsAsync() && lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT) { ThrowSyntaxError("Illegal await-expression in formal parameters of async function"); } - - ir::Expression *rightNode = ParseExpression(); - - auto *assignmentExpression = AllocNode( - ir::AstNodeType::ASSIGNMENT_PATTERN, returnNode, rightNode, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); - assignmentExpression->SetRange({returnNode->Start(), rightNode->End()}); - - return assignmentExpression; } void ParserImpl::CheckPropertyKeyAsyncModifier(ParserStatus *methodStatus) diff --git a/ets2panda/parser/expressionTSParser.cpp b/ets2panda/parser/expressionTSParser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..006a4b5fd0ff07741356108e18eff13f68ebe796 --- /dev/null +++ b/ets2panda/parser/expressionTSParser.cpp @@ -0,0 +1,676 @@ +/** + * Copyright (c) 2024 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. + */ + +#include "TSparser.h" + +#include "parserFlags.h" +#include "util/helpers.h" +#include "varbinder/privateBinding.h" +#include "varbinder/scope.h" +#include "varbinder/tsBinding.h" +#include "lexer/TSLexer.h" +#include "ir/base/spreadElement.h" +#include "ir/base/decorator.h" +#include "ir/base/classElement.h" +#include "ir/base/classDefinition.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/scriptFunction.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/exportDefaultDeclaration.h" +#include "ir/module/exportAllDeclaration.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/module/importDeclaration.h" +#include "ir/expressions/memberExpression.h" +#include "ir/expressions/sequenceExpression.h" +#include "ir/expressions/templateLiteral.h" +#include "ir/expressions/taggedTemplateExpression.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/functionExpression.h" +#include "ir/expressions/arrowFunctionExpression.h" +#include "ir/expressions/yieldExpression.h" +#include "ir/expressions/assignmentExpression.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/objectExpression.h" +#include "ir/expressions/arrayExpression.h" +#include "ir/expressions/literals/bigIntLiteral.h" +#include "ir/expressions/literals/booleanLiteral.h" +#include "ir/expressions/literals/nullLiteral.h" +#include "ir/expressions/literals/numberLiteral.h" +#include "ir/expressions/literals/stringLiteral.h" +#include "ir/statements/emptyStatement.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/ifStatement.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/whileStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/breakStatement.h" +#include "ir/statements/continueStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/returnStatement.h" +#include "ir/statements/debuggerStatement.h" +#include "ir/statements/classDeclaration.h" +#include "ir/statements/labelledStatement.h" +#include "ir/statements/variableDeclarator.h" +#include "ir/statements/functionDeclaration.h" +#include "ir/ts/tsLiteralType.h" +#include "ir/ts/tsMappedType.h" +#include "ir/ts/tsImportType.h" +#include "ir/ts/tsThisType.h" +#include "ir/ts/tsConditionalType.h" +#include "ir/ts/tsTypeOperator.h" +#include "ir/ts/tsInferType.h" +#include "ir/ts/tsTupleType.h" +#include "ir/ts/tsNamedTupleMember.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsIndexedAccessType.h" +#include "ir/ts/tsTypeQuery.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsTypePredicate.h" +#include "ir/ts/tsTypeLiteral.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsUnionType.h" +#include "ir/ts/tsIntersectionType.h" +#include "ir/ts/tsAnyKeyword.h" +#include "ir/ts/tsUndefinedKeyword.h" +#include "ir/ts/tsVoidKeyword.h" +#include "ir/ts/tsNumberKeyword.h" +#include "ir/ts/tsStringKeyword.h" +#include "ir/ts/tsBooleanKeyword.h" +#include "ir/ts/tsBigintKeyword.h" +#include "ir/ts/tsUnknownKeyword.h" +#include "ir/ts/tsNullKeyword.h" +#include "ir/ts/tsNeverKeyword.h" +#include "ir/ts/tsObjectKeyword.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsConstructorType.h" +#include "ir/ts/tsParenthesizedType.h" +#include "ir/ts/tsTypeAssertion.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/ts/tsNonNullExpression.h" +#include "ir/ts/tsEnumDeclaration.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsModuleDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/base/tsSignatureDeclaration.h" +#include "ir/base/tsIndexSignature.h" +#include "ir/base/tsMethodSignature.h" +#include "ir/base/tsPropertySignature.h" +#include "ir/ts/tsParameterProperty.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsExternalModuleReference.h" + +namespace ark::es2panda::parser { +ir::Expression *TSParser::ParsePotentialAsExpression(ir::Expression *expr) +{ + if (Lexer()->GetToken().KeywordType() != lexer::TokenType::KEYW_AS) { + return nullptr; + } + + Lexer()->NextToken(); // eat 'as' + TypeAnnotationParsingOptions options = + TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_CONST; + ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options); + + bool isConst = false; + if (typeAnnotation->IsTSTypeReference() && typeAnnotation->AsTSTypeReference()->TypeName()->IsIdentifier()) { + const util::StringView &refName = typeAnnotation->AsTSTypeReference()->TypeName()->AsIdentifier()->Name(); + if (refName.Is("const")) { + isConst = true; + } + } + + lexer::SourcePosition startLoc = expr->Start(); + auto *asExpr = AllocNode(expr, typeAnnotation, isConst); + asExpr->SetRange({startLoc, Lexer()->GetToken().End()}); + + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_AS) { + return ParsePotentialAsExpression(asExpr); + } + + return asExpr; +} + +ir::AnnotatedExpression *TSParser::ParsePatternElementGetReturnNode(ExpressionParseFlags &flags, bool &isOptional) +{ + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { + ir::AnnotatedExpression *returnNode = ParseArrayExpression(ExpressionParseFlags::MUST_BE_PATTERN); + isOptional = returnNode->AsArrayPattern()->IsOptional(); + return returnNode; + } + case lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD: { + if ((flags & ExpressionParseFlags::IN_REST) != 0) { + ThrowSyntaxError("Unexpected token"); + } + + return ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN); + } + case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { + ir::AnnotatedExpression *returnNode = + ParseObjectExpression(ExpressionParseFlags::MUST_BE_PATTERN | ExpressionParseFlags::OBJECT_PATTERN); + isOptional = returnNode->AsObjectPattern()->IsOptional(); + return returnNode; + } + case lexer::TokenType::LITERAL_IDENT: { + ir::AnnotatedExpression *returnNode = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + returnNode->AsIdentifier()->SetReference(); + + if (returnNode->AsIdentifier()->Decorators().empty()) { + returnNode->SetRange(Lexer()->GetToken().Loc()); + } else { + returnNode->SetRange( + {returnNode->AsIdentifier()->Decorators().front()->Start(), Lexer()->GetToken().End()}); + } + + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { + isOptional = true; + + if ((flags & ExpressionParseFlags::IN_REST) != 0) { + ThrowSyntaxError("A rest parameter cannot be optional"); + } + + returnNode->AsIdentifier()->SetOptional(true); + Lexer()->NextToken(); + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + returnNode->SetTsTypeAnnotation(ParseTypeAnnotation(&options)); + } + return returnNode; + } + default: { + ThrowSyntaxError("Unexpected token, expected an identifier."); + } + } +} +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *TSParser::ParsePatternElement(ExpressionParseFlags flags, bool allowDefault) +{ + bool isOptional = false; + ir::AnnotatedExpression *returnNode = ParsePatternElementGetReturnNode(flags, isOptional); + + if ((returnNode->IsObjectPattern() || returnNode->IsArrayPattern()) && !InAmbientContext() && + ((GetContext().Status() & ParserStatus::FUNCTION) != 0) && isOptional) { + ThrowSyntaxError("A binding pattern parameter cannot be optional in an implementation signature."); + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + return returnNode; + } + + if ((flags & ExpressionParseFlags::IN_REST) != 0) { + ThrowSyntaxError("A rest parameter cannot have an initializer."); + } + + if (!allowDefault) { + ThrowSyntaxError("Invalid destructuring assignment target"); + } + + if (isOptional) { + ThrowSyntaxError("Parameter cannot have question mark and initializer"); + } + + Lexer()->NextToken(); + + if (((GetContext().Status() & ParserStatus::GENERATOR_FUNCTION) != 0) && + Lexer()->GetToken().Type() == lexer::TokenType::KEYW_YIELD) { + ThrowSyntaxError("Yield is not allowed in generator parameters"); + } + + ir::Expression *rightNode = ParseExpression(); + + auto *assignmentExpression = AllocNode( + ir::AstNodeType::ASSIGNMENT_PATTERN, returnNode, rightNode, lexer::TokenType::PUNCTUATOR_SUBSTITUTION); + assignmentExpression->SetRange({returnNode->Start(), rightNode->End()}); + + return assignmentExpression; +} + +ir::TSParameterProperty *TSParser::CreateParameterProperty(ir::Expression *parameter, ir::ModifierFlags modifiers) +{ + auto accessibilityOption = ir::AccessibilityOption::NO_OPTS; + bool readonly = false; + bool isStatic = false; + bool isExport = false; + + if ((modifiers & ir::ModifierFlags::PRIVATE) != 0) { + accessibilityOption = ir::AccessibilityOption::PRIVATE; + } else if ((modifiers & ir::ModifierFlags::PUBLIC) != 0) { + accessibilityOption = ir::AccessibilityOption::PUBLIC; + } else if ((modifiers & ir::ModifierFlags::PROTECTED) != 0) { + accessibilityOption = ir::AccessibilityOption::PROTECTED; + } + + if ((modifiers & ir::ModifierFlags::READONLY) != 0) { + readonly = true; + } + + if ((modifiers & ir::ModifierFlags::STATIC) != 0) { + isStatic = true; + } + + // NOTE(Csaba Repasi): Handle export property of TSParameterProperty + + return AllocNode(accessibilityOption, parameter, readonly, isStatic, isExport); +} + +ir::Expression *TSParser::ParseFunctionParameter() +{ + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_THIS) { + Lexer()->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT); + } + + lexer::SourcePosition parameterStart = Lexer()->GetToken().Start(); + ir::ModifierFlags modifiers = ParseModifiers(); + // NOTE(Csaba Repasi): throw error if using strick mode reserved keyword here + if (((GetContext().Status() & ParserStatus::CONSTRUCTOR_FUNCTION) == 0) && modifiers != ir::ModifierFlags::NONE) { + ThrowSyntaxError("A parameter property is only allowed in a constructor implementation.", parameterStart); + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { + CheckRestrictedBinding(); + } + + ir::Expression *functionParameter = ParsePatternElement(ExpressionParseFlags::NO_OPTS, true); + + if (modifiers != ir::ModifierFlags::NONE && functionParameter->IsRestElement()) { + ThrowSyntaxError("A parameter property cannot be declared using a rest parameter.", parameterStart); + } + + if (modifiers != ir::ModifierFlags::NONE && + (functionParameter->IsArrayPattern() || functionParameter->IsObjectPattern() || + (functionParameter->IsAssignmentPattern() && + (functionParameter->AsAssignmentPattern()->Left()->IsArrayPattern() || + functionParameter->AsAssignmentPattern()->Left()->IsObjectPattern())))) { + ThrowSyntaxError("A parameter property may not be declared using a binding pattern.", parameterStart); + } + + if (modifiers != ir::ModifierFlags::NONE) { + functionParameter = CreateParameterProperty(functionParameter, modifiers); + functionParameter->SetRange({parameterStart, functionParameter->AsTSParameterProperty()->Parameter()->End()}); + } + + return functionParameter; +} + +ir::Expression *TSParser::ParseModuleReference() +{ + ir::Expression *result = nullptr; + + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_REQUIRE && + Lexer()->Lookahead() == lexer::LEX_CHAR_LEFT_PAREN) { + lexer::SourcePosition start = Lexer()->GetToken().Start(); + Lexer()->NextToken(); // eat 'require' + Lexer()->NextToken(); // eat '(' + + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { + ThrowSyntaxError("String literal expected."); + } + + result = AllocNode(Lexer()->GetToken().String()); + result->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + ThrowSyntaxError("')' expected."); + } + + result = AllocNode(result); + result->SetRange({start, Lexer()->GetToken().End()}); + Lexer()->NextToken(); // eat ')' + } else { + result = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + result->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD) { + result = ParseQualifiedReference(result); + } + } + + return result; +} + +ir::TSTypeReference *TSParser::ParseConstExpression() +{ + auto *identRef = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + identRef->SetReference(); + identRef->SetRange(Lexer()->GetToken().Loc()); + + auto *typeReference = AllocNode(identRef, nullptr); + typeReference->SetRange(Lexer()->GetToken().Loc()); + + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA && + Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON && + Lexer()->GetToken().Type() != lexer::TokenType::EOS && + Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET && + ((Lexer()->GetToken().Flags() & lexer::TokenFlags::NEW_LINE) == 0)) { + ThrowSyntaxError("Unexpected token."); + } + + return typeReference; +} + +bool TSParser::ParsePotentialNonNullExpression(ir::Expression **returnExpression, lexer::SourcePosition startLoc) +{ + if (returnExpression == nullptr || Lexer()->GetToken().NewLine()) { + return true; + } + + *returnExpression = AllocNode(*returnExpression); + (*returnExpression)->SetRange({startLoc, Lexer()->GetToken().End()}); + Lexer()->NextToken(); + return false; +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::ObjectExpression *TSParser::ParseObjectExpression(ExpressionParseFlags flags) +{ + ir::ObjectExpression *objExpression = ParserImpl::ParseObjectExpression(flags); + ParsePotentialOptionalFunctionParameter(objExpression); + return objExpression; +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::ArrayExpression *TSParser::ParseArrayExpression(ExpressionParseFlags flags) +{ + ir::ArrayExpression *arrayExpression = ParserImpl::ParseArrayExpression(flags); + ParsePotentialOptionalFunctionParameter(arrayExpression); + return arrayExpression; +} +class TSParser::ParsePotentialArrowExpressionHelper { + friend ir::ArrowFunctionExpression *TSParser::ParsePotentialArrowExpression(ir::Expression **returnExpression, + const lexer::SourcePosition &startLoc); + +private: + static ir::ArrowFunctionExpression *CreateCallExpression(TSParser *parser, lexer::Lexer *lexer, + ir::Expression **returnExpression, + ir::TSTypeParameterDeclaration *typeParamDecl, + const lexer::SourcePosition &startLoc) + { + ir::CallExpression *callExpression = parser->ParseCallExpression(*returnExpression, false); + + ir::TypeNode *returnTypeAnnotation = nullptr; + if (lexer->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + lexer->NextToken(); // eat ':' + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + returnTypeAnnotation = parser->ParseTypeAnnotation(&options); + } + + if (lexer->GetToken().Type() == lexer::TokenType::PUNCTUATOR_ARROW) { + ir::ArrowFunctionExpression *arrowFuncExpr = + parser->ParseArrowFunctionExpression(callExpression, typeParamDecl, returnTypeAnnotation, true); + arrowFuncExpr->SetStart(startLoc); + + return arrowFuncExpr; + } + + if (returnTypeAnnotation != nullptr || typeParamDecl != nullptr) { + parser->ThrowSyntaxError("'=>' expected"); + } + + *returnExpression = callExpression; + return nullptr; + } +}; + +ir::ArrowFunctionExpression *TSParser::ParsePotentialArrowExpression(ir::Expression **returnExpression, + const lexer::SourcePosition &startLoc) +{ + ir::TSTypeParameterDeclaration *typeParamDecl = nullptr; + + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::KEYW_FUNCTION: { + *returnExpression = ParseFunctionExpression(ParserStatus::ASYNC_FUNCTION); + (*returnExpression)->SetStart(startLoc); + break; + } + case lexer::TokenType::LITERAL_IDENT: { + ir::Expression *identRef = ParsePrimaryExpression(); + ASSERT(identRef->IsIdentifier()); + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { + ThrowSyntaxError("Unexpected token, expected '=>'"); + } + + ir::ArrowFunctionExpression *arrowFuncExpr = ParseArrowFunctionExpression(identRef, nullptr, nullptr, true); + arrowFuncExpr->SetStart(startLoc); + + return arrowFuncExpr; + } + case lexer::TokenType::PUNCTUATOR_ARROW: { + ir::ArrowFunctionExpression *arrowFuncExpr = + ParseArrowFunctionExpression(*returnExpression, nullptr, nullptr, true); + arrowFuncExpr->SetStart(startLoc); + return arrowFuncExpr; + } + case lexer::TokenType::PUNCTUATOR_LESS_THAN: { + const auto savedPos = Lexer()->Save(); + + auto options = TypeAnnotationParsingOptions::NO_OPTS; + typeParamDecl = ParseTypeParameterDeclaration(&options); + if (typeParamDecl == nullptr) { + Lexer()->Rewind(savedPos); + return nullptr; + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { + ThrowSyntaxError("'(' expected"); + } + + [[fallthrough]]; + } + case lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS: { + return ParsePotentialArrowExpressionHelper::CreateCallExpression(this, Lexer(), returnExpression, + typeParamDecl, startLoc); + } + default: { + break; + } + } + + return nullptr; +} + +ir::AnnotatedExpression *TSParser::ParseVariableDeclaratorKey(VariableParsingFlags flags) +{ + ir::AnnotatedExpression *init = ParserImpl::ParseVariableDeclaratorKey(flags); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + init->SetTsTypeAnnotation(ParseTypeAnnotation(&options)); + } + + return init; +} + +void TSParser::ParseOptionalFunctionParameter(ir::AnnotatedExpression *returnNode, bool isRest) +{ + bool isOptional = false; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { + if (isRest) { + ThrowSyntaxError("A rest parameter cannot be optional"); + } + + switch (returnNode->Type()) { + case ir::AstNodeType::IDENTIFIER: { + returnNode->AsIdentifier()->SetOptional(true); + break; + } + case ir::AstNodeType::OBJECT_PATTERN: + case ir::AstNodeType::ARRAY_PATTERN: { + if (!InAmbientContext() && ((GetContext().Status() & ParserStatus::FUNCTION) != 0)) { + ThrowSyntaxError("A binding pattern parameter cannot be optional in an implementation signature."); + } + + if (returnNode->IsObjectPattern()) { + returnNode->AsObjectPattern()->SetOptional(true); + break; + } + + returnNode->AsArrayPattern()->SetOptional(true); + break; + } + case ir::AstNodeType::REST_ELEMENT: { + returnNode->AsRestElement()->SetOptional(true); + break; + } + default: { + UNREACHABLE(); + } + } + + isOptional = true; + Lexer()->NextToken(); // eat '?' + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + returnNode->SetTsTypeAnnotation(ParseTypeAnnotation(&options)); + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + return; + } + + if (isRest) { + ThrowSyntaxError("A rest parameter cannot have an initializer"); + } + + if (returnNode->IsIdentifier() && isOptional) { + ThrowSyntaxError("Parameter cannot have question mark and initializer"); + } +} + +void TSParser::ValidateArrowFunctionRestParameter(ir::SpreadElement *restElement) +{ + ParseOptionalFunctionParameter(restElement, true); + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + ThrowSyntaxError("')' expected"); + } +} + +ir::Expression *TSParser::ParseArrowFunctionRestParameter(lexer::SourcePosition start) +{ + ir::SpreadElement *restElement = ParseSpreadElement(ExpressionParseFlags::MUST_BE_PATTERN); + + restElement->SetGrouped(); + restElement->SetStart(start); + + ValidateArrowFunctionRestParameter(restElement); + + Lexer()->NextToken(); + + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *returnTypeAnnotation = nullptr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + returnTypeAnnotation = ParseTypeAnnotation(&options); + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { + ThrowSyntaxError("Unexpected token"); + } + + return ParseArrowFunctionExpression(restElement, nullptr, returnTypeAnnotation, false); +} + +ir::Expression *TSParser::ParseArrowFunctionNoParameter(lexer::SourcePosition start) +{ + Lexer()->NextToken(); + + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *returnTypeAnnotation = nullptr; + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + Lexer()->NextToken(); // eat ':' + returnTypeAnnotation = ParseTypeAnnotation(&options); + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { + ThrowSyntaxError("Unexpected token"); + } + + auto *arrowExpr = ParseArrowFunctionExpression(nullptr, nullptr, returnTypeAnnotation, false); + arrowExpr->SetStart(start); + arrowExpr->AsArrowFunctionExpression()->Function()->SetStart(start); + + return arrowExpr; +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::Expression *TSParser::ParseCoverParenthesizedExpressionAndArrowParameterList( + [[maybe_unused]] ExpressionParseFlags flags) +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); + lexer::SourcePosition start = Lexer()->GetToken().Start(); + Lexer()->NextToken(); + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PERIOD_PERIOD_PERIOD) { + return ParseArrowFunctionRestParameter(start); + } + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + return ParseArrowFunctionNoParameter(start); + } + + ir::Expression *expr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::ACCEPT_REST | + ExpressionParseFlags::POTENTIALLY_IN_PATTERN); + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + ThrowSyntaxError("Unexpected token, expected ')'"); + } + + expr->SetGrouped(); + expr->SetRange({start, Lexer()->GetToken().End()}); + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { + auto savedPos = Lexer()->Save(); + Lexer()->NextToken(); // eat ':' + options = TypeAnnotationParsingOptions::NO_OPTS; + ir::TypeNode *returnTypeAnnotation = ParseTypeAnnotation(&options); + + if (returnTypeAnnotation == nullptr) { + Lexer()->Rewind(savedPos); + return expr; + } + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_ARROW) { + Lexer()->Rewind(savedPos); + return expr; + } + + return ParseArrowFunctionExpression(expr, nullptr, returnTypeAnnotation, false); + } + + return expr; +} + +} // namespace ark::es2panda::parser \ No newline at end of file diff --git a/ets2panda/parser/forwardDeclForParserImpl.h b/ets2panda/parser/forwardDeclForParserImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..05611714bc6752f017a6cb55be005b1834e91a23 --- /dev/null +++ b/ets2panda/parser/forwardDeclForParserImpl.h @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2021-2024 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. + */ + +// original_header.h +#ifndef FORWARD_DECL_FOR_PARSERIMPL_H +#define FORWARD_DECL_FOR_PARSERIMPL_H + +#include "ir/base/scriptFunctionSignature.h" +#include "parser/context/parserContext.h" +#include "varbinder/scope.h" + +namespace ark::es2panda::lexer { +enum class TokenFlags : uint32_t; +class LexerPosition; +class Token; +class Lexer; +} // namespace ark::es2panda::lexer + +namespace ark::es2panda::ir { +class ArrowFunctionExpression; +class AstNode; +class BlockStatement; +class BreakStatement; +class CallExpression; +class ClassDeclaration; +class ClassDefinition; +class ContinueStatement; +class DoWhileStatement; +class ExportAllDeclaration; +class ExportDefaultDeclaration; +class ExportNamedDeclaration; +class ExportNamedDeclaration; +class Expression; +class FunctionDeclaration; +class FunctionExpression; +class Identifier; +class IfStatement; +class ImportSource; +class ImportDeclaration; +class LabelledStatement; +class NewExpression; +class ObjectExpression; +class ReturnStatement; +class ScriptFunction; +class SequenceExpression; +class SpreadElement; +class Statement; +class StringLiteral; +class SwitchCaseStatement; +class SwitchStatement; +class TemplateLiteral; +class ThrowStatement; +class TryStatement; +class VariableDeclaration; +class WhileStatement; +class WithStatement; +class MemberExpression; +class MethodDefinition; +class Property; +class YieldExpression; +class MetaProperty; +class EmptyStatement; +class DebuggerStatement; +class CatchClause; +class VariableDeclarator; +class ClassElement; + +enum class PropertyKind; +enum class MethodDefinitionKind; +enum class ModifierFlags : uint32_t; +enum class Primitives; +enum class ClassDefinitionModifiers : uint32_t; +enum class CatchClauseType; +enum class VariableDeclaratorFlag; +} // namespace ark::es2panda::ir + +namespace ark::es2panda::parser { + +class ETSParser; + +using FunctionSignature = std::tuple; + +// NOLINTBEGIN(modernize-avoid-c-arrays) +inline constexpr char const ARRAY_FORMAT_NODE = '['; +inline constexpr char const EXPRESSION_FORMAT_NODE = 'E'; +inline constexpr char const STATEMENT_FORMAT_NODE = 'S'; +// NOLINTEND(modernize-avoid-c-arrays) + +class ClassElementDescriptor { +public: + explicit ClassElementDescriptor(ArenaAllocator *allocator) : decorators(allocator->Adapter()) {} + + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) + ArenaVector decorators; + ir::MethodDefinitionKind methodKind {}; + ParserStatus newStatus {}; + ir::ModifierFlags modifiers {}; + lexer::SourcePosition methodStart {}; + lexer::SourcePosition propStart {}; + bool isPrivateIdent {}; + bool hasSuperClass {}; + bool isGenerator {}; + bool invalidComputedProperty {}; + bool isComputed {}; + bool isIndexSignature {}; + bool classMethod {}; + bool classField {}; + varbinder::LocalScope *staticFieldScope {}; + varbinder::LocalScope *staticMethodScope {}; + varbinder::LocalScope *instanceFieldScope {}; + varbinder::LocalScope *instanceMethodScope {}; + // NOLINTEND(misc-non-private-member-variables-in-classes) +}; + +class ArrowFunctionDescriptor { +public: + explicit ArrowFunctionDescriptor(ArenaVector &&p, lexer::SourcePosition sl, ParserStatus ns) + : params(p), startLoc(sl), newStatus(ns) + { + } + + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) + ArenaVector params; + lexer::SourcePosition startLoc; + ParserStatus newStatus; + // NOLINTEND(misc-non-private-member-variables-in-classes) +}; + +class ArrowFunctionContext; +} // namespace ark::es2panda::parser +#endif diff --git a/ets2panda/parser/parserImpl.cpp b/ets2panda/parser/parserImpl.cpp index 3515bf031d7bb976d4f175dc8b98aa775a3ecdb3..348a1a525647b25b32c0d9440c0aad0f12ef4cfb 100644 --- a/ets2panda/parser/parserImpl.cpp +++ b/ets2panda/parser/parserImpl.cpp @@ -14,6 +14,7 @@ */ #include "parserImpl.h" +#include "parserStatusContext.h" #include "varbinder/privateBinding.h" #include "ir/astNode.h" @@ -383,11 +384,8 @@ ir::Expression *ParserImpl::ParseClassKey(ClassElementDescriptor *desc) } case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { ThrowIfPrivateIdent(desc, "Unexpected character in private identifier"); - auto [isComputed, invalidComputedProperty, isIndexSignature] = + std::tie(desc->isComputed, desc->invalidComputedProperty, desc->isIndexSignature) = ParseComputedClassFieldOrIndexSignature(&propName); - desc->isComputed = isComputed; - desc->invalidComputedProperty = invalidComputedProperty; - desc->isIndexSignature = isIndexSignature; break; } default: { diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index 34fb041a9925a3776d57cea340d555addf3b4fc9..ad57b0bb360bf482690edfd8ee9d49dbc5ad20ee 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -17,6 +17,7 @@ #define ES2PANDA_PARSER_CORE_PARSER_IMPL_H #include "es2panda.h" +#include "forwardDeclForParserImpl.h" #include "ir/base/scriptFunctionSignature.h" #include "lexer/token/sourceLocation.h" #include "lexer/token/tokenType.h" @@ -26,123 +27,7 @@ #include "parser/program/program.h" #include "util/helpers.h" -namespace ark::es2panda::lexer { -enum class TokenFlags : uint32_t; -class LexerPosition; -class Token; -class Lexer; -} // namespace ark::es2panda::lexer - -namespace ark::es2panda::ir { -class ArrowFunctionExpression; -class AstNode; -class BlockStatement; -class BreakStatement; -class CallExpression; -class ClassDeclaration; -class ClassDefinition; -class ContinueStatement; -class DoWhileStatement; -class ExportAllDeclaration; -class ExportDefaultDeclaration; -class ExportNamedDeclaration; -class ExportNamedDeclaration; -class Expression; -class FunctionDeclaration; -class FunctionExpression; -class Identifier; -class IfStatement; -class ImportSource; -class ImportDeclaration; -class LabelledStatement; -class NewExpression; -class ObjectExpression; -class ReturnStatement; -class ScriptFunction; -class SequenceExpression; -class SpreadElement; -class Statement; -class StringLiteral; -class SwitchCaseStatement; -class SwitchStatement; -class TemplateLiteral; -class ThrowStatement; -class TryStatement; -class VariableDeclaration; -class WhileStatement; -class WithStatement; -class MemberExpression; -class MethodDefinition; -class Property; -class YieldExpression; -class MetaProperty; -class EmptyStatement; -class DebuggerStatement; -class CatchClause; -class VariableDeclarator; -class ClassElement; - -enum class PropertyKind; -enum class MethodDefinitionKind; -enum class ModifierFlags : uint32_t; -enum class Primitives; -enum class ClassDefinitionModifiers : uint32_t; -enum class CatchClauseType; -enum class VariableDeclaratorFlag; -} // namespace ark::es2panda::ir - namespace ark::es2panda::parser { - -class ETSParser; - -using FunctionSignature = std::tuple; - -// NOLINTBEGIN(modernize-avoid-c-arrays) -inline constexpr char const ARRAY_FORMAT_NODE = '['; -inline constexpr char const EXPRESSION_FORMAT_NODE = 'E'; -inline constexpr char const STATEMENT_FORMAT_NODE = 'S'; -// NOLINTEND(modernize-avoid-c-arrays) - -class ClassElementDescriptor { -public: - explicit ClassElementDescriptor(ArenaAllocator *allocator) : decorators(allocator->Adapter()) {} - - // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - ArenaVector decorators; - ir::MethodDefinitionKind methodKind {}; - ParserStatus newStatus {}; - ir::ModifierFlags modifiers {}; - lexer::SourcePosition methodStart {}; - lexer::SourcePosition propStart {}; - bool isPrivateIdent {}; - bool hasSuperClass {}; - bool isGenerator {}; - bool invalidComputedProperty {}; - bool isComputed {}; - bool isIndexSignature {}; - bool classMethod {}; - bool classField {}; - varbinder::LocalScope *staticFieldScope {}; - varbinder::LocalScope *staticMethodScope {}; - varbinder::LocalScope *instanceFieldScope {}; - varbinder::LocalScope *instanceMethodScope {}; - // NOLINTEND(misc-non-private-member-variables-in-classes) -}; - -class ArrowFunctionDescriptor { -public: - explicit ArrowFunctionDescriptor(ArenaVector &&p, lexer::SourcePosition sl, ParserStatus ns) - : params(p), startLoc(sl), newStatus(ns) - { - } - - // NOLINTBEGIN(misc-non-private-member-variables-in-classes) - ArenaVector params; - lexer::SourcePosition startLoc; - ParserStatus newStatus; - // NOLINTEND(misc-non-private-member-variables-in-classes) -}; - using ENUMBITOPS_OPERATORS; enum class TypeAnnotationParsingOptions : uint32_t { @@ -165,8 +50,6 @@ enum class TypeAnnotationParsingOptions : uint32_t { DISALLOW_UNION = 1U << 15U, }; -class ArrowFunctionContext; - class ParserImpl { public: explicit ParserImpl(Program *program, const CompilerOptions &options, ParserStatus status = ParserStatus::NO_OPTS); @@ -207,9 +90,6 @@ protected: void ValidatePrivateIdentifier(); static ir::VariableDeclaratorFlag GetFlag(VariableParsingFlags flags); - ir::MethodDefinition *CheckClassMethodOverload(ir::Statement *property, ir::MethodDefinition **ctor, - lexer::SourcePosition errorInfo, ir::MethodDefinition *lastOverload, - bool implExists, bool isAbstract = false); void ThrowAllocationError(std::string_view message) const; @@ -251,12 +131,15 @@ protected: bool ParseDirective(ArenaVector *statements); void ParseDirectivePrologue(ArenaVector *statements); ir::BlockStatement *ParseFunctionBody(); + std::tuple ParseIsForInOf( + ir::Expression *leftNode, ExpressionParseFlags exprFlags); std::tuple ParseForInOf( ir::Expression *leftNode, ExpressionParseFlags exprFlags, bool isAwait); std::tuple ParseForInOf(ir::AstNode *initNode, ExpressionParseFlags exprFlags, bool isAwait); std::tuple ParseForUpdate(bool isAwait); + std::tuple ParseForLoopInitializer(); ir::SwitchCaseStatement *ParseSwitchCaseStatement(bool *seenDefault); virtual ir::Expression *ParseCatchParam(); ir::CatchClause *ParseCatchClause(); @@ -316,6 +199,10 @@ protected: ir::TypeNode *returnTypeAnnotation); ir::Expression *ParseAssignmentExpression(ir::Expression *lhsExpression, ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); + ir::Expression *ParseAssignmentBinaryExpression(lexer::TokenType tokenType, ir::Expression *lhsExpression, + ExpressionParseFlags flags); + ir::Expression *ParseAssignmentEqualExpression(lexer::TokenType tokenType, ir::Expression *lhsExpression, + ExpressionParseFlags flags); ir::SequenceExpression *ParseSequenceExpression(ir::Expression *startExpr, bool acceptRest = false); ir::FunctionExpression *ParseFunctionExpression(ParserStatus newStatus = ParserStatus::NO_OPTS); ir::ArrowFunctionExpression *ParseArrowFunctionExpression(ir::Expression *expr, @@ -422,6 +309,7 @@ protected: // NOLINTNEXTLINE(google-default-arguments) virtual ir::Expression *ParsePatternElement(ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS, bool allowDefault = true); + void ParsePatternElementErrorCheck(ExpressionParseFlags flags, bool allowDefault); virtual bool ParsePotentialNonNullExpression(ir::Expression **returnExpression, lexer::SourcePosition startLoc); virtual ir::AstNode *ParseImportSpecifiers(ArenaVector *specifiers); virtual ir::Statement *ParseImportDeclaration(StatementParsingFlags flags); @@ -432,6 +320,8 @@ protected: virtual ir::ObjectExpression *ParseObjectExpression(ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); // NOLINTNEXTLINE(google-default-arguments) virtual ir::ArrayExpression *ParseArrayExpression(ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); + void ParseArrayExpressionErrorCheck(ir::ArrayExpression *arrayExpressionNode, ExpressionParseFlags flags, + bool inPattern); virtual ir::ArrowFunctionExpression *ParsePotentialArrowExpression(ir::Expression **returnExpression, const lexer::SourcePosition &startLoc); virtual bool ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, ir::Expression **returnExpression, @@ -497,8 +387,13 @@ protected: virtual ir::Expression *ParsePrimaryExpression(ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); virtual ir::Expression *ParsePostPrimaryExpression(ir::Expression *primaryExpr, lexer::SourcePosition startLoc, bool ignoreCallExpression, bool *isChainExpression); + ir::Expression *ParsePostPrimaryExpressionBackTick(ir::Expression *returnExpression, + lexer::SourcePosition startLoc); + ir::Expression *ParsePostPrimaryExpressionDot(ir::Expression *returnExpression, lexer::TokenType tokenType, + bool *isChainExpression); virtual ir::ClassElement *ParseClassStaticBlock(); virtual ParserStatus ValidateArrowParameter(ir::Expression *expr, bool *seenOptional); + void ValidateArrowParameterAssignment(ir::AssignmentExpression *expr); virtual ArrowFunctionDescriptor ConvertToArrowParameter(ir::Expression *expr, bool isAsync); virtual ir::Expression *ParseNewExpression(); @@ -610,158 +505,6 @@ private: lexer::Lexer *lexer_ {}; const CompilerOptions &options_; }; - -template -class SavedStatusContext { -public: - explicit SavedStatusContext(ParserContext *ctx) - // NOLINTNEXTLINE(readability-magic-numbers) - : ctx_(ctx), savedStatus_(static_cast(ctx->Status() & STATUS)) - { - // NOLINTNEXTLINE(readability-magic-numbers) - ctx->Status() |= STATUS; - } - - NO_COPY_SEMANTIC(SavedStatusContext); - NO_MOVE_SEMANTIC(SavedStatusContext); - - ~SavedStatusContext() - { - if (savedStatus_ == ParserStatus::NO_OPTS) { - ctx_->Status() &= ~savedStatus_; - } - } - -private: - ParserContext *ctx_; - ParserStatus savedStatus_; -}; - -class SwitchContext : public SavedStatusContext { -public: - explicit SwitchContext(ParserContext *ctx) : SavedStatusContext(ctx) {} - NO_COPY_SEMANTIC(SwitchContext); - NO_MOVE_SEMANTIC(SwitchContext); - ~SwitchContext() = default; -}; - -class IterationContext : public SavedStatusContext { -public: - explicit IterationContext(ParserContext *ctx) : SavedStatusContext(ctx) {} - - NO_COPY_SEMANTIC(IterationContext); - NO_MOVE_SEMANTIC(IterationContext); - ~IterationContext() = default; -}; - -class FunctionParameterContext : public SavedStatusContext { -public: - explicit FunctionParameterContext(ParserContext *ctx) : SavedStatusContext(ctx) {} - - NO_COPY_SEMANTIC(FunctionParameterContext); - NO_MOVE_SEMANTIC(FunctionParameterContext); - ~FunctionParameterContext() = default; -}; - -class SavedParserContext { -public: - template - explicit SavedParserContext(ParserImpl *parser, Args &&...args) : parser_(parser), prev_(parser->context_) - { - parser_->context_ = ParserContext(&prev_, std::forward(args)...); - } - - NO_COPY_SEMANTIC(SavedParserContext); - DEFAULT_MOVE_SEMANTIC(SavedParserContext); - - ~SavedParserContext() - { - parser_->context_ = prev_; - } - -private: - ParserImpl *parser_; - ParserContext prev_; -}; - -class SavedClassPrivateContext { -public: - explicit SavedClassPrivateContext(ParserImpl *parser) : parser_(parser), prev_(parser->classPrivateContext_) - { - parser_->classPrivateContext_ = ClassPrivateContext(&prev_); - } - - NO_COPY_SEMANTIC(SavedClassPrivateContext); - DEFAULT_MOVE_SEMANTIC(SavedClassPrivateContext); - - ~SavedClassPrivateContext() - { - parser_->classPrivateContext_ = prev_; - } - -private: - ParserImpl *parser_; - ClassPrivateContext prev_; -}; - -class FunctionContext : public SavedParserContext { -public: - explicit FunctionContext(ParserImpl *parser, ParserStatus newStatus) : SavedParserContext(parser, newStatus) - { - if ((newStatus & ParserStatus::GENERATOR_FUNCTION) != 0) { - flags_ |= ir::ScriptFunctionFlags::GENERATOR; - } - - if ((newStatus & ParserStatus::ASYNC_FUNCTION) != 0) { - flags_ |= ir::ScriptFunctionFlags::ASYNC; - } - - if ((newStatus & ParserStatus::CONSTRUCTOR_FUNCTION) != 0) { - flags_ |= ir::ScriptFunctionFlags::CONSTRUCTOR; - } - } - - ir::ScriptFunctionFlags Flags() const - { - return flags_; - } - - void AddFlag(ir::ScriptFunctionFlags flags) - { - flags_ |= flags; - } - - NO_COPY_SEMANTIC(FunctionContext); - NO_MOVE_SEMANTIC(FunctionContext); - ~FunctionContext() = default; - -private: - ir::ScriptFunctionFlags flags_ {ir::ScriptFunctionFlags::NONE}; -}; - -class ArrowFunctionContext : public FunctionContext { -public: - explicit ArrowFunctionContext(ParserImpl *parser, bool isAsync) - : FunctionContext(parser, InitialFlags(parser->context_.Status())) - { - if (isAsync) { - AddFlag(ir::ScriptFunctionFlags::ASYNC); - } - - AddFlag(ir::ScriptFunctionFlags::ARROW); - } - - NO_COPY_SEMANTIC(ArrowFunctionContext); - NO_MOVE_SEMANTIC(ArrowFunctionContext); - ~ArrowFunctionContext() = default; - -private: - static ParserStatus InitialFlags(ParserStatus currentStatus) - { - return ParserStatus::FUNCTION | ParserStatus::ARROW_FUNCTION | - static_cast(currentStatus & (ParserStatus::ALLOW_SUPER | ParserStatus::ALLOW_SUPER_CALL)); - } -}; } // namespace ark::es2panda::parser template <> diff --git a/ets2panda/parser/parserStatusContext.h b/ets2panda/parser/parserStatusContext.h new file mode 100644 index 0000000000000000000000000000000000000000..602fa1249bde33c0d4a17567d7ca98305dbce926 --- /dev/null +++ b/ets2panda/parser/parserStatusContext.h @@ -0,0 +1,175 @@ +/** + * Copyright (c) 2021-2024 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. + */ + +#ifndef PARSER_STATUS_CONTEXT_H +#define PARSER_STATUS_CONTEXT_H + +#include "parserImpl.h" + +namespace ark::es2panda::parser { + +template +class SavedStatusContext { +public: + explicit SavedStatusContext(ParserContext *ctx) + // NOLINTNEXTLINE(readability-magic-numbers) + : ctx_(ctx), savedStatus_(static_cast(ctx->Status() & STATUS)) + { + // NOLINTNEXTLINE(readability-magic-numbers) + ctx->Status() |= STATUS; + } + + NO_COPY_SEMANTIC(SavedStatusContext); + NO_MOVE_SEMANTIC(SavedStatusContext); + + ~SavedStatusContext() + { + if (savedStatus_ == ParserStatus::NO_OPTS) { + ctx_->Status() &= ~savedStatus_; + } + } + +private: + ParserContext *ctx_; + ParserStatus savedStatus_; +}; + +class SwitchContext : public SavedStatusContext { +public: + explicit SwitchContext(ParserContext *ctx) : SavedStatusContext(ctx) {} + NO_COPY_SEMANTIC(SwitchContext); + NO_MOVE_SEMANTIC(SwitchContext); + ~SwitchContext() = default; +}; + +class IterationContext : public SavedStatusContext { +public: + explicit IterationContext(ParserContext *ctx) : SavedStatusContext(ctx) {} + + NO_COPY_SEMANTIC(IterationContext); + NO_MOVE_SEMANTIC(IterationContext); + ~IterationContext() = default; +}; + +class FunctionParameterContext : public SavedStatusContext { +public: + explicit FunctionParameterContext(ParserContext *ctx) : SavedStatusContext(ctx) {} + + NO_COPY_SEMANTIC(FunctionParameterContext); + NO_MOVE_SEMANTIC(FunctionParameterContext); + ~FunctionParameterContext() = default; +}; + +class SavedParserContext { +public: + template + explicit SavedParserContext(ParserImpl *parser, Args &&...args) : parser_(parser), prev_(parser->context_) + { + parser_->context_ = ParserContext(&prev_, std::forward(args)...); + } + + NO_COPY_SEMANTIC(SavedParserContext); + DEFAULT_MOVE_SEMANTIC(SavedParserContext); + + ~SavedParserContext() + { + parser_->context_ = prev_; + } + +private: + ParserImpl *parser_; + ParserContext prev_; +}; + +class SavedClassPrivateContext { +public: + explicit SavedClassPrivateContext(ParserImpl *parser) : parser_(parser), prev_(parser->classPrivateContext_) + { + parser_->classPrivateContext_ = ClassPrivateContext(&prev_); + } + + NO_COPY_SEMANTIC(SavedClassPrivateContext); + DEFAULT_MOVE_SEMANTIC(SavedClassPrivateContext); + + ~SavedClassPrivateContext() + { + parser_->classPrivateContext_ = prev_; + } + +private: + ParserImpl *parser_; + ClassPrivateContext prev_; +}; + +class FunctionContext : public SavedParserContext { +public: + explicit FunctionContext(ParserImpl *parser, ParserStatus newStatus) : SavedParserContext(parser, newStatus) + { + if ((newStatus & ParserStatus::GENERATOR_FUNCTION) != 0) { + flags_ |= ir::ScriptFunctionFlags::GENERATOR; + } + + if ((newStatus & ParserStatus::ASYNC_FUNCTION) != 0) { + flags_ |= ir::ScriptFunctionFlags::ASYNC; + } + + if ((newStatus & ParserStatus::CONSTRUCTOR_FUNCTION) != 0) { + flags_ |= ir::ScriptFunctionFlags::CONSTRUCTOR; + } + } + + ir::ScriptFunctionFlags Flags() const + { + return flags_; + } + + void AddFlag(ir::ScriptFunctionFlags flags) + { + flags_ |= flags; + } + + NO_COPY_SEMANTIC(FunctionContext); + NO_MOVE_SEMANTIC(FunctionContext); + ~FunctionContext() = default; + +private: + ir::ScriptFunctionFlags flags_ {ir::ScriptFunctionFlags::NONE}; +}; + +class ArrowFunctionContext : public FunctionContext { +public: + explicit ArrowFunctionContext(ParserImpl *parser, bool isAsync) + : FunctionContext(parser, InitialFlags(parser->context_.Status())) + { + if (isAsync) { + AddFlag(ir::ScriptFunctionFlags::ASYNC); + } + + AddFlag(ir::ScriptFunctionFlags::ARROW); + } + + NO_COPY_SEMANTIC(ArrowFunctionContext); + NO_MOVE_SEMANTIC(ArrowFunctionContext); + ~ArrowFunctionContext() = default; + +private: + static ParserStatus InitialFlags(ParserStatus currentStatus) + { + return ParserStatus::FUNCTION | ParserStatus::ARROW_FUNCTION | + static_cast(currentStatus & (ParserStatus::ALLOW_SUPER | ParserStatus::ALLOW_SUPER_CALL)); + } +}; +} // namespace ark::es2panda::parser +#endif diff --git a/ets2panda/parser/statementParser.cpp b/ets2panda/parser/statementParser.cpp index e3dbe1fb3bf05d2a8cf421f086295a062a8b1ab1..127d808c12e5bec82de96c0c71f20ee11d76e7ec 100644 --- a/ets2panda/parser/statementParser.cpp +++ b/ets2panda/parser/statementParser.cpp @@ -14,6 +14,7 @@ */ #include "parser/parserFlags.h" +#include "parser/parserStatusContext.h" #include "util/helpers.h" #include "ir/astNode.h" #include "ir/base/catchClause.h" @@ -724,51 +725,53 @@ std::tuple ParserImpl::Par return {forKind, rightNode, updateNode}; } -std::tuple ParserImpl::ParseForInOf( - ir::Expression *leftNode, ExpressionParseFlags exprFlags, bool isAwait) +std::tuple ParserImpl::ParseIsForInOf( + ir::Expression *leftNode, ExpressionParseFlags exprFlags) { - ForStatementKind forKind = ForStatementKind::UPDATE; - ir::AstNode *initNode = nullptr; - ir::Expression *updateNode = nullptr; - ir::Expression *rightNode = nullptr; + ASSERT(lexer_->GetToken().IsForInOf()); + ForStatementKind forKind = ForStatementKind::OF; - if (lexer_->GetToken().IsForInOf()) { - if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_IN) { - forKind = ForStatementKind::IN; - exprFlags = ExpressionParseFlags::ACCEPT_COMMA; - ValidateForInStatement(); - } else { - forKind = ForStatementKind::OF; - } + if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_IN) { + forKind = ForStatementKind::IN; + exprFlags = ExpressionParseFlags::ACCEPT_COMMA; + ValidateForInStatement(); + } - bool isValid = true; - switch (leftNode->Type()) { - case ir::AstNodeType::IDENTIFIER: - case ir::AstNodeType::MEMBER_EXPRESSION: { - break; - } - case ir::AstNodeType::ARRAY_EXPRESSION: { - isValid = leftNode->AsArrayExpression()->ConvertibleToArrayPattern(); - break; - } - case ir::AstNodeType::OBJECT_EXPRESSION: { - isValid = leftNode->AsObjectExpression()->ConvertibleToObjectPattern(); - break; - } - default: { - isValid = false; - } + bool isValid = true; + switch (leftNode->Type()) { + case ir::AstNodeType::IDENTIFIER: + case ir::AstNodeType::MEMBER_EXPRESSION: { + break; } - - if (!isValid) { - ValidateLvalueAssignmentTarget(leftNode); + case ir::AstNodeType::ARRAY_EXPRESSION: { + isValid = leftNode->AsArrayExpression()->ConvertibleToArrayPattern(); + break; + } + case ir::AstNodeType::OBJECT_EXPRESSION: { + isValid = leftNode->AsObjectExpression()->ConvertibleToObjectPattern(); + break; + } + default: { + isValid = false; } + } - initNode = leftNode; - lexer_->NextToken(); - rightNode = ParseExpression(exprFlags); + if (!isValid) { + ValidateLvalueAssignmentTarget(leftNode); + } - return {forKind, initNode, rightNode, updateNode}; + lexer_->NextToken(); + + return {forKind, leftNode, ParseExpression(exprFlags), nullptr}; +} + +std::tuple ParserImpl::ParseForInOf( + ir::Expression *leftNode, ExpressionParseFlags exprFlags, bool isAwait) +{ + ir::Expression *updateNode = nullptr; + ir::Expression *rightNode = nullptr; + if (lexer_->GetToken().IsForInOf()) { + return ParseIsForInOf(leftNode, exprFlags); } if (isAwait) { @@ -777,19 +780,14 @@ std::tuple ir::Expression *expr = ParseAssignmentExpression(leftNode); - if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { - initNode = ParseSequenceExpression(expr); - } else { - initNode = expr; - } + ir::AstNode *initNode = + lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA ? ParseSequenceExpression(expr) : expr; if (initNode->IsConditionalExpression()) { ir::ConditionalExpression *condExpr = initNode->AsConditionalExpression(); - if (condExpr->Alternate()->IsBinaryExpression()) { - const auto *binaryExpr = condExpr->Alternate()->AsBinaryExpression(); - if (binaryExpr->OperatorType() == lexer::TokenType::KEYW_IN) { - ThrowSyntaxError("Invalid left-hand side in for-in statement"); - } + if (condExpr->Alternate()->IsBinaryExpression() && + condExpr->Alternate()->AsBinaryExpression()->OperatorType() == lexer::TokenType::KEYW_IN) { + ThrowSyntaxError("Invalid left-hand side in for-in statement"); } } @@ -807,7 +805,6 @@ std::tuple lexer_->NextToken(); } else { rightNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::IN_FOR); - if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON) { ThrowSyntaxError("Unexpected token, expected ';' in 'ForStatement'."); } @@ -818,7 +815,7 @@ std::tuple updateNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::IN_FOR); } - return {forKind, initNode, rightNode, updateNode}; + return {ForStatementKind::UPDATE, initNode, rightNode, updateNode}; } std::tuple ParserImpl::ParseForUpdate(bool isAwait) @@ -847,22 +844,11 @@ std::tuple ParserImpl::ParseForUpdate(bool i return {rightNode, updateNode}; } -ir::Statement *ParserImpl::ParseForStatement() +std::tuple ParserImpl::ParseForLoopInitializer() { - lexer::SourcePosition startLoc = lexer_->GetToken().Start(); - ForStatementKind forKind = ForStatementKind::UPDATE; - ir::AstNode *initNode = nullptr; - ir::Expression *updateNode = nullptr; - ir::Expression *leftNode = nullptr; - ir::Expression *rightNode = nullptr; - bool canBeForInOf = true; - bool isAwait = false; - lexer_->NextToken(); VariableParsingFlags varFlags = VariableParsingFlags::IN_FOR; - ExpressionParseFlags exprFlags = ExpressionParseFlags::NO_OPTS; if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT) { - isAwait = true; varFlags |= VariableParsingFlags::DISALLOW_INIT; lexer_->NextToken(); } @@ -892,32 +878,42 @@ ir::Statement *ParserImpl::ParseForStatement() switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_VAR: { - initNode = ParseVariableDeclaration(varFlags | VariableParsingFlags::VAR); - break; + return {nullptr, ParseVariableDeclaration(varFlags | VariableParsingFlags::VAR)}; } case lexer::TokenType::KEYW_LET: { - initNode = ParseVariableDeclaration(varFlags | VariableParsingFlags::LET); - break; + return {nullptr, ParseVariableDeclaration(varFlags | VariableParsingFlags::LET)}; } case lexer::TokenType::KEYW_CONST: { - initNode = ParseVariableDeclaration(varFlags | VariableParsingFlags::CONST | - VariableParsingFlags::ACCEPT_CONST_NO_INIT); - break; + return {nullptr, ParseVariableDeclaration(varFlags | VariableParsingFlags::CONST | + VariableParsingFlags::ACCEPT_CONST_NO_INIT)}; } case lexer::TokenType::PUNCTUATOR_SEMI_COLON: { - if (isAwait) { + if ((varFlags & VariableParsingFlags::DISALLOW_INIT) != 0 /*isAsync*/) { ThrowSyntaxError(UNEXPECTED_TOKEN, lexer_->GetToken().Start()); } - canBeForInOf = false; lexer_->NextToken(); - break; + return {nullptr, nullptr}; } default: { - leftNode = ParseUnaryOrPrefixUpdateExpression(ExpressionParseFlags::POTENTIALLY_IN_PATTERN); - break; + return {ParseUnaryOrPrefixUpdateExpression(ExpressionParseFlags::POTENTIALLY_IN_PATTERN), nullptr}; } } +} + +ir::Statement *ParserImpl::ParseForStatement() +{ + lexer::SourcePosition startLoc = lexer_->GetToken().Start(); + ForStatementKind forKind = ForStatementKind::UPDATE; + ir::AstNode *initNode = nullptr; + ir::Expression *updateNode = nullptr; + ir::Expression *leftNode = nullptr; + ir::Expression *rightNode = nullptr; + + lexer_->NextToken(); + bool isAwait = lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT; + std::tie(leftNode, initNode) = ParseForLoopInitializer(); + bool canBeForInOf = (leftNode != nullptr) || (initNode != nullptr); IterationContext iterCtx(&context_); @@ -938,10 +934,11 @@ ir::Statement *ParserImpl::ParseForStatement() if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { ThrowSyntaxError(INVALID_TYPE_ANNOTATION_IN_FOR, lexer_->GetToken().Start()); } - std::tie(forKind, initNode, rightNode, updateNode) = ParseForInOf(leftNode, exprFlags, isAwait); + std::tie(forKind, initNode, rightNode, updateNode) = + ParseForInOf(leftNode, ExpressionParseFlags::NO_OPTS, isAwait); } else if (initNode != nullptr) { // initNode was parsed as VariableDeclaration and declaration size = 1 - std::tie(forKind, rightNode, updateNode) = ParseForInOf(initNode, exprFlags, isAwait); + std::tie(forKind, rightNode, updateNode) = ParseForInOf(initNode, ExpressionParseFlags::NO_OPTS, isAwait); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) { @@ -953,8 +950,6 @@ ir::Statement *ParserImpl::ParseForStatement() lexer_->NextToken(); ir::Statement *bodyNode = ParseStatement(); - lexer::SourcePosition endLoc = bodyNode->End(); - ir::Statement *forStatement = nullptr; if (forKind == ForStatementKind::UPDATE) { @@ -965,7 +960,7 @@ ir::Statement *ParserImpl::ParseForStatement() forStatement = AllocNode(initNode, rightNode, bodyNode, isAwait); } - forStatement->SetRange({startLoc, endLoc}); + forStatement->SetRange({startLoc, bodyNode->End()}); return forStatement; } diff --git a/ets2panda/parser/statementTSParser.cpp b/ets2panda/parser/statementTSParser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ce03fbe2f1d66b21640b7382faae71b46ee73de --- /dev/null +++ b/ets2panda/parser/statementTSParser.cpp @@ -0,0 +1,373 @@ +/** + * Copyright (c) 2024 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. + */ + +#include "TSparser.h" + +#include "parserFlags.h" +#include "util/helpers.h" +#include "varbinder/privateBinding.h" +#include "varbinder/scope.h" +#include "varbinder/tsBinding.h" +#include "lexer/TSLexer.h" +#include "ir/base/spreadElement.h" +#include "ir/base/decorator.h" +#include "ir/base/classElement.h" +#include "ir/base/classDefinition.h" +#include "ir/base/methodDefinition.h" +#include "ir/base/scriptFunction.h" +#include "ir/module/importDefaultSpecifier.h" +#include "ir/module/exportDefaultDeclaration.h" +#include "ir/module/exportAllDeclaration.h" +#include "ir/module/exportNamedDeclaration.h" +#include "ir/module/importDeclaration.h" +#include "ir/expressions/memberExpression.h" +#include "ir/expressions/sequenceExpression.h" +#include "ir/expressions/templateLiteral.h" +#include "ir/expressions/taggedTemplateExpression.h" +#include "ir/expressions/callExpression.h" +#include "ir/expressions/functionExpression.h" +#include "ir/expressions/arrowFunctionExpression.h" +#include "ir/expressions/yieldExpression.h" +#include "ir/expressions/assignmentExpression.h" +#include "ir/expressions/identifier.h" +#include "ir/expressions/objectExpression.h" +#include "ir/expressions/arrayExpression.h" +#include "ir/expressions/literals/bigIntLiteral.h" +#include "ir/expressions/literals/booleanLiteral.h" +#include "ir/expressions/literals/nullLiteral.h" +#include "ir/expressions/literals/numberLiteral.h" +#include "ir/expressions/literals/stringLiteral.h" +#include "ir/statements/emptyStatement.h" +#include "ir/statements/blockStatement.h" +#include "ir/statements/ifStatement.h" +#include "ir/statements/doWhileStatement.h" +#include "ir/statements/whileStatement.h" +#include "ir/statements/tryStatement.h" +#include "ir/statements/breakStatement.h" +#include "ir/statements/continueStatement.h" +#include "ir/statements/throwStatement.h" +#include "ir/statements/switchStatement.h" +#include "ir/statements/returnStatement.h" +#include "ir/statements/debuggerStatement.h" +#include "ir/statements/classDeclaration.h" +#include "ir/statements/labelledStatement.h" +#include "ir/statements/variableDeclarator.h" +#include "ir/statements/functionDeclaration.h" +#include "ir/ts/tsLiteralType.h" +#include "ir/ts/tsMappedType.h" +#include "ir/ts/tsImportType.h" +#include "ir/ts/tsThisType.h" +#include "ir/ts/tsConditionalType.h" +#include "ir/ts/tsTypeOperator.h" +#include "ir/ts/tsInferType.h" +#include "ir/ts/tsTupleType.h" +#include "ir/ts/tsNamedTupleMember.h" +#include "ir/ts/tsQualifiedName.h" +#include "ir/ts/tsIndexedAccessType.h" +#include "ir/ts/tsTypeQuery.h" +#include "ir/ts/tsTypeReference.h" +#include "ir/ts/tsTypePredicate.h" +#include "ir/ts/tsTypeLiteral.h" +#include "ir/ts/tsArrayType.h" +#include "ir/ts/tsUnionType.h" +#include "ir/ts/tsIntersectionType.h" +#include "ir/ts/tsAnyKeyword.h" +#include "ir/ts/tsUndefinedKeyword.h" +#include "ir/ts/tsVoidKeyword.h" +#include "ir/ts/tsNumberKeyword.h" +#include "ir/ts/tsStringKeyword.h" +#include "ir/ts/tsBooleanKeyword.h" +#include "ir/ts/tsBigintKeyword.h" +#include "ir/ts/tsUnknownKeyword.h" +#include "ir/ts/tsNullKeyword.h" +#include "ir/ts/tsNeverKeyword.h" +#include "ir/ts/tsObjectKeyword.h" +#include "ir/ts/tsFunctionType.h" +#include "ir/ts/tsConstructorType.h" +#include "ir/ts/tsParenthesizedType.h" +#include "ir/ts/tsTypeAssertion.h" +#include "ir/ts/tsAsExpression.h" +#include "ir/ts/tsNonNullExpression.h" +#include "ir/ts/tsEnumDeclaration.h" +#include "ir/ts/tsInterfaceDeclaration.h" +#include "ir/ts/tsTypeAliasDeclaration.h" +#include "ir/ts/tsModuleDeclaration.h" +#include "ir/ts/tsTypeParameterInstantiation.h" +#include "ir/ts/tsInterfaceHeritage.h" +#include "ir/base/tsSignatureDeclaration.h" +#include "ir/base/tsIndexSignature.h" +#include "ir/base/tsMethodSignature.h" +#include "ir/base/tsPropertySignature.h" +#include "ir/ts/tsParameterProperty.h" +#include "ir/ts/tsClassImplements.h" +#include "ir/ts/tsImportEqualsDeclaration.h" +#include "ir/ts/tsExternalModuleReference.h" + +namespace ark::es2panda::parser { +// NOLINTNEXTLINE(google-default-arguments) +ir::Statement *TSParser::ParseStatement(StatementParsingFlags flags) +{ + return ParseDeclareAndDecorators(flags); +} +ir::TSImportEqualsDeclaration *TSParser::ParseTsImportEqualsDeclaration(const lexer::SourcePosition &startLoc, + bool isExport) +{ + ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_IMPORT); + Lexer()->NextToken(); + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + ThrowSyntaxError("Unexpected token"); + } + + auto *id = AllocNode(Lexer()->GetToken().Ident(), Allocator()); + id->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); // eat id name + + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + ThrowSyntaxError("'=' expected"); + } + Lexer()->NextToken(); // eat substitution + + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { + ThrowSyntaxError("identifier expected"); + } + + auto *importEqualsDecl = AllocNode(id, ParseModuleReference(), isExport); + importEqualsDecl->SetRange({startLoc, Lexer()->GetToken().End()}); + + ConsumeSemicolon(importEqualsDecl); + + return importEqualsDecl; +} + +// NOLINTNEXTLINE(google-default-arguments) +ir::ExportDefaultDeclaration *TSParser::ParseExportDefaultDeclaration(const lexer::SourcePosition &startLoc, + bool isExportEquals) +{ + Lexer()->NextToken(); // eat `default` keyword or `=` + + ir::AstNode *declNode = nullptr; + bool eatSemicolon = false; + + switch (Lexer()->GetToken().KeywordType()) { + case lexer::TokenType::KEYW_FUNCTION: { + declNode = ParseFunctionDeclaration(true); + break; + } + case lexer::TokenType::KEYW_CLASS: { + declNode = ParseClassDeclaration(ir::ClassDefinitionModifiers::ID_REQUIRED); + break; + } + case lexer::TokenType::KEYW_INTERFACE: { + declNode = ParseInterfaceDeclaration(false); + break; + } + case lexer::TokenType::KEYW_ASYNC: { + if ((Lexer()->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) == 0) { + Lexer()->NextToken(); // eat `async` + declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); + break; + } + [[fallthrough]]; + } + default: { + declNode = ParseExpression(); + eatSemicolon = true; + break; + } + } + + lexer::SourcePosition endLoc = declNode->End(); + auto *exportDeclaration = AllocNode(declNode, isExportEquals); + exportDeclaration->SetRange({startLoc, endLoc}); + + if (eatSemicolon) { + ConsumeSemicolon(exportDeclaration); + } + + return exportDeclaration; +} + +ir::Statement *TSParser::GetDeclarationForNamedExport(ir::ClassDefinitionModifiers &classModifiers, + ir::ModifierFlags &flags) +{ + switch (Lexer()->GetToken().KeywordType()) { + case lexer::TokenType::KEYW_VAR: { + return ParseVariableDeclaration(VariableParsingFlags::VAR); + } + case lexer::TokenType::KEYW_CONST: { + return ParseVariableDeclaration(VariableParsingFlags::CONST); + } + case lexer::TokenType::KEYW_LET: { + return ParseVariableDeclaration(VariableParsingFlags::LET); + } + case lexer::TokenType::KEYW_FUNCTION: { + return ParseFunctionDeclaration(false, ParserStatus::NO_OPTS); + } + case lexer::TokenType::KEYW_CLASS: { + return ParseClassDeclaration(classModifiers, flags); + } + case lexer::TokenType::KEYW_ENUM: { + return ParseEnumDeclaration(); + } + case lexer::TokenType::KEYW_INTERFACE: { + return ParseInterfaceDeclaration(false); + } + case lexer::TokenType::KEYW_TYPE: { + return ParseTypeAliasDeclaration(); + } + case lexer::TokenType::KEYW_GLOBAL: + case lexer::TokenType::KEYW_MODULE: + case lexer::TokenType::KEYW_NAMESPACE: { + return ParseModuleDeclaration(); + } + default: { + if (!Lexer()->GetToken().IsAsyncModifier()) { + ThrowSyntaxError("Unexpected token"); + } + + Lexer()->NextToken(); // eat `async` keyword + return ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); + } + } +} +ir::ExportNamedDeclaration *TSParser::ParseNamedExportDeclaration(const lexer::SourcePosition &startLoc) +{ + ir::ClassDefinitionModifiers classModifiers = ir::ClassDefinitionModifiers::ID_REQUIRED; + ir::ModifierFlags flags = ir::ModifierFlags::NONE; + + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_DECLARE) { + CheckDeclare(); + } + + if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_ABSTRACT) { + Lexer()->NextToken(); // eat 'abstract' + flags |= ir::ModifierFlags::ABSTRACT; + } + + ir::Statement *decl = GetDeclarationForNamedExport(classModifiers, flags); + + if (decl->IsVariableDeclaration()) { + ConsumeSemicolon(decl); + } + + lexer::SourcePosition endLoc = decl->End(); + ArenaVector specifiers(Allocator()->Adapter()); + auto *exportDeclaration = AllocNode(Allocator(), decl, std::move(specifiers)); + exportDeclaration->SetRange({startLoc, endLoc}); + + return exportDeclaration; +} + +ir::Statement *TSParser::ParseExportDeclaration(StatementParsingFlags flags) +{ + lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); + Lexer()->NextToken(); // eat `export` keyword + + switch (Lexer()->GetToken().Type()) { + case lexer::TokenType::KEYW_DEFAULT: { + return ParseExportDefaultDeclaration(startLoc); + } + case lexer::TokenType::PUNCTUATOR_MULTIPLY: { + return ParseExportAllDeclaration(startLoc); + } + case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { + return ParseExportNamedSpecifiers(startLoc); + } + case lexer::TokenType::KEYW_IMPORT: { + return ParseTsImportEqualsDeclaration(startLoc, true); + } + case lexer::TokenType::PUNCTUATOR_SUBSTITUTION: { + return ParseExportDefaultDeclaration(startLoc, true); + } + default: { + ir::ExportNamedDeclaration *exportDecl = ParseNamedExportDeclaration(startLoc); + + if (exportDecl->Decl()->IsVariableDeclaration() && ((flags & StatementParsingFlags::GLOBAL) == 0) && + exportDecl->Parent() != nullptr && !exportDecl->Parent()->IsTSModuleBlock() && + !GetContext().IsModule()) { + ThrowSyntaxError("Modifiers cannot appear here'"); + } + + return exportDecl; + } + } +} + +ir::Statement *TSParser::ParseConstStatement(StatementParsingFlags flags) +{ + lexer::SourcePosition constVarStar = Lexer()->GetToken().Start(); + Lexer()->NextToken(); + + if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ENUM) { + return ParseEnumDeclaration(true); + } + + if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) { + ThrowSyntaxError("Lexical declaration is not allowed in single statement context"); + } + + auto *variableDecl = ParseVariableDeclaration(VariableParsingFlags::CONST | VariableParsingFlags::NO_SKIP_VAR_KIND); + variableDecl->SetStart(constVarStar); + ConsumeSemicolon(variableDecl); + + return variableDecl; +} + +ir::Statement *TSParser::ParsePotentialConstEnum(VariableParsingFlags flags) +{ + if ((flags & VariableParsingFlags::CONST) == 0) { + ThrowSyntaxError("Variable declaration expected."); + } + + return ParseEnumDeclaration(true); +} + +ir::Statement *TSParser::ParseImportDeclaration([[maybe_unused]] StatementParsingFlags flags) +{ + char32_t nextChar = Lexer()->Lookahead(); + if (nextChar == lexer::LEX_CHAR_LEFT_PAREN || nextChar == lexer::LEX_CHAR_DOT) { + return ParseExpressionStatement(); + } + + lexer::SourcePosition startLoc = Lexer()->GetToken().Start(); + Lexer()->NextToken(); // eat import + + ArenaVector specifiers(Allocator()->Adapter()); + + ir::StringLiteral *source = nullptr; + + if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { + ir::AstNode *astNode = ParseImportSpecifiers(&specifiers); + if (astNode != nullptr) { + ASSERT(astNode->IsTSImportEqualsDeclaration()); + astNode->SetRange({startLoc, Lexer()->GetToken().End()}); + ConsumeSemicolon(astNode->AsTSImportEqualsDeclaration()); + return astNode->AsTSImportEqualsDeclaration(); + } + source = ParseFromClause(true); + } else { + source = ParseFromClause(false); + } + + lexer::SourcePosition endLoc = source->End(); + auto *importDeclaration = AllocNode(source, std::move(specifiers)); + importDeclaration->SetRange({startLoc, endLoc}); + + ConsumeSemicolon(importDeclaration); + + return importDeclaration; +} + +} // namespace ark::es2panda::parser \ No newline at end of file diff --git a/ets2panda/test/parser/ts/test_import_type-expected.txt b/ets2panda/test/parser/ts/test_import_type-expected.txt index 1f19c1b27a3fbef5b4def9bda16a29f8560caee6..67c7aee67d77d322fc5b3b19354338453d998268 100644 --- a/ets2panda/test/parser/ts/test_import_type-expected.txt +++ b/ets2panda/test/parser/ts/test_import_type-expected.txt @@ -42,7 +42,7 @@ "loc": { "start": { "line": 17, - "column": 8 + "column": 21 }, "end": { "line": 17, @@ -160,7 +160,7 @@ "loc": { "start": { "line": 20, - "column": 10 + "column": 25 }, "end": { "line": 20, @@ -446,7 +446,7 @@ "loc": { "start": { "line": 24, - "column": 15 + "column": 34 }, "end": { "line": 24, @@ -781,7 +781,7 @@ "loc": { "start": { "line": 24, - "column": 37 + "column": 132 }, "end": { "line": 24,