/** * Copyright (c) 2021-2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ETSparser.h" #include "parser/parserFlags.h" #include "parser/parserStatusContext.h" #include "util/errorRecovery.h" #include "util/helpers.h" #include "ir/astNode.h" #include "ir/base/catchClause.h" #include "ir/base/classDefinition.h" #include "ir/base/scriptFunction.h" #include "ir/expression.h" #include "ir/expressions/arrayExpression.h" #include "ir/expressions/binaryExpression.h" #include "ir/expressions/conditionalExpression.h" #include "ir/expressions/literals/stringLiteral.h" #include "ir/expressions/objectExpression.h" #include "ir/expressions/sequenceExpression.h" #include "ir/module/exportAllDeclaration.h" #include "ir/module/exportDefaultDeclaration.h" #include "ir/module/exportNamedDeclaration.h" #include "ir/module/exportSpecifier.h" #include "ir/module/importDeclaration.h" #include "ir/module/importDefaultSpecifier.h" #include "ir/module/importNamespaceSpecifier.h" #include "ir/module/importSpecifier.h" #include "ir/statements/blockStatement.h" #include "ir/statements/breakStatement.h" #include "ir/statements/classDeclaration.h" #include "ir/statements/continueStatement.h" #include "ir/statements/debuggerStatement.h" #include "ir/statements/doWhileStatement.h" #include "ir/statements/emptyStatement.h" #include "ir/statements/expressionStatement.h" #include "ir/statements/forInStatement.h" #include "ir/statements/forOfStatement.h" #include "ir/statements/forUpdateStatement.h" #include "ir/statements/functionDeclaration.h" #include "ir/statements/ifStatement.h" #include "ir/statements/labelledStatement.h" #include "ir/statements/returnStatement.h" #include "ir/statements/switchCaseStatement.h" #include "ir/statements/switchStatement.h" #include "ir/statements/throwStatement.h" #include "ir/statements/tryStatement.h" #include "ir/statements/variableDeclaration.h" #include "ir/statements/variableDeclarator.h" #include "ir/statements/whileStatement.h" #include "ir/ets/etsStructDeclaration.h" #include "lexer/lexer.h" #include "lexer/token/letters.h" #include "lexer/token/sourceLocation.h" #include "util/recursiveGuard.h" #include "util/ustring.h" #include "generated/diagnostic.h" #include "parserImpl.h" namespace ark::es2panda::parser { using namespace std::literals::string_literals; // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParserImpl::ParseStatementLiteralIdentHelper(StatementParsingFlags flags) { if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT) { return ParseStructStatement(flags, ir::ClassDefinitionModifiers::NONE); } if (lexer_->Lookahead() == lexer::LEX_CHAR_COLON) { const auto pos = lexer_->Save(); lexer_->NextToken(); return ParseLabelledStatement(pos); } return ParsePotentialExpressionStatement(flags); } // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParserImpl::ParseStatementPunctuatorsHelper(StatementParsingFlags flags) { TrackRecursive trackRecursive(RecursiveCtx()); if (!trackRecursive) { LogError(diagnostic::DEEP_NESTING); while (Lexer()->GetToken().Type() != lexer::TokenType::EOS) { Lexer()->NextToken(); } return AllocBrokenStatement(Lexer()->GetToken().Loc()); } switch (lexer_->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: return ParseBlockStatement(); case lexer::TokenType::PUNCTUATOR_SEMI_COLON: return ParseEmptyStatement(); case lexer::TokenType::PUNCTUATOR_FORMAT: // 1 if (lexer_->Lookahead() == static_cast(STATEMENT_FORMAT_NODE)) { return ParseStatementFormatPlaceholder(); } [[fallthrough]]; default: return ParseExpressionStatement(flags); } } // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParserImpl::ParseStatementControlFlowTokenHelper(StatementParsingFlags flags) { switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_IF: return ParseIfStatement(); case lexer::TokenType::KEYW_DO: return ParseDoWhileStatement(); case lexer::TokenType::KEYW_FOR: return ParseForStatement(); case lexer::TokenType::KEYW_TRY: return ParseTryStatement(); case lexer::TokenType::KEYW_WHILE: return ParseWhileStatement(); case lexer::TokenType::KEYW_BREAK: return ParseBreakStatement(); case lexer::TokenType::KEYW_CONTINUE: return ParseContinueStatement(); case lexer::TokenType::KEYW_THROW: return ParseThrowStatement(); case lexer::TokenType::KEYW_RETURN: return ParseReturnStatement(); case lexer::TokenType::KEYW_SWITCH: return ParseSwitchStatement(); default: return ParseExpressionStatement(flags); } } // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParserImpl::ParseStatement(StatementParsingFlags flags) { if (IsETSParser()) { AsETSParser()->HandleJsDocLikeComments(); } const auto tokenType = lexer_->GetToken().Type(); bool isPunctuatorToken = tokenType == lexer::TokenType::PUNCTUATOR_LEFT_BRACE || tokenType == lexer::TokenType::PUNCTUATOR_SEMI_COLON || tokenType == lexer::TokenType::PUNCTUATOR_FORMAT; if (isPunctuatorToken) { return ParseStatementPunctuatorsHelper(flags); } bool isControlFlowToken = tokenType == lexer::TokenType::KEYW_IF || tokenType == lexer::TokenType::KEYW_DO || tokenType == lexer::TokenType::KEYW_FOR || tokenType == lexer::TokenType::KEYW_TRY || tokenType == lexer::TokenType::KEYW_WHILE || tokenType == lexer::TokenType::KEYW_BREAK || tokenType == lexer::TokenType::KEYW_CONTINUE || tokenType == lexer::TokenType::KEYW_THROW || tokenType == lexer::TokenType::KEYW_RETURN || tokenType == lexer::TokenType::KEYW_SWITCH; if (isControlFlowToken) { return ParseStatementControlFlowTokenHelper(flags); } return ParseStatementBasedOnTokenType(flags); } ir::Statement *ParserImpl::ParseStatementBasedOnTokenType(StatementParsingFlags flags) { switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_EXPORT: return ParseExportDeclaration(flags); case lexer::TokenType::KEYW_IMPORT: return ParseImportDeclaration(flags); case lexer::TokenType::KEYW_FUNCTION: return ParseFunctionStatement(flags); case lexer::TokenType::KEYW_ABSTRACT: case lexer::TokenType::KEYW_FINAL: case lexer::TokenType::KEYW_CLASS: return ParseClassStatement(flags, ir::ClassDefinitionModifiers::NONE); case lexer::TokenType::KEYW_VAR: return ParseVarStatement(); case lexer::TokenType::KEYW_LET: return ParseLetStatement(flags); case lexer::TokenType::KEYW_CONST: return ParseConstStatement(flags); case lexer::TokenType::KEYW_DEBUGGER: return ParseDebuggerStatement(); case lexer::TokenType::LITERAL_IDENT: if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_VAR) { return ParseVarStatement(); } return ParseStatementLiteralIdentHelper(flags); case lexer::TokenType::KEYW_WITH: LogError(diagnostic::WITH_DEPRECATED); lexer_->NextToken(); return nullptr; case lexer::TokenType::KEYW_ENUM: return ParseEnumDeclaration(); case lexer::TokenType::KEYW_INTERFACE: return ParseInterfaceStatement(flags); case lexer::TokenType::PUNCTUATOR_AT: if (IsETSParser()) { return ParseAnnotationsInStatement(flags); } [[fallthrough]]; default: return ParseExpressionStatement(flags); } } ir::Statement *ParserImpl::ParseAnnotationsInStatement([[maybe_unused]] StatementParsingFlags flags) { ES2PANDA_UNREACHABLE(); } ir::Statement *ParserImpl::ParseVarStatement() { auto *variableDecl = ParseVariableDeclaration(VariableParsingFlags::VAR); ConsumeSemicolon(variableDecl); return variableDecl; } ir::Statement *ParserImpl::ParseLetStatement(StatementParsingFlags flags) { if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) { LogError(diagnostic::LEXICAL_DEC_NOT_ALLOWED_IN_SINGLE_STATEMENT_CONTEXT); } auto *variableDecl = ParseVariableDeclaration(VariableParsingFlags::LET); ES2PANDA_ASSERT(variableDecl != nullptr); if (variableDecl->IsBrokenStatement()) { // Error processing. return variableDecl; } ConsumeSemicolon(variableDecl); return variableDecl; } ir::Statement *ParserImpl::ParseConstStatement(StatementParsingFlags flags) { if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) { LogError(diagnostic::LEXICAL_DEC_NOT_ALLOWED_IN_SINGLE_STATEMENT_CONTEXT); } lexer::SourcePosition constVarStar = lexer_->GetToken().Start(); lexer_->NextToken(); auto *variableDecl = ParseVariableDeclaration(VariableParsingFlags::CONST | VariableParsingFlags::NO_SKIP_VAR_KIND); ES2PANDA_ASSERT(variableDecl != nullptr); if (variableDecl->IsBrokenStatement()) { // Error processing. return variableDecl; } variableDecl->SetStart(constVarStar); ConsumeSemicolon(variableDecl); return variableDecl; } ir::EmptyStatement *ParserImpl::ParseEmptyStatement() { auto *empty = AllocNode(); ES2PANDA_ASSERT(empty != nullptr); empty->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); return empty; } ir::Statement *ParserImpl::ParseDebuggerStatement() { auto *debuggerNode = AllocNode(); ES2PANDA_ASSERT(debuggerNode != nullptr); debuggerNode->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); ConsumeSemicolon(debuggerNode); return debuggerNode; } ir::Statement *ParserImpl::ParseFunctionStatement(StatementParsingFlags flags) { CheckFunctionDeclaration(flags); if ((flags & StatementParsingFlags::STMT_LEXICAL_SCOPE_NEEDED) == 0) { return ParseFunctionDeclaration(false, ParserStatus::NO_OPTS); } auto *funcDecl = ParseFunctionDeclaration(false, ParserStatus::NO_OPTS); ArenaVector stmts(Allocator()->Adapter()); stmts.push_back(funcDecl); auto *localBlockStmt = AllocNode(Allocator(), std::move(stmts)); ES2PANDA_ASSERT(localBlockStmt != nullptr); localBlockStmt->SetRange(funcDecl->Range()); return funcDecl; } ir::Statement *ParserImpl::ParsePotentialExpressionStatement(StatementParsingFlags flags) { return ParseExpressionStatement(flags); } // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParserImpl::ParseStructStatement([[maybe_unused]] StatementParsingFlags flags, ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags modFlags) { LogError(diagnostic::ILLEGAL_START_STRUCT_CLASS, {"STRUCT"}); return ParseStructDeclaration(modifiers, modFlags); } // NOLINTNEXTLINE(google-default-arguments) ir::Statement *ParserImpl::ParseClassStatement(StatementParsingFlags flags, ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags modFlags) { if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) { LogError(diagnostic::LEXICAL_DEC_NOT_ALLOWED_IN_SINGLE_STATEMENT_CONTEXT); } return ParseClassDeclaration(modifiers, modFlags); } ir::Statement *ParserImpl::ParseInterfaceStatement(StatementParsingFlags flags) { if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) { LogError(diagnostic::LEXICAL_DEC_NOT_ALLOWED_IN_SINGLE_STATEMENT_CONTEXT); } return ParseInterfaceDeclaration(false); } ir::Statement *ParserImpl::ParseStructDeclaration(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags) { const lexer::SourcePosition startLoc = lexer_->GetToken().Start(); modifiers |= ir::ClassDefinitionModifiers::DECLARATION; if (IsExternal()) { modifiers |= ir::ClassDefinitionModifiers::FROM_EXTERNAL; } ir::ClassDefinition *classDefinition = ParseClassDefinition(modifiers, flags); if (classDefinition == nullptr) { // Error processing. // Error is logged inside ParseClassDefinition return AllocBrokenStatement(Lexer()->GetToken().Loc()); } lexer::SourcePosition endLoc = classDefinition->End(); auto *structDecl = AllocNode(classDefinition, Allocator()); ES2PANDA_ASSERT(structDecl != nullptr); structDecl->SetRange({startLoc, endLoc}); return structDecl; } ir::Statement *ParserImpl::ParseClassDeclaration(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags) { const lexer::SourcePosition startLoc = lexer_->GetToken().Start(); modifiers |= ir::ClassDefinitionModifiers::DECLARATION; if (IsExternal()) { modifiers |= ir::ClassDefinitionModifiers::FROM_EXTERNAL; } ir::ClassDefinition *classDefinition = ParseClassDefinition(modifiers, flags); if (classDefinition == nullptr) { // Error processing. // Error is logged inside ParseClassDefinition return AllocBrokenStatement(Lexer()->GetToken().Loc()); } lexer::SourcePosition endLoc = classDefinition->End(); auto *classDecl = AllocNode(classDefinition, Allocator()); ES2PANDA_ASSERT(classDecl != nullptr); classDecl->SetRange({startLoc, endLoc}); return classDecl; } void ParserImpl::CheckFunctionDeclaration(StatementParsingFlags flags) { if ((flags & StatementParsingFlags::LABELLED) != 0) { LogError(diagnostic::STRICT_MODE_FUNC_DECL); } if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) { if ((flags & (StatementParsingFlags::IF_ELSE | StatementParsingFlags::LABELLED)) == 0) { LogError(diagnostic::LEXICAL_DEC_NOT_ALLOWED_IN_SINGLE_STATEMENT_CONTEXT); } if (lexer_->Lookahead() == lexer::LEX_CHAR_ASTERISK) { LogError(diagnostic::GENERATORS_ONLY_TOP_LEVEL_OR_INSIDE_BLOCK); } } } void ParserImpl::ConsumeSemicolon(ir::Statement *statement) { auto const &token = lexer_->GetToken(); auto tokenType = token.Type(); if (tokenType == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { ES2PANDA_ASSERT(statement != nullptr); statement->SetEnd(token.End()); lexer_->NextToken(); return; } if (!token.NewLine() && tokenType != lexer::TokenType::EOS && tokenType != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { LogUnexpectedToken(token); } } ArenaVector ParserImpl::ParseStatementList(StatementParsingFlags flags) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT && lexer_->Lookahead() == static_cast(ARRAY_FORMAT_NODE)) { return std::move(ParseStatementsArrayFormatPlaceholder()); } ArenaVector statements(Allocator()->Adapter()); ParseDirectivePrologue(&statements); auto endType = (flags & StatementParsingFlags::GLOBAL) != 0 ? lexer::TokenType::EOS : lexer::TokenType::PUNCTUATOR_RIGHT_BRACE; while (lexer_->GetToken().Type() != endType && lexer_->GetToken().Type() != lexer::TokenType::EOS) { util::ErrorRecursionGuard infiniteLoopBlocker(lexer_); if (auto statement = ParseStatement(flags); statement != nullptr) { statements.push_back(statement); } } return statements; } bool ParserImpl::ParseDirective(ArenaVector *statements) { ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_STRING); const util::StringView &str = lexer_->GetToken().String(); const auto status = static_cast( context_.Status() & (ParserStatus::CONSTRUCTOR_FUNCTION | ParserStatus::HAS_COMPLEX_PARAM)); if (status == ParserStatus::HAS_COMPLEX_PARAM && str.Is("use strict")) { LogError(diagnostic::ILLEGAL_USE_STRICT); } ir::Expression *exprNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); if (exprNode == nullptr) { // Error processing. return false; } bool isDirective = exprNode->IsStringLiteral(); auto *exprStatement = AllocNode(exprNode); ES2PANDA_ASSERT(exprStatement != nullptr); exprStatement->SetRange(exprNode->Range()); ConsumeSemicolon(exprStatement); statements->push_back(exprStatement); return isDirective; } void ParserImpl::ParseDirectivePrologue(ArenaVector *statements) { while (true) { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_STRING || !ParseDirective(statements)) { break; } } } bool ParserImpl::ValidateLabeledStatement([[maybe_unused]] lexer::TokenType type) { return true; } ir::BlockStatement *ParserImpl::ParseBlockStatement() { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE); auto statements = ParseStatementList(); auto *blockNode = AllocNode(Allocator(), std::move(statements)); ES2PANDA_ASSERT(blockNode != nullptr); blockNode->SetRange({startLoc, lexer_->GetToken().End()}); ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE); return blockNode; } void ParserImpl::ReportPossibleOutOfBoundaryJumpError([[maybe_unused]] bool allowBreak) {} void ParserImpl::ReportIllegalBreakError(const lexer::SourcePosition &startLoc) { LogError(diagnostic::ILLEGAL_BREAK, {}, startLoc); } ir::Statement *ParserImpl::ParseBreakStatement() { bool allowBreak = (context_.Status() & (ParserStatus::IN_ITERATION | ParserStatus::IN_SWITCH)) != 0; ReportPossibleOutOfBoundaryJumpError(allowBreak); lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON || lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().NewLine() || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { if (!allowBreak) { ReportIllegalBreakError(startLoc); } auto *breakStatement = AllocNode(); ES2PANDA_ASSERT(breakStatement != nullptr); breakStatement->SetRange({startLoc, lexer_->GetToken().End()}); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); } return breakStatement; } if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { LogExpectedToken(lexer::TokenType::LITERAL_IDENT); } const auto &label = lexer_->GetToken().Ident(); if (!ValidateBreakLabel(label)) { LogError(diagnostic::UNDEFINED_LABEL); } auto *identNode = AllocNode(label, Allocator()); ES2PANDA_ASSERT(identNode != nullptr); identNode->SetRange(lexer_->GetToken().Loc()); auto *breakStatement = AllocNode(identNode); ES2PANDA_ASSERT(breakStatement != nullptr); breakStatement->SetRange({startLoc, lexer_->GetToken().End()}); lexer_->NextToken(); ConsumeSemicolon(breakStatement); return breakStatement; } void ParserImpl::ReportIllegalContinueError() { LogError(diagnostic::ILLEGALE_CONTINUE); } ir::Statement *ParserImpl::ParseContinueStatement() { ReportPossibleOutOfBoundaryJumpError((context_.Status() & (ParserStatus::IN_ITERATION | ParserStatus::IN_SWITCH)) != 0U); if ((context_.Status() & ParserStatus::IN_ITERATION) == 0) { ReportIllegalContinueError(); } lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { auto *continueStatement = AllocNode(); ES2PANDA_ASSERT(continueStatement != nullptr); continueStatement->SetRange({startLoc, lexer_->GetToken().End()}); lexer_->NextToken(); return continueStatement; } if (lexer_->GetToken().NewLine() || lexer_->GetToken().Type() == lexer::TokenType::EOS || lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_BRACE) { auto *continueStatement = AllocNode(); ES2PANDA_ASSERT(continueStatement != nullptr); continueStatement->SetRange({startLoc, endLoc}); return continueStatement; } if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { LogExpectedToken(lexer::TokenType::LITERAL_IDENT); } const auto &label = lexer_->GetToken().Ident(); if (!ValidateContinueLabel(label)) { LogError(diagnostic::UNDEFINED_LABEL); } auto *identNode = AllocNode(label, Allocator()); ES2PANDA_ASSERT(identNode != nullptr); identNode->SetRange(lexer_->GetToken().Loc()); auto *continueStatement = AllocNode(identNode); ES2PANDA_ASSERT(continueStatement != nullptr); continueStatement->SetRange({startLoc, lexer_->GetToken().End()}); lexer_->NextToken(); ConsumeSemicolon(continueStatement); return continueStatement; } ir::Statement *ParserImpl::ParseDoWhileStatement() { IterationContext iterCtx(&context_); lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); ir::Statement *body = ParseStatement(); if (IsBrokenStatement(body)) { LogError(diagnostic::MISSING_LOOP_BODY, {"do while"}); } if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_WHILE) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { // do {} (true) LogError(diagnostic::UNEXPECTED_TOKEN_WHILE); // just skip the token } else { // do {} whle (true) LogExpectedToken(lexer::TokenType::KEYW_WHILE); lexer_->NextToken(); } } else { lexer_->NextToken(); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { LogExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); } lexer_->NextToken(); ir::Expression *condition = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); if (condition->IsBrokenExpression()) { LogError(diagnostic::MISSING_LOOP_CONDITION, {"do while"}); } auto endLoc = lexer_->GetToken().End(); ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); auto *doWhileStatement = AllocNode(body, condition); ES2PANDA_ASSERT(doWhileStatement != nullptr); doWhileStatement->SetRange({startLoc, endLoc}); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { doWhileStatement->SetEnd(lexer_->GetToken().End()); lexer_->NextToken(); } return doWhileStatement; } ir::FunctionDeclaration *ParserImpl::ParseFunctionDeclaration(bool canBeAnonymous, ParserStatus newStatus) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::KEYW_FUNCTION); ParserStatus savedStatus = context_.Status(); lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) { newStatus |= ParserStatus::GENERATOR_FUNCTION; lexer_->NextToken(); } context_.Status() = savedStatus; if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { if (canBeAnonymous) { ir::ScriptFunction *func = ParseFunction(newStatus | ParserStatus::NEED_RETURN_TYPE); ES2PANDA_ASSERT(func != nullptr); func->SetStart(startLoc); auto *funcDecl = AllocNode(Allocator(), func, true); ES2PANDA_ASSERT(funcDecl != nullptr); funcDecl->SetRange(func->Range()); return funcDecl; } // test exists for ts extension LogError(diagnostic::UNEXPECTED_TOKEN_ID_FUN); lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_IDENT); lexer_->GetToken().SetTokenStr(ERROR_LITERAL); } CheckRestrictedBinding(); auto *identNode = ExpectIdentifier(); newStatus |= ParserStatus::FUNCTION_DECLARATION; ir::ScriptFunction *func = ParseFunction(newStatus | ParserStatus::NEED_RETURN_TYPE); ES2PANDA_ASSERT(func != nullptr); func->SetIdent(identNode); func->SetStart(startLoc); auto *funcDecl = AllocNode(Allocator(), func); ES2PANDA_ASSERT(funcDecl != nullptr); funcDecl->SetRange(func->Range()); if (func->IsOverload() && lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); } return funcDecl; } ir::Statement *ParserImpl::ParseExpressionStatement(StatementParsingFlags flags) { const auto startPos = lexer_->Save(); ParserStatus savedStatus = context_.Status(); auto tokenType = lexer_->GetToken().Type(); if (tokenType == lexer::TokenType::KEYW_PUBLIC || tokenType == lexer::TokenType::KEYW_PRIVATE || tokenType == lexer::TokenType::KEYW_PROTECTED) { lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_CLASS || lexer_->GetToken().Type() == lexer::TokenType::KEYW_INTERFACE) { LogError(diagnostic::LOCAL_CLASS_ACCESS_MOD, {}, startPos.GetToken().Start()); // Suppose it is a class declaration. return ParseClassDeclaration(ir::ClassDefinitionModifiers::NONE); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_AT) { LogError(diagnostic::ANNOTATION_DECLARATION_ACCESS_MODIFIER, {}, startPos.GetToken().Start()); } lexer_->Rewind(startPos); } if (lexer_->GetToken().IsAsyncModifier()) { lexer_->NextToken(); if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_FUNCTION && !lexer_->GetToken().NewLine()) { if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) { LogError(diagnostic::LEXICAL_DEC_NOT_ALLOWED_IN_SINGLE_STATEMENT_CONTEXT); } ir::FunctionDeclaration *functionDecl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); functionDecl->SetStart(startPos.GetToken().Start()); return functionDecl; } lexer_->Rewind(startPos); } ir::Expression *exprNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); context_.Status() = savedStatus; lexer::SourcePosition endPos = exprNode->End(); auto *exprStatementNode = AllocNode(exprNode); ES2PANDA_ASSERT(exprStatementNode != nullptr); exprStatementNode->SetRange({startPos.GetToken().Start(), endPos}); ConsumeSemicolon(exprStatementNode); return exprStatementNode; } // NOLINTBEGIN(cert-err58-cpp) static std::string const INVALID_LEFT_HAND_IN_FOR_OF = "Invalid left-hand side in 'for' statement: must have a single binding."s; static std::string const MISSING_LEFT_IN_FOR = "Missing left parenthesis in 'for' statement."s; static std::string const MISSING_RIGHT_IN_FOR = "Missing right parenthesis in 'for' statement."s; static std::string const INVALID_TYPE_ANNOTATION_IN_FOR = "Type annotation is not allowed when existing variable is used as loop iterator in 'for' statement."s; // NOLINTEND(cert-err58-cpp) std::tuple ParserImpl::ParseForInOf( ir::AstNode *initNode, ExpressionParseFlags exprFlags, bool isAwait) { ForStatementKind forKind = ForStatementKind::UPDATE; ir::Expression *updateNode = nullptr; ir::Expression *rightNode = nullptr; if (lexer_->GetToken().IsForInOf()) { const ir::VariableDeclarator *varDecl = initNode->AsVariableDeclaration()->Declarators().front(); if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_IN) { if (varDecl->Init() != nullptr) { LogError(diagnostic::FOR_IN_LOOP_HAS_INIT); } forKind = ForStatementKind::IN; exprFlags = ExpressionParseFlags::ACCEPT_COMMA; ValidateForInStatement(); } else { if (varDecl->Init() != nullptr) { LogError(diagnostic::FOR_OF_LOOP_HAS_INIT); } forKind = ForStatementKind::OF; } lexer_->NextToken(); rightNode = ParseExpression(exprFlags); } else { if (IsETSParser()) { ExpectToken(lexer::TokenType::PUNCTUATOR_SEMI_COLON); } if (isAwait) { LogUnexpectedToken(Lexer()->GetToken()); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { LogError(diagnostic::INVALID_LEFT_FOR_IN_OF); return {forKind, rightNode, updateNode}; } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); } else { rightNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::IN_FOR); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON) { LogExpectedToken(lexer::TokenType::PUNCTUATOR_SEMI_COLON); } lexer_->NextToken(); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { updateNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::IN_FOR); } } return {forKind, rightNode, updateNode}; } std::tuple ParserImpl::ParseIsForInOf( ir::Expression *leftNode, ExpressionParseFlags exprFlags) { ES2PANDA_ASSERT(lexer_->GetToken().IsForInOf()); ForStatementKind forKind = ForStatementKind::OF; if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_IN) { forKind = ForStatementKind::IN; exprFlags = ExpressionParseFlags::ACCEPT_COMMA; ValidateForInStatement(); } bool isValid = true; switch (leftNode->Type()) { case ir::AstNodeType::IDENTIFIER: case ir::AstNodeType::MEMBER_EXPRESSION: { break; } case ir::AstNodeType::ARRAY_EXPRESSION: { isValid = leftNode->AsArrayExpression()->ConvertibleToArrayPattern(); break; } case ir::AstNodeType::OBJECT_EXPRESSION: { isValid = leftNode->AsObjectExpression()->ConvertibleToObjectPattern(); break; } default: { isValid = false; } } if (!isValid) { ValidateLvalueAssignmentTarget(leftNode); } lexer_->NextToken(); return {forKind, leftNode, ParseExpression(exprFlags), nullptr}; } std::tuple ParserImpl::ParseForInOf( ir::Expression *leftNode, ExpressionParseFlags exprFlags, bool isAwait) { ir::Expression *updateNode = nullptr; ir::Expression *rightNode = nullptr; if (lexer_->GetToken().IsForInOf()) { return ParseIsForInOf(leftNode, exprFlags); } if (isAwait) { LogUnexpectedToken(Lexer()->GetToken()); } ir::Expression *expr = ParseAssignmentExpression(leftNode); ir::AstNode *initNode = lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA ? ParseSequenceExpression(expr) : expr; ES2PANDA_ASSERT(initNode != nullptr); if (initNode->IsConditionalExpression()) { ir::ConditionalExpression *condExpr = initNode->AsConditionalExpression(); if (condExpr->Alternate()->IsBinaryExpression() && condExpr->Alternate()->AsBinaryExpression()->OperatorType() == lexer::TokenType::KEYW_IN) { LogError(diagnostic::INVALID_LEFT_FOR_IN); rightNode = AllocBrokenExpression(Lexer()->GetToken().Loc()); updateNode = AllocBrokenExpression(Lexer()->GetToken().Loc()); // CC-OFFNXT(G.FMT.03-CPP) project code style return {ForStatementKind::IN, initNode, rightNode, updateNode}; } } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { rightNode = AllocBrokenExpression(Lexer()->GetToken().Loc()); updateNode = AllocBrokenExpression(Lexer()->GetToken().Loc()); LogError(diagnostic::INVALID_LEFT_FOR_IN_OF); return {ForStatementKind::UPDATE, initNode, rightNode, updateNode}; } ExpectToken(lexer::TokenType::PUNCTUATOR_SEMI_COLON); if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); } else { rightNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::IN_FOR); ExpectToken(lexer::TokenType::PUNCTUATOR_SEMI_COLON); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { updateNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::IN_FOR); } return {ForStatementKind::UPDATE, initNode, rightNode, updateNode}; } std::tuple ParserImpl::ParseForUpdate(bool isAwait) { if (isAwait) { LogUnexpectedToken(Lexer()->GetToken()); } ir::Expression *updateNode = nullptr; ir::Expression *rightNode = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); } else { rightNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::IN_FOR); ExpectToken(lexer::TokenType::PUNCTUATOR_SEMI_COLON); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS) { updateNode = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA | ExpressionParseFlags::IN_FOR); } return {rightNode, updateNode}; } std::tuple ParserImpl::ParseForLoopInitializer() { VariableParsingFlags varFlags = VariableParsingFlags::IN_FOR; if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT) { varFlags |= VariableParsingFlags::DISALLOW_INIT; lexer_->NextToken(); } ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); lexer::TokenType tokenType; auto const currentPosition = lexer_->Save(); do { tokenType = lexer_->GetToken().Type(); if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_OF) { varFlags |= VariableParsingFlags::FOR_OF; break; } if (tokenType == lexer::TokenType::KEYW_IN) { varFlags |= VariableParsingFlags::STOP_AT_IN; break; } lexer_->NextToken(); } while (tokenType != lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS && tokenType != lexer::TokenType::PUNCTUATOR_LEFT_BRACE && tokenType != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS && tokenType != lexer::TokenType::EOS); lexer_->Rewind(currentPosition); switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_VAR: return {nullptr, ParseVariableDeclaration(varFlags | VariableParsingFlags::VAR)}; case lexer::TokenType::KEYW_LET: return {nullptr, ParseVariableDeclaration(varFlags | VariableParsingFlags::LET)}; case lexer::TokenType::KEYW_CONST: { return {nullptr, ParseVariableDeclaration(varFlags | VariableParsingFlags::CONST | VariableParsingFlags::ACCEPT_CONST_NO_INIT)}; } case lexer::TokenType::PUNCTUATOR_SEMI_COLON: if ((varFlags & VariableParsingFlags::DISALLOW_INIT) != 0 /*isAsync*/) { LogUnexpectedToken(Lexer()->GetToken()); } lexer_->NextToken(); return {nullptr, nullptr}; default: return {ParseUnaryOrPrefixUpdateExpression(ExpressionParseFlags::POTENTIALLY_IN_PATTERN), nullptr}; } } bool ParserImpl::GetCanBeForInOf(ir::Expression *leftNode, ir::AstNode *initNode) { bool statementIsCorrect = initNode != nullptr && !initNode->IsBrokenStatement(); bool expressionIsCorrect = leftNode != nullptr && !leftNode->IsBrokenExpression(); bool canBeForInOf = expressionIsCorrect || statementIsCorrect; if (statementIsCorrect) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SEMI_COLON) { lexer_->NextToken(); canBeForInOf = false; } else if (initNode->AsVariableDeclaration()->Declarators().size() > 1 && lexer_->GetToken().IsForInOf()) { LogError(diagnostic::INVALID_LEFT_HAND_IN_FOR_OF, {}, initNode->AsVariableDeclaration()->Declarators()[1]->Start()); } } return canBeForInOf; } struct ForStatementNodes { ir::AstNode *init; ir::Expression *right; ir::Expression *update; ir::Statement *body; }; ir::Statement *ParserImpl::CreateForStatement(ForStatementNodes &&nodes, ForStatementKind forKind, const lexer::SourcePosition &startLoc, bool isAwait) { ES2PANDA_ASSERT(nodes.body != nullptr); ir::Statement *forStatement = nullptr; if (forKind == ForStatementKind::UPDATE) { forStatement = AllocNode(nodes.init, nodes.right, nodes.update, nodes.body); } else { if (nodes.init == nullptr || nodes.right == nullptr) { // Error processing. // Error is logged inside ParseForLoopInitializer or ParseForUpdate, or ParseForInOf return AllocBrokenStatement(Lexer()->GetToken().Loc()); } if (forKind == ForStatementKind::IN) { forStatement = AllocNode(nodes.init, nodes.right, nodes.body); } else { forStatement = AllocNode(nodes.init, nodes.right, nodes.body, isAwait); } } ES2PANDA_ASSERT(forStatement != nullptr); forStatement->SetRange({startLoc, nodes.body->End()}); return forStatement; } ir::Statement *ParserImpl::ParseForStatement() { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ForStatementKind forKind = ForStatementKind::UPDATE; ir::AstNode *initNode = nullptr; ir::Expression *updateNode = nullptr; ir::Expression *leftNode = nullptr; ir::Expression *rightNode = nullptr; lexer_->NextToken(); bool isAwait = lexer_->GetToken().Type() == lexer::TokenType::KEYW_AWAIT; std::tie(leftNode, initNode) = ParseForLoopInitializer(); IterationContext iterCtx(&context_); // VariableDeclaration->DeclarationSize > 1 or seen semi_colon if (!GetCanBeForInOf(leftNode, initNode)) { std::tie(rightNode, updateNode) = ParseForUpdate(isAwait); } else if (leftNode != nullptr) { // initNode was parsed as LHS if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) { LogError(diagnostic::INVALID_TYPE_ANNOTATION_IN_FOR); lexer_->NextToken(); // eat ':' } std::tie(forKind, initNode, rightNode, updateNode) = ParseForInOf(leftNode, ExpressionParseFlags::NO_OPTS, isAwait); } else if (initNode != nullptr) { // initNode was parsed as VariableDeclaration and declaration size = 1 std::tie(forKind, rightNode, updateNode) = ParseForInOf(initNode, ExpressionParseFlags::NO_OPTS, isAwait); } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_EXCLAMATION_MARK) { lexer_->NextToken(); } ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); ir::Statement *bodyNode = ParseStatement(); if (bodyNode == nullptr) { return AllocBrokenStatement(Lexer()->GetToken().Loc()); } return CreateForStatement({initNode, rightNode, updateNode, bodyNode}, forKind, startLoc, isAwait); } void ParserImpl::ReportIfBodyEmptyError([[maybe_unused]] ir::Statement *consequent) {} ir::Statement *ParserImpl::ParseIfStatement() { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer::SourcePosition endLoc; lexer_->NextToken(); ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); ir::Expression *test = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); ir::Statement *consequent = ParseStatement(StatementParsingFlags::IF_ELSE | StatementParsingFlags::ALLOW_LEXICAL); ES2PANDA_ASSERT(consequent != nullptr); ReportIfBodyEmptyError(consequent); endLoc = consequent->End(); ir::Statement *alternate = nullptr; if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_ELSE) { lexer_->NextToken(); // eat ELSE keyword alternate = ParseStatement(StatementParsingFlags::IF_ELSE | StatementParsingFlags::ALLOW_LEXICAL); if (alternate != nullptr) { // Error processing. endLoc = alternate->End(); } } auto *ifStatement = AllocNode(test, consequent, alternate); ES2PANDA_ASSERT(ifStatement != nullptr); ifStatement->SetRange({startLoc, endLoc}); return ifStatement; } ir::Statement *ParserImpl::ParseLabelledStatement(const lexer::LexerPosition &pos) { const util::StringView &actualLabel = pos.GetToken().Ident(); if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_AWAIT && context_.IsModule()) { LogError(diagnostic::AWAIT_RESERVED_IDENTIFIER_IN_MODULE, {}, pos.GetToken().Start()); } if (context_.FindLabel(actualLabel) != nullptr) { LogError(diagnostic::LABEL_ALREADY_DECLARED, {}, pos.GetToken().Start()); } SavedParserContext newCtx(this, ParserStatus::IN_LABELED, actualLabel); auto *identNode = AllocNode(actualLabel, Allocator()); ES2PANDA_ASSERT(identNode != nullptr); identNode->SetRange(pos.GetToken().Loc()); lexer_->NextToken(); if (!ValidateLabeledStatement(Lexer()->GetToken().Type())) { return AllocBrokenStatement(Lexer()->GetToken().Loc()); // Error processing. } ir::Statement *body = ParseStatement(StatementParsingFlags::LABELLED); auto *labeledStatement = AllocNode(identNode, body); ES2PANDA_ASSERT(labeledStatement != nullptr); labeledStatement->SetRange({pos.GetToken().Start(), body->End()}); return labeledStatement; } ir::Statement *ParserImpl::ParseReturnStatement() { bool inClassInitializer = (context_.Status() & ParserStatus::IN_CLASS_BODY) != 0 && (context_.Status() & ParserStatus::STATIC_BLOCK) != 0; if ((context_.Status() & ParserStatus::FUNCTION) == 0 && (context_.Status() & ParserStatus::PARSE_TRAILING_BLOCK) == 0 && !(inClassInitializer && IsETSParser())) { LogError(diagnostic::RETURN_IN_FUN_BODY); } lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); bool hasArgument = (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_SEMI_COLON && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE && lexer_->GetToken().Type() != lexer::TokenType::EOS && !lexer_->GetToken().NewLine()); ir::ReturnStatement *returnStatement = nullptr; if (hasArgument) { if (inClassInitializer) { LogError(diagnostic::RETURN_WITH_VALUE); } ir::Expression *expression = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); if (expression != nullptr) { // Error processing. endLoc = expression->End(); } // returnStatement will have void return type if expression == nullptr returnStatement = AllocNode(expression); } else { returnStatement = AllocNode(); } ES2PANDA_ASSERT(returnStatement != nullptr); returnStatement->SetRange({startLoc, endLoc}); ConsumeSemicolon(returnStatement); context_.Status() |= ParserStatus::FUNCTION_HAS_RETURN_STATEMENT; return returnStatement; } void ParserImpl::ReportMultipleDefaultError() { LogError(diagnostic::MULTIPLE_DEFAULT); } ir::SwitchCaseStatement *ParserImpl::ParseSwitchCaseStatement(bool *seenDefault) { auto const &token = lexer_->GetToken(); lexer::SourcePosition caseStartLoc = token.Start(); ir::Expression *testExpr = nullptr; switch (token.KeywordType()) { case lexer::TokenType::KEYW_CASE: { lexer_->NextToken(); // eat 'case' testExpr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); break; } case lexer::TokenType::KEYW_DEFAULT: { if (*seenDefault) { ReportMultipleDefaultError(); } *seenDefault = true; lexer_->NextToken(); // eat 'default' break; } default: { LogError(diagnostic::UNEXPECTED_TOKEN_PARAM_EXPECTED_CASE_OR_DEFAULT, {lexer::TokenToString(lexer_->GetToken().Type())}); testExpr = AllocBrokenExpression(caseStartLoc); } } lexer::SourcePosition caseEndLoc = lexer_->GetToken().End(); ExpectToken(lexer::TokenType::PUNCTUATOR_COLON); ArenaVector consequents(Allocator()->Adapter()); while (lexer_->GetToken().Type() != lexer::TokenType::KEYW_CASE && lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_DEFAULT && lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE && lexer_->GetToken().Type() != lexer::TokenType::EOS) { util::ErrorRecursionGuard infiniteLoopBlocker(Lexer()); ir::Statement *consequent = ParseStatement(StatementParsingFlags::ALLOW_LEXICAL); ES2PANDA_ASSERT(consequent != nullptr); caseEndLoc = consequent->End(); consequents.push_back(consequent); } auto *caseNode = AllocNode(testExpr, std::move(consequents)); ES2PANDA_ASSERT(caseNode != nullptr); caseNode->SetRange({caseStartLoc, caseEndLoc}); return caseNode; } ir::Statement *ParserImpl::ParseSwitchStatement() { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ExpectToken(lexer::TokenType::KEYW_SWITCH); ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); ir::Expression *discriminant = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); SwitchContext switchContext(&context_); ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE); bool seenDefault = false; ArenaVector cases(Allocator()->Adapter()); while (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_RIGHT_BRACE && lexer_->GetToken().Type() != lexer::TokenType::EOS) { util::ErrorRecursionGuard infiniteLoopBlocker(lexer_); auto caseStatement = ParseSwitchCaseStatement(&seenDefault); if (caseStatement != nullptr) { cases.push_back(caseStatement); } } auto endLoc = lexer_->GetToken().End(); ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE); auto *switchStatement = AllocNode(discriminant, std::move(cases)); ES2PANDA_ASSERT(switchStatement != nullptr); switchStatement->SetRange({startLoc, endLoc}); return switchStatement; } void ParserImpl::ReportIllegalNewLineErrorAfterThrow() { LogError(diagnostic::ILLEGAL_NEW_LINE); } ir::Statement *ParserImpl::ParseThrowStatement() { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); if (lexer_->GetToken().NewLine()) { ReportIllegalNewLineErrorAfterThrow(); } ir::Expression *expression = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); ES2PANDA_ASSERT(expression != nullptr); lexer::SourcePosition endLoc = expression->End(); auto *throwStatement = AllocNode(expression); ES2PANDA_ASSERT(throwStatement != nullptr); throwStatement->SetRange({startLoc, endLoc}); ConsumeSemicolon(throwStatement); context_.Status() |= ParserStatus::FUNCTION_HAS_THROW_STATEMENT; return throwStatement; } void ParserImpl::ParseCatchParamTypeAnnotation([[maybe_unused]] ir::AnnotatedExpression *param) {} ir::Expression *ParserImpl::ParseCatchParam() { ir::AnnotatedExpression *param = nullptr; if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { return param; } lexer_->NextToken(); // eat '(' if (auto const tokenType = lexer_->GetToken().Type(); tokenType == lexer::TokenType::LITERAL_IDENT) { CheckRestrictedBinding(); param = ExpectIdentifier(); } else if (tokenType == lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET) { param = ParseArrayExpression(ExpressionParseFlags::MUST_BE_PATTERN); } else if (tokenType == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { param = ParseObjectExpression(ExpressionParseFlags::MUST_BE_PATTERN); } else { LogError(diagnostic::UNEXPECTED_TOKEN_PARAM, {lexer::TokenToString(lexer_->GetToken().Type())}); } if (param != nullptr) { // Error processing. ParseCatchParamTypeAnnotation(param); } ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); return param; } ir::CatchClause *ParserImpl::ParseCatchClause() { lexer::SourcePosition catchStartLoc = lexer_->GetToken().Start(); lexer_->NextToken(); // eat 'catch' keyword ir::Expression *param = ParseCatchParam(); if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { LogError(diagnostic::EXPECTED_PARAM_GOT_PARAM, {"{", lexer::TokenToString(lexer_->GetToken().Type())}); } ir::BlockStatement *catchBlock = ParseBlockStatement(); ES2PANDA_ASSERT(catchBlock != nullptr); lexer::SourcePosition endLoc = catchBlock->End(); auto *catchClause = AllocNode(param, catchBlock); ES2PANDA_ASSERT(catchClause != nullptr); catchClause->SetRange({catchStartLoc, endLoc}); return catchClause; } ir::Statement *ParserImpl::ParseTryStatement() { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer::SourcePosition endLoc = lexer_->GetToken().End(); lexer_->NextToken(); // eat 'try' if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { LogError(diagnostic::EXPECTED_PARAM_GOT_PARAM, {"{", lexer::TokenToString(lexer_->GetToken().Type())}); } ir::BlockStatement *body = ParseBlockStatement(); if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_CATCH && lexer_->GetToken().Type() != lexer::TokenType::KEYW_FINALLY) { /* If we are here, there are two options: 1. there is neither 'catch', nor 'finally'; 2. we made typo and got identifier instead of a first keyword after Try statement. So, this check does not work if we write Try, Catch statements and then make a mistake -> only setting current token as 'catch' is a possible option to fix most cases Test exixts for ts extension only: catch_or_finally_1.ts */ LogError(diagnostic::MISSING_CATCH_OR_FINALLY); } ir::CatchClause *catchClause = nullptr; ir::BlockStatement *finallyClause = nullptr; ArenaVector catchClauses(Allocator()->Adapter()); while (lexer_->GetToken().Type() == lexer::TokenType::KEYW_CATCH) { catchClause = ParseCatchClause(); ES2PANDA_ASSERT(catchClause != nullptr); endLoc = catchClause->End(); catchClauses.push_back(catchClause); } if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_FINALLY) { lexer_->NextToken(); // eat 'finally' keyword finallyClause = ParseBlockStatement(); ES2PANDA_ASSERT(finallyClause != nullptr); endLoc = finallyClause->End(); } ArenaVector> finalizerInsertions(Allocator()->Adapter()); auto *tryStatement = AllocNode(body, std::move(catchClauses), finallyClause, finalizerInsertions); ES2PANDA_ASSERT(tryStatement != nullptr); tryStatement->SetRange({startLoc, endLoc}); return tryStatement; } void ParserImpl::ValidateDeclaratorId() { if (InAmbientContext()) { return; } CheckRestrictedBinding(); } ir::VariableDeclarator *ParserImpl::ParseVariableDeclaratorInitializer(ir::Expression *init, VariableParsingFlags flags, const lexer::SourcePosition &startLoc) { if ((flags & VariableParsingFlags::DISALLOW_INIT) != 0) { LogError(diagnostic::FOR_AWAIT_OF_VAR_NOT_INIT); } lexer_->NextToken(); if (InAmbientContext() && (flags & VariableParsingFlags::CONST) == 0) { LogError(diagnostic::INITIALIZERS_IN_AMBIENT_CONTEXTS); } auto exprFlags = ((flags & VariableParsingFlags::STOP_AT_IN) != 0 ? ExpressionParseFlags::STOP_AT_IN : ExpressionParseFlags::NO_OPTS); ir::Expression *initializer = ParseExpression(exprFlags); if (initializer == nullptr) { // Error processing. return nullptr; } lexer::SourcePosition endLoc = initializer->End(); auto *declarator = AllocNode(GetFlag(flags), init, initializer); declarator->SetRange({startLoc, endLoc}); return declarator; } ir::AnnotatedExpression *ParserImpl::ParseVariableDeclaratorKey([[maybe_unused]] VariableParsingFlags flags) { switch (lexer_->GetToken().Type()) { case lexer::TokenType::LITERAL_IDENT: { ValidateDeclaratorId(); return ExpectIdentifier(true); } case lexer::TokenType::PUNCTUATOR_LEFT_SQUARE_BRACKET: { return ParseArrayExpression(ExpressionParseFlags::MUST_BE_PATTERN); } case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { return ParseObjectExpression(ExpressionParseFlags::MUST_BE_PATTERN); } default: { break; } } LogError(diagnostic::UNEXPECTED_TOKEN); return nullptr; } ir::VariableDeclaratorFlag ParserImpl::GetFlag(VariableParsingFlags flags) { constexpr auto VARIABLE_FLAGS = (VariableParsingFlags::VAR | VariableParsingFlags::LET | VariableParsingFlags::CONST); switch (static_cast(flags & VARIABLE_FLAGS)) { case VariableParsingFlags::CONST: return ir::VariableDeclaratorFlag::CONST; case VariableParsingFlags::VAR: return ir::VariableDeclaratorFlag::VAR; case VariableParsingFlags::LET: return ir::VariableDeclaratorFlag::LET; default: ES2PANDA_UNREACHABLE(); } } ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(ir::Expression *init, lexer::SourcePosition startLoc, VariableParsingFlags flags) { if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) { return ParseVariableDeclaratorInitializer(init, flags, startLoc); } if ((flags & VariableParsingFlags::CONST) != 0U && (flags & VariableParsingFlags::ACCEPT_CONST_NO_INIT) == 0U) { LogError(diagnostic::MISSING_INIT_OR_CONST_DEC); } if ((flags & VariableParsingFlags::IN_FOR) == 0U && (init->IsArrayPattern() || init->IsObjectPattern())) { LogError(diagnostic::MISSING_INIT_IN_DEST_DEC); } lexer::SourcePosition endLoc = init->End(); auto declarator = AllocNode(GetFlag(flags), init); declarator->SetRange({startLoc, endLoc}); return declarator; } ir::VariableDeclarator *ParserImpl::ParseVariableDeclarator(VariableParsingFlags flags) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); ir::Expression *init = ParseVariableDeclaratorKey(flags); if (init == nullptr) { // Error processing. return nullptr; } return ParseVariableDeclarator(init, startLoc, flags); } ir::Statement *ParserImpl::ParsePotentialConstEnum([[maybe_unused]] VariableParsingFlags flags) { LogError(diagnostic::VAR_DEC_EXPECTED); return ParseEnumDeclaration(true); } void ParserImpl::ReportIfVarDeclaration([[maybe_unused]] VariableParsingFlags flags) {} ir::Statement *ParserImpl::ParseVariableDeclaration(VariableParsingFlags flags) { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); if ((flags & VariableParsingFlags::NO_SKIP_VAR_KIND) == 0) { lexer_->NextToken(); } ReportIfVarDeclaration(flags); if (lexer_->GetToken().Type() == lexer::TokenType::KEYW_ENUM) { return ParsePotentialConstEnum(flags); } ArenaVector declarators(Allocator()->Adapter()); while (true) { ir::VariableDeclarator *declarator = ParseVariableDeclarator(flags); if (declarator != nullptr) { // Error processing. declarators.push_back(declarator); } if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) { break; } lexer_->NextToken(); } if (declarators.empty()) { // Error processing. // Error is logged inside ParseVariableDeclaratorKey or ParseVariableDeclaratorInitializer return AllocBrokenStatement(Lexer()->GetToken().Loc()); } auto varKind = ir::VariableDeclaration::VariableDeclarationKind::VAR; if ((flags & VariableParsingFlags::LET) != 0) { varKind = ir::VariableDeclaration::VariableDeclarationKind::LET; } else if ((flags & VariableParsingFlags::CONST) != 0) { varKind = ir::VariableDeclaration::VariableDeclarationKind::CONST; } lexer::SourcePosition endLoc = declarators.back()->End(); auto *declaration = AllocNode(varKind, Allocator(), std::move(declarators)); ES2PANDA_ASSERT(declaration != nullptr); declaration->SetRange({startLoc, endLoc}); return declaration; } ir::Statement *ParserImpl::ParseWhileStatement() { lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); ir::Expression *condition = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA); ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS); IterationContext iterCtx(&context_); ir::Statement *body = ParseStatement(); if (IsBrokenStatement(body)) { LogError(diagnostic::MISSING_LOOP_BODY, {"while"}); } if (condition->IsBrokenExpression()) { LogError(diagnostic::MISSING_LOOP_CONDITION, {"while"}); } lexer::SourcePosition endLoc = body->End(); auto *whileStatement = AllocNode(condition, body); ES2PANDA_ASSERT(whileStatement != nullptr); whileStatement->SetRange({startLoc, endLoc}); return whileStatement; } // NOLINTNEXTLINE(google-default-arguments) ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const lexer::SourcePosition &startLoc, bool isExportEquals) { lexer_->NextToken(); // eat `default` keyword or `=` ir::AstNode *declNode = nullptr; bool eatSemicolon = false; switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_FUNCTION: declNode = ParseFunctionDeclaration(true); break; case lexer::TokenType::KEYW_CLASS: declNode = ParseClassDeclaration(ir::ClassDefinitionModifiers::NONE); break; case lexer::TokenType::LITERAL_IDENT: switch (lexer_->GetToken().KeywordType()) { case lexer::TokenType::KEYW_STRUCT: declNode = ParseStructDeclaration(ir::ClassDefinitionModifiers::NONE); break; case lexer::TokenType::KEYW_ASYNC: if ((lexer_->GetToken().Flags() & lexer::TokenFlags::HAS_ESCAPE) == 0) { lexer_->NextToken(); // eat `async` declNode = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); break; } [[fallthrough]]; default: declNode = ParseExpression(); eatSemicolon = true; break; } break; default: declNode = ParseExpression(); eatSemicolon = true; break; } ES2PANDA_ASSERT(declNode != nullptr); lexer::SourcePosition endLoc = declNode->End(); auto *exportDeclaration = AllocNode(declNode, isExportEquals); ES2PANDA_ASSERT(exportDeclaration != nullptr); exportDeclaration->SetRange({startLoc, endLoc}); if (eatSemicolon) { ConsumeSemicolon(exportDeclaration); } return exportDeclaration; } ir::Identifier *ParserImpl::ParseNamedExport(lexer::Token *exportedToken) { if (exportedToken->Type() != lexer::TokenType::LITERAL_IDENT) { // test exists for js and ts extensions LogError(diagnostic::UNEXPECTED_TOKEN_ID); exportedToken->SetTokenType(lexer::TokenType::LITERAL_IDENT); exportedToken->SetTokenStr(ERROR_LITERAL); } CheckRestrictedBinding(exportedToken->KeywordType()); const util::StringView &exportedString = exportedToken->Ident(); auto *exported = AllocNode(exportedString, Allocator()); ES2PANDA_ASSERT(exported != nullptr); exported->SetRange(exportedToken->Loc()); return exported; } ir::ExportAllDeclaration *ParserImpl::ParseExportAllDeclaration(const lexer::SourcePosition &startLoc) { lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat `*` character ir::Identifier *exported = nullptr; if (CheckModuleAsModifier()) { lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); exported = ParseNamedExport(&lexer_->GetToken()); lexer_->NextToken(); // eat exported name } ir::StringLiteral *source = ParseFromClause(); ES2PANDA_ASSERT(source != nullptr); lexer::SourcePosition endLoc = source->End(); auto *exportDeclaration = AllocNode(source, exported); ES2PANDA_ASSERT(exportDeclaration != nullptr); exportDeclaration->SetRange({startLoc, endLoc}); ConsumeSemicolon(exportDeclaration); return exportDeclaration; } ir::ExportNamedDeclaration *ParserImpl::ParseExportNamedSpecifiers(const lexer::SourcePosition &startLoc) { lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat `{` character ArenaVector specifiers(Allocator()->Adapter()); lexer::SourcePosition endPos; ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT, [this, &specifiers]() { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { // test exists for ts extension only LogExpectedToken(lexer::TokenType::LITERAL_IDENT); } lexer::Token localToken = lexer_->GetToken(); auto *local = AllocNode(lexer_->GetToken().Ident(), Allocator()); local->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); // eat local name ir::Identifier *exported = nullptr; if (CheckModuleAsModifier()) { lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat `as` literal exported = ParseNamedExport(&lexer_->GetToken()); lexer_->NextToken(); // eat exported name } else { exported = ParseNamedExport(&localToken); } if (exported != nullptr) { // Error processing. auto *specifier = AllocNode(local, exported); specifier->SetRange({local->Start(), exported->End()}); specifiers.push_back(specifier); } return true; }, &endPos, true); ir::StringLiteral *source = nullptr; if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM) { source = ParseFromClause(); } auto *exportDeclaration = AllocNode(Allocator(), source, std::move(specifiers)); ES2PANDA_ASSERT(exportDeclaration != nullptr); exportDeclaration->SetRange({startLoc, endPos}); ConsumeSemicolon(exportDeclaration); return exportDeclaration; } ir::Statement *ParserImpl::ParseNamedExportDeclaration(const lexer::SourcePosition &startLoc) { ir::Statement *decl = nullptr; switch (lexer_->GetToken().Type()) { case lexer::TokenType::KEYW_VAR: decl = ParseVariableDeclaration(VariableParsingFlags::VAR); break; case lexer::TokenType::KEYW_CONST: decl = ParseVariableDeclaration(VariableParsingFlags::CONST); break; case lexer::TokenType::KEYW_LET: decl = ParseVariableDeclaration(VariableParsingFlags::LET); break; case lexer::TokenType::KEYW_FUNCTION: decl = ParseFunctionDeclaration(false, ParserStatus::NO_OPTS); break; case lexer::TokenType::KEYW_CLASS: decl = ParseClassDeclaration(ir::ClassDefinitionModifiers::ID_REQUIRED); break; case lexer::TokenType::LITERAL_IDENT: if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_STRUCT) { decl = ParseStructDeclaration(ir::ClassDefinitionModifiers::NONE); break; } [[fallthrough]]; default: if (!lexer_->GetToken().IsAsyncModifier()) { LogExpectedToken(lexer::TokenType::KEYW_ASYNC); } lexer_->NextToken(); // eat `async` keyword if (lexer_->GetToken().Type() != lexer::TokenType::KEYW_FUNCTION) { LogExpectedToken(lexer::TokenType::KEYW_FUNCTION); return AllocBrokenStatement(Lexer()->GetToken().Loc()); } decl = ParseFunctionDeclaration(false, ParserStatus::ASYNC_FUNCTION); break; } ES2PANDA_ASSERT(decl != nullptr); if (decl->IsVariableDeclaration()) { ConsumeSemicolon(decl); } lexer::SourcePosition endLoc = decl->End(); ArenaVector specifiers(Allocator()->Adapter()); auto *exportDeclaration = AllocNode(Allocator(), decl, std::move(specifiers)); ES2PANDA_ASSERT(exportDeclaration != nullptr); exportDeclaration->SetRange({startLoc, endLoc}); return exportDeclaration; } ir::Statement *ParserImpl::ParseExportDeclaration(StatementParsingFlags flags) { if ((flags & StatementParsingFlags::GLOBAL) == 0) { LogError(diagnostic::IMPORT_EXPORT_ONLY_AT_TOP_LEVEL); } if (!context_.IsModule()) { LogError(diagnostic::IMPORT_META_ONLY_MODULE); } lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); // eat `export` keyword switch (lexer_->GetToken().Type()) { case lexer::TokenType::PUNCTUATOR_MULTIPLY: { return ParseExportAllDeclaration(startLoc); } case lexer::TokenType::PUNCTUATOR_LEFT_BRACE: { return ParseExportNamedSpecifiers(startLoc); } default: { if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_DEFAULT) { return ParseExportDefaultDeclaration(startLoc); } return ParseNamedExportDeclaration(startLoc); } } } void ParserImpl::ParseNameSpaceImport(ArenaVector *specifiers) { lexer::SourcePosition namespaceStart = lexer_->GetToken().Start(); lexer_->NextToken(); // eat `*` character if (!CheckModuleAsModifier()) { LogExpectedToken(lexer::TokenType::KEYW_AS); } lexer_->NextToken(); // eat `as` literal ir::Identifier *local = ParseNamedImport(&lexer_->GetToken()); auto *specifier = AllocNode(local); ES2PANDA_ASSERT(specifier != nullptr); specifier->SetRange({namespaceStart, lexer_->GetToken().End()}); specifiers->push_back(specifier); lexer_->NextToken(); // eat local name } ir::Identifier *ParserImpl::ParseNamedImport(lexer::Token *importedToken) { if (importedToken->Type() != lexer::TokenType::LITERAL_IDENT) { LogError(diagnostic::UNEXPECTED_TOKEN_ID); importedToken->SetTokenType(lexer::TokenType::LITERAL_IDENT); importedToken->SetTokenStr(ERROR_LITERAL); } CheckRestrictedBinding(importedToken->KeywordType()); auto *local = AllocNode(importedToken->Ident(), Allocator()); ES2PANDA_ASSERT(local != nullptr); local->SetRange(importedToken->Loc()); return local; } void ParserImpl::ParseNamedImportSpecifiers(ArenaVector *specifiers) { lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT); // eat `{` character ParseList( lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT, [this, specifiers]() { if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) { // test exists for ts extension only LogExpectedToken(lexer::TokenType::LITERAL_IDENT); } lexer::Token importedToken = lexer_->GetToken(); auto *imported = AllocNode(importedToken.Ident(), Allocator()); ir::Identifier *local = nullptr; imported->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); // eat import name if (CheckModuleAsModifier()) { lexer_->NextToken(); // eat `as` literal local = ParseNamedImport(&lexer_->GetToken()); lexer_->NextToken(); // eat local name } else { local = ParseNamedImport(&importedToken); } auto *specifier = AllocNode(imported, local); specifier->SetRange({imported->Start(), local->End()}); specifiers->push_back(specifier); return true; }, nullptr, true); } ir::AstNode *ParserImpl::ParseImportDefaultSpecifier(ArenaVector *specifiers) { ir::Identifier *local = ParseNamedImport(&lexer_->GetToken()); lexer_->NextToken(); // eat local name auto *specifier = AllocNode(local); ES2PANDA_ASSERT(specifier != nullptr); specifier->SetRange(specifier->Local()->Range()); specifiers->push_back(specifier); lexer_->NextToken(); // eat specifier name if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) { lexer_->NextToken(); // eat comma } return nullptr; } ir::StringLiteral *ParserImpl::ParseFromClause(bool requireFrom) { if (lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM) { // unexpected_token_5.ts if (requireFrom) { LogExpectedToken(lexer::TokenType::KEYW_FROM); lexer_->NextToken(); // eat `from` literal } } else { lexer_->NextToken(); // eat `from` literal } if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { // test exists for ts extension only LogExpectedToken(lexer::TokenType::LITERAL_STRING); lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_STRING); lexer_->GetToken().SetTokenStr(ERROR_LITERAL); } auto *source = AllocNode(lexer_->GetToken().String()); ES2PANDA_ASSERT(source != nullptr); source->SetRange(lexer_->GetToken().Loc()); lexer_->NextToken(); return source; } ir::AstNode *ParserImpl::ParseImportSpecifiers(ArenaVector *specifiers) { ES2PANDA_ASSERT(specifiers->empty()); if (lexer_->GetToken().Type() == lexer::TokenType::LITERAL_IDENT) { ir::AstNode *astNode = ParseImportDefaultSpecifier(specifiers); if (astNode != nullptr) { return astNode; } } if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MULTIPLY) { ParseNameSpaceImport(specifiers); } else if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { ParseNamedImportSpecifiers(specifiers); } return nullptr; } ir::Statement *ParserImpl::ParseImportDeclaration(StatementParsingFlags flags) { if ((flags & StatementParsingFlags::GLOBAL) == 0) { LogError(diagnostic::IMPORT_EXPORT_ONLY_AT_TOP_LEVEL); } if (!context_.IsModule()) { LogError(diagnostic::IMPORT_META_ONLY_MODULE); } char32_t nextChar = lexer_->Lookahead(); if (nextChar == lexer::LEX_CHAR_LEFT_PAREN || nextChar == lexer::LEX_CHAR_DOT) { return ParseExpressionStatement(); } lexer::SourcePosition startLoc = lexer_->GetToken().Start(); lexer_->NextToken(); // eat import ArenaVector specifiers(Allocator()->Adapter()); ir::StringLiteral *source = nullptr; if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_STRING) { ParseImportSpecifiers(&specifiers); source = ParseFromClause(true); } else { source = ParseFromClause(false); } ES2PANDA_ASSERT(source != nullptr); lexer::SourcePosition endLoc = source->End(); auto *importDeclaration = AllocNode(source, std::move(specifiers)); ES2PANDA_ASSERT(importDeclaration != nullptr); importDeclaration->SetRange({startLoc, endLoc}); ConsumeSemicolon(importDeclaration); return importDeclaration; } ir::Statement *ParserImpl::AllocBrokenStatement(const lexer::SourcePosition &pos) { return AllocBrokenStatement({pos, pos}); } ir::Statement *ParserImpl::AllocBrokenStatement(const lexer::SourceRange &range) { auto *broken = AllocNode(true); ES2PANDA_ASSERT(broken != nullptr); broken->SetRange(range); return broken; } bool ParserImpl::IsBrokenStatement(ir::Statement *st) { if (st->IsEmptyStatement()) { return st->AsEmptyStatement()->IsBrokenStatement(); } return false; } ir::Statement *ParserImpl::AllocEmptyStatement() { auto *empty = AllocNode(); ES2PANDA_ASSERT(empty != nullptr); empty->SetRange(lexer_->GetToken().Loc()); return empty; } } // namespace ark::es2panda::parser