From 0fd61f875214bd0b09817f9c9e5429ba1cdd9405 Mon Sep 17 00:00:00 2001 From: Csaba Osztrogonac Date: Tue, 23 Jul 2024 15:35:34 +0200 Subject: [PATCH] [ArkTS Frontend] Fix OHOS code style in ets2panda/parser https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/IAF2VW Change-Id: Id23ee723417a6b0249f79e8c82fc5690b6466e65 Signed-off-by: Csaba Osztrogonac --- ets2panda/BUILD.gn | 5 + ets2panda/CMakeLists.txt | 5 + ets2panda/parser/ETSparser.cpp | 2770 +-------------------- ets2panda/parser/ETSparser.h | 5 +- ets2panda/parser/ETSparserClasses.cpp | 1092 ++++++++ ets2panda/parser/ETSparserEnums.cpp | 318 +++ ets2panda/parser/ETSparserExpressions.cpp | 810 ++++++ ets2panda/parser/ETSparserStatements.cpp | 337 +++ ets2panda/parser/ETSparserTypes.cpp | 434 ++++ 9 files changed, 3109 insertions(+), 2667 deletions(-) create mode 100644 ets2panda/parser/ETSparserClasses.cpp create mode 100644 ets2panda/parser/ETSparserEnums.cpp create mode 100644 ets2panda/parser/ETSparserExpressions.cpp create mode 100644 ets2panda/parser/ETSparserStatements.cpp create mode 100644 ets2panda/parser/ETSparserTypes.cpp diff --git a/ets2panda/BUILD.gn b/ets2panda/BUILD.gn index c7a2c0f773..dc35767198 100644 --- a/ets2panda/BUILD.gn +++ b/ets2panda/BUILD.gn @@ -382,6 +382,11 @@ 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", diff --git a/ets2panda/CMakeLists.txt b/ets2panda/CMakeLists.txt index f6f77d63f6..13c9109e93 100644 --- a/ets2panda/CMakeLists.txt +++ b/ets2panda/CMakeLists.txt @@ -378,6 +378,11 @@ set(ES2PANDA_LIB_SRC 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 diff --git a/ets2panda/parser/ETSparser.cpp b/ets2panda/parser/ETSparser.cpp index e4ac1b283e..1142847c4c 100644 --- a/ets2panda/parser/ETSparser.cpp +++ b/ets2panda/parser/ETSparser.cpp @@ -26,65 +26,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 +54,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,14 +63,10 @@ #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" @@ -271,121 +225,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 +243,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 +296,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 +307,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 +328,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 +435,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 +497,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,319 +556,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(), name, typeParamDecl, body, std::move(extends), 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; @@ -1746,49 +717,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) { @@ -1904,439 +832,43 @@ 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; + if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { + if (((*options) & TypeAnnotationParsingOptions::THROW_ERROR) != 0) { + ThrowExpectedToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); } - Lexer()->NextToken(); // eat '&' - types.push_back(ParseTypeReference(&options)); + Lexer()->Rewind(savedPos); + typeAnnotation = nullptr; + } else { + Lexer()->NextToken(); // eat ')' } - - 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); - } - - Lexer()->Rewind(savedPos); - typeAnnotation = nullptr; - } else { - Lexer()->NextToken(); // eat ')' - } -} - -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) @@ -2346,16 +878,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 || @@ -2396,12 +918,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(); @@ -2697,89 +1213,33 @@ ir::ETSUnionType *ETSParser::CreateOptionalParameterTypeNode(ir::TypeNode *typeA return unionType; } -ir::Expression *ETSParser::ParseFunctionParameterExpression(ir::AnnotatedExpression *const paramIdent, - ir::ETSUndefinedType *defaultUndef) +ir::Expression *ETSParser::ParseFunctionParameter() { - ir::ETSParameterExpression *paramExpression; - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { + auto *const paramIdent = GetAnnotatedExpressionFromParam(); + + ir::ETSUndefinedType *defaultUndef = nullptr; + + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { if (paramIdent->IsRestElement()) { ThrowSyntaxError(NO_DEFAULT_FOR_REST); } + defaultUndef = AllocNode(); + defaultUndef->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()}); + Lexer()->NextToken(); // eat '?' + } - auto const lexerPos = Lexer()->Save().Iterator(); - Lexer()->NextToken(); // eat '=' + const bool isArrow = (GetContext().Status() & ParserStatus::ARROW_FUNCTION) != 0; + + if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) { + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options); 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."); + typeAnnotation = CreateOptionalParameterTypeNode(typeAnnotation, defaultUndef); } - 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(); - - ir::ETSUndefinedType *defaultUndef = nullptr; - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_QUESTION_MARK) { - if (paramIdent->IsRestElement()) { - ThrowSyntaxError(NO_DEFAULT_FOR_REST); - } - defaultUndef = AllocNode(); - defaultUndef->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()}); - Lexer()->NextToken(); // eat '?' - } - - const bool isArrow = (GetContext().Status() & ParserStatus::ARROW_FUNCTION) != 0; - - if (Lexer()->TryEatTokenType(lexer::TokenType::PUNCTUATOR_COLON)) { - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - ir::TypeNode *typeAnnotation = ParseTypeAnnotation(&options); - - if (defaultUndef != nullptr) { - typeAnnotation = CreateOptionalParameterTypeNode(typeAnnotation, defaultUndef); - } - - if (paramIdent->IsRestElement() && !typeAnnotation->IsTSArrayType()) { - ThrowSyntaxError(ONLY_ARRAY_FOR_REST); + if (paramIdent->IsRestElement() && !typeAnnotation->IsTSArrayType()) { + ThrowSyntaxError(ONLY_ARRAY_FOR_REST); } typeAnnotation->SetParent(paramIdent); @@ -2884,28 +1344,6 @@ ir::VariableDeclarator *ETSParser::ParseVariableDeclarator(ir::Expression *init, return declarator; } -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::Expression *ETSParser::ParseCatchParam() { if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { @@ -2951,50 +1389,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(); @@ -3022,587 +1416,80 @@ ir::Statement *ETSParser::ParseImportDeclaration([[maybe_unused]] StatementParsi importSource = ParseSourceFromClause(false); } - lexer::SourcePosition endLoc = importSource->Source()->End(); - auto *importDeclaration = AllocNode(importSource, std::move(specifiers)); - importDeclaration->SetRange({startLoc, endLoc}); - - ConsumeSemicolon(importDeclaration); - - return importDeclaration; -} - -ir::Statement *ETSParser::ParseExportDeclaration([[maybe_unused]] StatementParsingFlags flags) -{ - 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) -{ - if (type == lexer::TokenType::KEYW_INSTANCEOF) { - TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; - - if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_NULL) { - auto *typeAnnotation = AllocNode(); - typeAnnotation->SetRange(Lexer()->GetToken().Loc()); - Lexer()->NextToken(); - - return typeAnnotation; - } - - return ParseTypeAnnotation(&options); - } - - 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) -{ - if (Lexer()->Lookahead() == lexer::LEX_CHAR_LESS_THAN || - (!primaryExpr->IsIdentifier() && !primaryExpr->IsMemberExpression())) { - return true; - } - - const auto savedPos = Lexer()->Save(); - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) { - Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1); - } - - TypeAnnotationParsingOptions options = - TypeAnnotationParsingOptions::ALLOW_WILDCARD | TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE; - ir::TSTypeParameterInstantiation *typeParams = ParseTypeParameterInstantiation(&options); - - if (typeParams == nullptr) { - Lexer()->Rewind(savedPos); - return true; - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::EOS) { - ThrowSyntaxError("'(' expected"); - } - - if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { - if (!ignoreCallExpression) { - *returnExpression = ParseCallExpression(*returnExpression, false, false); - (*returnExpression)->AsCallExpression()->SetTypeParams(typeParams); - return false; - } - - return true; - } - - Lexer()->Rewind(savedPos); - 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); + lexer::SourcePosition endLoc = importSource->Source()->End(); + auto *importDeclaration = AllocNode(importSource, std::move(specifiers)); + importDeclaration->SetRange({startLoc, endLoc}); - 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)); + ConsumeSemicolon(importDeclaration); - classDefinition->SetRange(bodyRange); - } + return importDeclaration; +} - return classDefinition; +ir::Statement *ETSParser::ParseExportDeclaration([[maybe_unused]] StatementParsingFlags flags) +{ + ThrowUnexpectedToken(lexer::TokenType::KEYW_EXPORT); } -ir::Expression *ETSParser::ParseNewExpression() +ir::Expression *ETSParser::ParseExpressionOrTypeAnnotation(lexer::TokenType type, + [[maybe_unused]] ExpressionParseFlags flags) { - lexer::SourcePosition start = Lexer()->GetToken().Start(); + if (type == lexer::TokenType::KEYW_INSTANCEOF) { + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; + + if (Lexer()->GetToken().Type() == lexer::TokenType::LITERAL_NULL) { + auto *typeAnnotation = AllocNode(); + typeAnnotation->SetRange(Lexer()->GetToken().Loc()); + Lexer()->NextToken(); - Lexer()->NextToken(); // eat new + return typeAnnotation; + } - 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."); + return ParseTypeAnnotation(&options); } - 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); + return ParseExpression(ExpressionParseFlags::DISALLOW_YIELD); +} - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { - auto *arrInstance = AllocNode(typeReference, dimension); - arrInstance->SetRange({start, endLoc}); - return arrInstance; - } +bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, ir::Expression **returnExpression, + [[maybe_unused]] const lexer::SourcePosition &startLoc, + bool ignoreCallExpression) +{ + if (Lexer()->Lookahead() == lexer::LEX_CHAR_LESS_THAN || + (!primaryExpr->IsIdentifier() && !primaryExpr->IsMemberExpression())) { + return true; + } - ArenaVector dimensions(Allocator()->Adapter()); - dimensions.push_back(dimension); + const auto savedPos = Lexer()->Save(); - do { - Lexer()->NextToken(); - dimensions.push_back(ParseExpression()); + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SHIFT) { + Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1); + } - endLoc = Lexer()->GetToken().End(); - ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_SQUARE_BRACKET); - } while (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET); + TypeAnnotationParsingOptions options = + TypeAnnotationParsingOptions::ALLOW_WILDCARD | TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE; + ir::TSTypeParameterInstantiation *typeParams = ParseTypeParameterInstantiation(&options); - auto *multiArray = AllocNode(typeReference, std::move(dimensions)); - multiArray->SetRange({start, endLoc}); - return multiArray; + if (typeParams == nullptr) { + Lexer()->Rewind(savedPos); + return true; } - 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()}); + if (Lexer()->GetToken().Type() == lexer::TokenType::EOS) { + ThrowSyntaxError("'(' expected"); + } - return newExprNode; -} + if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { + if (!ignoreCallExpression) { + *returnExpression = ParseCallExpression(*returnExpression, false, false); + (*returnExpression)->AsCallExpression()->SetTypeParams(typeParams); + return false; + } -ir::Expression *ETSParser::ParseAsyncExpression() -{ - Lexer()->NextToken(); // eat 'async' - if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS || - !IsArrowFunctionExpressionStart()) { - ThrowSyntaxError("Unexpected token. expected '('"); + return true; } - 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; + Lexer()->Rewind(savedPos); + return true; } ir::ModifierFlags ETSParser::ParseTypeVarianceModifier(TypeAnnotationParsingOptions *const options) @@ -3690,9 +1577,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); } @@ -3709,422 +1595,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), 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) { @@ -4231,49 +1712,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 61c6cae57d..d5d8c6dd04 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 0000000000..f227d4061a --- /dev/null +++ b/ets2panda/parser/ETSparserClasses.cpp @@ -0,0 +1,1092 @@ +/** + * 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 "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 { +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(), name, typeParamDecl, body, std::move(extends), 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 0000000000..661630e2bf --- /dev/null +++ b/ets2panda/parser/ETSparserEnums.cpp @@ -0,0 +1,318 @@ +/** + * 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 "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 { +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), 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 0000000000..f644482f5d --- /dev/null +++ b/ets2panda/parser/ETSparserExpressions.cpp @@ -0,0 +1,810 @@ +/** + * 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 "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 { +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 0000000000..9fc9d50f31 --- /dev/null +++ b/ets2panda/parser/ETSparserStatements.cpp @@ -0,0 +1,337 @@ +/** + * 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 "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 { +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 0000000000..47659ad985 --- /dev/null +++ b/ets2panda/parser/ETSparserTypes.cpp @@ -0,0 +1,434 @@ +/** + * 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 "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 { +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 -- Gitee