* Copyright (c) 2021-2026 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 "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;
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);
}
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:
if (lexer_->Lookahead() == static_cast<char32_t>(STATEMENT_FORMAT_NODE)) {
return ParseStatementFormatPlaceholder();
}
[[fallthrough]];
default:
return ParseExpressionStatement(flags);
}
}
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);
}
}
ir::Statement *ParserImpl::ParseStatement(StatementParsingFlags flags)
{
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 ParseEnumStatement(flags);
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::ParseInitModuleStatement()
{
ES2PANDA_UNREACHABLE();
}
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()) {
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()) {
return variableDecl;
}
variableDecl->SetStart(constVarStar);
ConsumeSemicolon(variableDecl);
return variableDecl;
}
ir::EmptyStatement *ParserImpl::ParseEmptyStatement()
{
auto *empty = AllocNode<ir::EmptyStatement>();
ES2PANDA_ASSERT(empty != nullptr);
empty->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return empty;
}
ir::Statement *ParserImpl::ParseDebuggerStatement()
{
auto *debuggerNode = AllocNode<ir::DebuggerStatement>();
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<ir::Statement *> stmts(Allocator()->Adapter());
stmts.push_back(funcDecl);
auto *localBlockStmt = AllocNode<ir::BlockStatement>(Allocator(), std::move(stmts));
ES2PANDA_ASSERT(localBlockStmt != nullptr);
localBlockStmt->SetRange(funcDecl->Range());
return funcDecl;
}
ir::Statement *ParserImpl::ParsePotentialExpressionStatement(StatementParsingFlags flags)
{
return ParseExpressionStatement(flags);
}
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);
}
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::ParseEnumStatement(StatementParsingFlags flags)
{
if ((flags & StatementParsingFlags::ALLOW_LEXICAL) == 0) {
LogError(diagnostic::LEXICAL_DEC_NOT_ALLOWED_IN_SINGLE_STATEMENT_CONTEXT);
}
return ParseEnumDeclaration();
}
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) {
return AllocBrokenStatement(Lexer()->GetToken().Loc());
}
lexer::SourcePosition endLoc = classDefinition->End();
auto *structDecl = AllocNode<ir::ETSStructDeclaration>(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) {
return AllocBrokenStatement(Lexer()->GetToken().Loc());
}
lexer::SourcePosition endLoc = classDefinition->End();
auto *classDecl = AllocNode<ir::ClassDeclaration>(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<ir::Statement *> ParserImpl::ParseStatementList(StatementParsingFlags flags)
{
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_FORMAT &&
lexer_->Lookahead() == static_cast<char32_t>(ARRAY_FORMAT_NODE)) {
return std::move(ParseStatementsArrayFormatPlaceholder());
}
ArenaVector<ir::Statement *> 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<ir::Statement *> *statements)
{
ES2PANDA_ASSERT(lexer_->GetToken().Type() == lexer::TokenType::LITERAL_STRING);
const util::StringView &str = lexer_->GetToken().String();
const auto status = static_cast<ParserStatus>(
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) {
return false;
}
bool isDirective = exprNode->IsStringLiteral();
auto *exprStatement = AllocNode<ir::ExpressionStatement>(exprNode);
ES2PANDA_ASSERT(exprStatement != nullptr);
exprStatement->SetRange(exprNode->Range());
ConsumeSemicolon(exprStatement);
statements->push_back(exprStatement);
return isDirective;
}
void ParserImpl::ParseDirectivePrologue(ArenaVector<ir::Statement *> *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<ir::BlockStatement>(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<ir::BreakStatement>();
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<ir::Identifier>(label, Allocator());
ES2PANDA_ASSERT(identNode != nullptr);
identNode->SetRange(lexer_->GetToken().Loc());
auto *breakStatement = AllocNode<ir::BreakStatement>(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<ir::ContinueStatement>();
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<ir::ContinueStatement>();
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<ir::Identifier>(label, Allocator());
ES2PANDA_ASSERT(identNode != nullptr);
identNode->SetRange(lexer_->GetToken().Loc());
auto *continueStatement = AllocNode<ir::ContinueStatement>(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) {
LogError(diagnostic::UNEXPECTED_TOKEN_WHILE);
} else {
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<ir::DoWhileStatement>(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<ir::FunctionDeclaration>(Allocator(), func, true);
ES2PANDA_ASSERT(funcDecl != nullptr);
funcDecl->SetRange(func->Range());
return funcDecl;
}
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<ir::FunctionDeclaration>(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)
{
if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_INIT_MODULE && IsETSParser()) {
return ParseInitModuleStatement();
}
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());
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<ir::ExpressionStatement>(exprNode);
ES2PANDA_ASSERT(exprStatementNode != nullptr);
exprStatementNode->SetRange({startPos.GetToken().Start(), endPos});
ConsumeSemicolon(exprStatementNode);
return exprStatementNode;
}
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;
std::tuple<ForStatementKind, ir::Expression *, ir::Expression *> 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()) {
ES2PANDA_ASSERT(initNode != nullptr);
if (!initNode->IsVariableDeclaration()) {
LogError(diagnostic::INVALID_LEFT_HAND_IN_FOR_OF, {}, lexer_->GetToken().Start());
return {forKind, rightNode, updateNode};
}
if (initNode->AsVariableDeclaration()->Declarators().empty()) {
LogError(diagnostic::INVALID_LEFT_HAND_IN_FOR_OF, {}, initNode->Start());
return {forKind, rightNode, updateNode};
}
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<ForStatementKind, ir::AstNode *, ir::Expression *, ir::Expression *> 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<ForStatementKind, ir::AstNode *, ir::Expression *, ir::Expression *> ParserImpl::ParseForInOf(
ir::Expression *leftNode, ExpressionParseFlags exprFlags, bool isAwait)
{
ES2PANDA_ASSERT(lexer_ != nullptr);
ES2PANDA_ASSERT(leftNode != nullptr);
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());
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<ir::Expression *, ir::Expression *> 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<ir::Expression *, ir::Statement *> 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 ) {
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->IsVariableDeclaration()) {
LogError(diagnostic::INVALID_LEFT_HAND_IN_FOR_OF);
} 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<ir::ForUpdateStatement>(nodes.init, nodes.right, nodes.update, nodes.body);
} else {
if (nodes.init == nullptr || nodes.right == nullptr) {
return AllocBrokenStatement(Lexer()->GetToken().Loc());
}
if (forKind == ForStatementKind::IN) {
forStatement = AllocNode<ir::ForInStatement>(nodes.init, nodes.right, nodes.body);
} else {
forStatement = AllocNode<ir::ForOfStatement>(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_);
if (!GetCanBeForInOf(leftNode, initNode)) {
std::tie(rightNode, updateNode) = ParseForUpdate(isAwait);
} else if (leftNode != nullptr) {
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
LogError(diagnostic::INVALID_TYPE_ANNOTATION_IN_FOR);
lexer_->NextToken();
}
std::tie(forKind, initNode, rightNode, updateNode) =
ParseForInOf(leftNode, ExpressionParseFlags::NO_OPTS, isAwait);
} else if (initNode != nullptr) {
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();
alternate = ParseStatement(StatementParsingFlags::IF_ELSE | StatementParsingFlags::ALLOW_LEXICAL);
if (alternate != nullptr) {
endLoc = alternate->End();
}
}
auto *ifStatement = AllocNode<ir::IfStatement>(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<ir::Identifier>(actualLabel, Allocator());
ES2PANDA_ASSERT(identNode != nullptr);
identNode->SetRange(pos.GetToken().Loc());
lexer_->NextToken();
if (!ValidateLabeledStatement(Lexer()->GetToken().Type())) {
return AllocBrokenStatement(Lexer()->GetToken().Loc());
}
ir::Statement *body = ParseStatement(StatementParsingFlags::LABELLED);
auto *labeledStatement = AllocNode<ir::LabelledStatement>(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) {
endLoc = expression->End();
}
returnStatement = AllocNode<ir::ReturnStatement>(expression);
} else {
returnStatement = AllocNode<ir::ReturnStatement>();
}
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();
testExpr = ParseExpression(ExpressionParseFlags::ACCEPT_COMMA);
break;
}
case lexer::TokenType::KEYW_DEFAULT: {
if (*seenDefault) {
ReportMultipleDefaultError();
}
*seenDefault = true;
lexer_->NextToken();
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<ir::Statement *> 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<ir::SwitchCaseStatement>(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<ir::SwitchCaseStatement *> 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<ir::SwitchStatement>(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<ir::ThrowStatement>(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();
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) {
ParseCatchParamTypeAnnotation(param);
}
ExpectToken(lexer::TokenType::PUNCTUATOR_RIGHT_PARENTHESIS);
return param;
}
ir::CatchClause *ParserImpl::ParseCatchClause()
{
lexer::SourcePosition catchStartLoc = lexer_->GetToken().Start();
lexer_->NextToken();
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<ir::CatchClause>(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();
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) {
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<ir::CatchClause *> 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();
finallyClause = ParseBlockStatement();
ES2PANDA_ASSERT(finallyClause != nullptr);
endLoc = finallyClause->End();
}
ArenaVector<std::pair<compiler::LabelPair, const ir::Statement *>> finalizerInsertions(Allocator()->Adapter());
auto *tryStatement = AllocNode<ir::TryStatement>(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();
auto exprFlags = ((flags & VariableParsingFlags::STOP_AT_IN) != 0 ? ExpressionParseFlags::STOP_AT_IN
: ExpressionParseFlags::NO_OPTS);
ir::Expression *initializer = ParseExpression(exprFlags);
if (initializer == nullptr) {
return nullptr;
}
if (InAmbientContext()) {
LogError(diagnostic::INITIALIZERS_IN_AMBIENT_CONTEXTS, {init->AsIdentifier()->Name()}, initializer->Start());
}
lexer::SourcePosition endLoc = initializer->End();
auto *declarator = AllocNode<ir::VariableDeclarator>(GetFlag(flags), init, initializer);
declarator->SetRange({startLoc, endLoc});
return declarator;
}
ir::Expression *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<VariableParsingFlags>(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<ir::VariableDeclarator>(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) {
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<ir::VariableDeclarator *> declarators(Allocator()->Adapter());
while (true) {
ir::VariableDeclarator *declarator = ParseVariableDeclarator(flags);
if (declarator != nullptr) {
declarators.push_back(declarator);
if (declarator->Init() != nullptr && declarator->Init()->IsETSClassLiteral()) {
ParseClassBody({});
LogError(diagnostic::UNSUPPORTED_CLASS_LITERAL);
return AllocBrokenStatement(declarator->Init()->Start());
}
}
if (lexer_->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COMMA) {
break;
}
lexer_->NextToken();
}
if (declarators.empty()) {
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<ir::VariableDeclaration>(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<ir::WhileStatement>(condition, body);
ES2PANDA_ASSERT(whileStatement != nullptr);
whileStatement->SetRange({startLoc, endLoc});
return whileStatement;
}
ir::ExportDefaultDeclaration *ParserImpl::ParseExportDefaultDeclaration(const lexer::SourcePosition &startLoc,
bool isExportEquals)
{
lexer_->NextToken();
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();
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<ir::ExportDefaultDeclaration>(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) {
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<ir::Identifier>(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);
ir::Identifier *exported = nullptr;
if (CheckModuleAsModifier()) {
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
exported = ParseNamedExport(&lexer_->GetToken());
lexer_->NextToken();
}
ir::StringLiteral *source = ParseFromClause();
ES2PANDA_ASSERT(source != nullptr);
lexer::SourcePosition endLoc = source->End();
auto *exportDeclaration = AllocNode<ir::ExportAllDeclaration>(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);
ArenaVector<ir::ExportSpecifier *> specifiers(Allocator()->Adapter());
lexer::SourcePosition endPos;
ParseList(
lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT,
[this, &specifiers](bool &) {
if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogExpectedToken(lexer::TokenType::LITERAL_IDENT);
}
lexer::Token localToken = lexer_->GetToken();
auto *local = AllocNode<ir::Identifier>(lexer_->GetToken().Ident(), Allocator());
local->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
ir::Identifier *exported = nullptr;
if (CheckModuleAsModifier()) {
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
exported = ParseNamedExport(&lexer_->GetToken());
lexer_->NextToken();
} else {
exported = ParseNamedExport(&localToken);
}
if (exported != nullptr) {
auto *specifier = AllocNode<ir::ExportSpecifier>(local, exported);
specifier->SetRange({local->Start(), exported->End()});
specifiers.push_back(specifier);
}
return true;
},
&endPos, ParseListOptions::ALLOW_TRAILING_SEP);
ir::StringLiteral *source = nullptr;
if (lexer_->GetToken().KeywordType() == lexer::TokenType::KEYW_FROM) {
source = ParseFromClause();
}
auto *exportDeclaration = AllocNode<ir::ExportNamedDeclaration>(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();
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<ir::ExportSpecifier *> specifiers(Allocator()->Adapter());
auto *exportDeclaration = AllocNode<ir::ExportNamedDeclaration>(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();
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<ir::AstNode *> *specifiers)
{
lexer::SourcePosition namespaceStart = lexer_->GetToken().Start();
lexer_->NextToken();
if (!CheckModuleAsModifier()) {
LogExpectedToken(lexer::TokenType::KEYW_AS);
}
lexer_->NextToken();
ir::Identifier *local = ParseNamedImport(&lexer_->GetToken());
auto *specifier = AllocNode<ir::ImportNamespaceSpecifier>(local);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange({namespaceStart, lexer_->GetToken().End()});
specifiers->push_back(specifier);
lexer_->NextToken();
}
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<ir::Identifier>(importedToken->Ident(), Allocator());
ES2PANDA_ASSERT(local != nullptr);
local->SetRange(importedToken->Loc());
return local;
}
void ParserImpl::ParseNamedImportSpecifiers(ArenaVector<ir::AstNode *> *specifiers)
{
lexer_->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
ParseList(
lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT,
[this, specifiers](bool &) {
if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_IDENT) {
LogExpectedToken(lexer::TokenType::LITERAL_IDENT);
}
lexer::Token importedToken = lexer_->GetToken();
auto *imported = AllocNode<ir::Identifier>(importedToken.Ident(), Allocator());
ir::Identifier *local = nullptr;
imported->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
if (CheckModuleAsModifier()) {
lexer_->NextToken();
local = ParseNamedImport(&lexer_->GetToken());
lexer_->NextToken();
} else {
local = ParseNamedImport(&importedToken);
}
auto *specifier = AllocNode<ir::ImportSpecifier>(imported, local);
specifier->SetRange({imported->Start(), local->End()});
specifiers->push_back(specifier);
return true;
},
nullptr, ParseListOptions::ALLOW_TRAILING_SEP);
}
ir::AstNode *ParserImpl::ParseImportDefaultSpecifier(ArenaVector<ir::AstNode *> *specifiers)
{
ir::Identifier *local = ParseNamedImport(&lexer_->GetToken());
lexer_->NextToken();
auto *specifier = AllocNode<ir::ImportDefaultSpecifier>(local);
ES2PANDA_ASSERT(specifier != nullptr);
specifier->SetRange(specifier->Local()->Range());
specifiers->push_back(specifier);
lexer_->NextToken();
if (lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COMMA) {
lexer_->NextToken();
}
return nullptr;
}
ir::StringLiteral *ParserImpl::ParseFromClause(bool requireFrom)
{
if (lexer_->GetToken().KeywordType() != lexer::TokenType::KEYW_FROM) {
if (requireFrom) {
LogExpectedToken(lexer::TokenType::KEYW_FROM);
lexer_->NextToken();
}
} else {
lexer_->NextToken();
}
if (lexer_->GetToken().Type() != lexer::TokenType::LITERAL_STRING) {
LogExpectedToken(lexer::TokenType::LITERAL_STRING);
lexer_->GetToken().SetTokenType(lexer::TokenType::LITERAL_STRING);
lexer_->GetToken().SetTokenStr(ERROR_LITERAL);
}
auto *source = AllocNode<ir::StringLiteral>(lexer_->GetToken().String());
ES2PANDA_ASSERT(source != nullptr);
source->SetRange(lexer_->GetToken().Loc());
lexer_->NextToken();
return source;
}
ir::AstNode *ParserImpl::ParseImportSpecifiers(ArenaVector<ir::AstNode *> *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();
ArenaVector<ir::AstNode *> 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<ir::ImportDeclaration>(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<ir::EmptyStatement>(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<ir::EmptyStatement>();
ES2PANDA_ASSERT(empty != nullptr);
empty->SetRange(lexer_->GetToken().Loc());
return empty;
}
}