* 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 "ETSparser.h"
#include "ETSNolintParser.h"
#include <utility>
#include "util/es2pandaMacros.h"
#include "parser/parserFlags.h"
#include "parser/parserStatusContext.h"
#include "util/helpers.h"
#include "util/language.h"
#include "varbinder/varbinder.h"
#include "varbinder/ETSBinder.h"
#include "lexer/lexer.h"
#include "lexer/ETSLexer.h"
#include "ir/astNode.h"
#include "ir/base/classDefinition.h"
#include "ir/base/decorator.h"
#include "ir/base/catchClause.h"
#include "ir/base/classProperty.h"
#include "ir/base/scriptFunction.h"
#include "ir/base/methodDefinition.h"
#include "ir/base/classStaticBlock.h"
#include "ir/base/spreadElement.h"
#include "ir/expressions/identifier.h"
#include "ir/expressions/functionExpression.h"
#include "ir/statements/functionDeclaration.h"
#include "ir/statements/expressionStatement.h"
#include "ir/statements/classDeclaration.h"
#include "ir/statements/variableDeclarator.h"
#include "ir/statements/variableDeclaration.h"
#include "ir/expressions/dummyNode.h"
#include "ir/expressions/callExpression.h"
#include "ir/expressions/thisExpression.h"
#include "ir/expressions/typeofExpression.h"
#include "ir/expressions/memberExpression.h"
#include "ir/expressions/updateExpression.h"
#include "ir/expressions/arrowFunctionExpression.h"
#include "ir/expressions/unaryExpression.h"
#include "ir/expressions/yieldExpression.h"
#include "ir/expressions/awaitExpression.h"
#include "ir/expressions/literals/nullLiteral.h"
#include "ir/expressions/literals/numberLiteral.h"
#include "ir/expressions/literals/stringLiteral.h"
#include "ir/expressions/literals/undefinedLiteral.h"
#include "ir/module/importDeclaration.h"
#include "ir/module/importDefaultSpecifier.h"
#include "ir/module/importSpecifier.h"
#include "ir/module/exportSpecifier.h"
#include "ir/module/exportNamedDeclaration.h"
#include "ir/statements/blockStatement.h"
#include "ir/statements/ifStatement.h"
#include "ir/statements/labelledStatement.h"
#include "ir/statements/switchStatement.h"
#include "ir/statements/throwStatement.h"
#include "ir/statements/tryStatement.h"
#include "ir/statements/whileStatement.h"
#include "ir/statements/forOfStatement.h"
#include "ir/statements/doWhileStatement.h"
#include "ir/statements/breakStatement.h"
#include "ir/statements/debuggerStatement.h"
#include "ir/ets/etsClassLiteral.h"
#include "ir/ets/etsPrimitiveType.h"
#include "ir/ets/etsPackageDeclaration.h"
#include "ir/ets/etsReExportDeclaration.h"
#include "ir/ets/etsNewArrayInstanceExpression.h"
#include "ir/ets/etsTuple.h"
#include "ir/ets/etsFunctionType.h"
#include "ir/ets/etsNewClassInstanceExpression.h"
#include "ir/ets/etsNewMultiDimArrayInstanceExpression.h"
#include "ir/ets/etsModule.h"
#include "ir/ets/etsTypeReference.h"
#include "ir/ets/etsTypeReferencePart.h"
#include "ir/ets/etsNullishTypes.h"
#include "ir/ets/etsUnionType.h"
#include "ir/ets/etsImportDeclaration.h"
#include "ir/ets/etsStructDeclaration.h"
#include "ir/ets/etsParameterExpression.h"
#include "ir/module/importNamespaceSpecifier.h"
#include "ir/ts/tsAsExpression.h"
#include "ir/ts/tsInterfaceDeclaration.h"
#include "ir/ts/tsEnumDeclaration.h"
#include "ir/ts/tsTypeParameterInstantiation.h"
#include "ir/ts/tsInterfaceBody.h"
#include "ir/ts/tsImportEqualsDeclaration.h"
#include "ir/ts/tsArrayType.h"
#include "ir/ts/tsQualifiedName.h"
#include "ir/ts/tsTypeReference.h"
#include "ir/ts/tsTypeParameter.h"
#include "ir/ts/tsInterfaceHeritage.h"
#include "ir/ts/tsFunctionType.h"
#include "ir/ts/tsClassImplements.h"
#include "ir/ts/tsEnumMember.h"
#include "ir/ts/tsTypeAliasDeclaration.h"
#include "ir/ts/tsTypeParameterDeclaration.h"
#include "ir/ts/tsNonNullExpression.h"
#include "ir/ts/tsThisType.h"
#include "generated/signatures.h"
#include "generated/diagnostic.h"
namespace ark::es2panda::parser {
class FunctionContext;
using namespace std::literals::string_literals;
ir::Statement *ETSParser::ParseEnumDeclaration(bool isConst, bool isStatic)
{
ES2PANDA_ASSERT(Lexer()->GetToken().Type() == lexer::TokenType::KEYW_ENUM);
lexer::SourcePosition enumStart = Lexer()->GetToken().Start();
Lexer()->NextToken();
auto *key = ExpectIdentifier(false, true);
auto *declNode = ParseEnumMembers(key, enumStart, isConst, isStatic);
if (declNode == nullptr) {
return AllocBrokenStatement(enumStart);
}
return declNode;
}
ir::Statement *ETSParser::ParsePotentialConstEnum(VariableParsingFlags flags)
{
if ((flags & VariableParsingFlags::CONST) == 0) {
LogError(diagnostic::VAR_DEC_EXPECTED);
} else {
LogError(diagnostic::UNSUPPORTED_CONST_ENUM);
}
return ParseEnumDeclaration(false);
}
ir::TSEnumDeclaration *ETSParser::ParseEnumMembers(ir::Identifier *const key, const lexer::SourcePosition &enumStart,
const bool isConst, const bool isStatic)
{
if (Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_LEFT_BRACE &&
Lexer()->GetToken().Type() != lexer::TokenType::PUNCTUATOR_COLON) {
LogExpectedToken(lexer::TokenType::PUNCTUATOR_LEFT_BRACE);
}
ir::TypeNode *typeAnnotation = nullptr;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_COLON) {
Lexer()->NextToken();
TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::REPORT_ERROR;
typeAnnotation = ParseTypeAnnotation(&options);
typeAnnotation->SetRange({Lexer()->GetToken().Start(), Lexer()->GetToken().End()});
}
Lexer()->NextToken(lexer::NextTokenFlags::KEYWORD_TO_IDENT);
ArenaVector<ir::AstNode *> members(Allocator()->Adapter());
lexer::SourcePosition enumEnd = ParseEnumMember(members);
ir::TSEnumDeclaration *enumDeclaration;
if (typeAnnotation == nullptr) {
enumDeclaration = AllocNode<ir::TSEnumDeclaration>(
Allocator(), key, std::move(members),
ir::TSEnumDeclaration::ConstructorFlags {isConst, isStatic, InAmbientContext()},
GetContext().GetLanguage());
} else {
enumDeclaration = AllocNode<ir::TSEnumDeclaration>(
Allocator(), key, std::move(members),
ir::TSEnumDeclaration::ConstructorFlags {isConst, isStatic, InAmbientContext()}, typeAnnotation,
GetContext().GetLanguage());
}
ES2PANDA_ASSERT(enumDeclaration != nullptr);
if (InAmbientContext()) {
enumDeclaration->AddModifier(ir::ModifierFlags::DECLARE);
}
enumDeclaration->SetRange({enumStart, enumEnd});
return enumDeclaration;
}
ir::Expression *ETSParser::ParseEnumExpression()
{
ir::Expression *expression {};
auto endLoc = Lexer()->GetToken().Start();
expression = ParseExpression();
if (expression == nullptr) {
LogError(diagnostic::ENUM_INVALID_INIT, {}, endLoc);
return AllocNode<ir::NumberLiteral>(lexer::Number(0));
}
return expression;
}
bool ETSParser::ParseNumberEnumHelper()
{
bool minusSign = false;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_PLUS) {
Lexer()->NextToken();
} else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_MINUS) {
minusSign = true;
Lexer()->NextToken();
}
if (Lexer()->GetToken().Type() != lexer::TokenType::LITERAL_NUMBER) {
LogError(diagnostic::INVALID_ENUM_TYPE, {}, Lexer()->GetToken().Start());
Lexer()->GetToken().SetTokenType(lexer::TokenType::LITERAL_NUMBER);
Lexer()->GetToken().SetTokenStr(ERROR_LITERAL);
}
return minusSign;
}
lexer::SourcePosition ETSParser::ParseEnumMember(ArenaVector<ir::AstNode *> &members)
{
ir::Expression *currentNumberExpr = AllocNode<ir::NumberLiteral>(lexer::Number(0));
auto const parseMember = [this, &members, ¤tNumberExpr](bool &) {
auto *const ident = ExpectIdentifier(false, true);
ir::Expression *ordinal;
lexer::SourcePosition endLoc;
bool isGenerated = false;
if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_SUBSTITUTION) {
Lexer()->NextToken();
ordinal = ParseEnumExpression();
currentNumberExpr = ordinal;
endLoc = ordinal->End();
} else {
ordinal = currentNumberExpr;
ordinal->SetRange({ident->End(), ident->End()});
isGenerated = true;
endLoc = ident->End();
}
auto *const member = AllocNode<ir::TSEnumMember>(ident, ordinal, isGenerated);
member->SetRange({ident->Start(), endLoc});
members.emplace_back(member);
auto incrementNode = AllocNode<ir::NumberLiteral>(lexer::Number(1));
ir::Expression *dummyNode = currentNumberExpr->Clone(Allocator(), nullptr)->AsExpression();
currentNumberExpr =
AllocNode<ir::BinaryExpression>(dummyNode, incrementNode, lexer::TokenType::PUNCTUATOR_PLUS);
return true;
};
lexer::SourcePosition enumEnd;
ParseList(lexer::TokenType::PUNCTUATOR_RIGHT_BRACE, lexer::NextTokenFlags::KEYWORD_TO_IDENT, parseMember, &enumEnd,
ParseListOptions::ALLOW_TRAILING_SEP);
return enumEnd;
}
}