* 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.
*/
#ifndef ES2PANDA_COMPILER_ENUM_PRE_CHECK_LOWERING_H
#define ES2PANDA_COMPILER_ENUM_PRE_CHECK_LOWERING_H
#include "compiler/lowering/phase.h"
namespace ark::es2panda::compiler {
class EnumLoweringPhase : public PhaseForAllPrograms {
public:
static constexpr std::string_view STRING_REFERENCE_TYPE {"String"};
static constexpr std::string_view STRING_TYPE {"string"};
static constexpr std::string_view NUMBER_TYPE {"number"};
static constexpr std::string_view IDENTIFIER_I {"i"};
static constexpr std::string_view PARAM_NAME {"name"};
static constexpr std::string_view PARAM_VALUE {"value"};
static constexpr std::string_view PARAM_ORDINAL {"ordinal"};
static constexpr std::string_view ITEMS_ARRAY_NAME {checker::ETSEnumType::ITEMS_ARRAY_NAME};
static constexpr std::string_view BASE_CLASS_NAME {"BaseEnum"};
static constexpr std::string_view ORDINAL_NAME {"#ordinal"};
static constexpr auto ORDINAL_TYPE {ir::PrimitiveType::INT};
enum EnumType { NOT_SPECIFIED = 0, INT = 1, LONG = 2, DOUBLE = 3, FLOAT = 4, BYTE = 5, SHORT = 6, STRING = 7 };
struct DeclarationFlags {
bool isTopLevel;
bool isLocal;
bool isNamespace;
[[nodiscard]] bool IsValid() const noexcept
{
return isTopLevel || isLocal || isNamespace;
}
};
EnumLoweringPhase() noexcept = default;
std::string_view Name() const override
{
return "EnumLoweringPhase";
}
void Setup() override
{
context_ = Context();
checker_ = Context()->GetChecker()->AsETSChecker();
varbinder_ = Context()->parserProgram->VarBinder()->AsETSBinder();
}
bool PerformForProgram(parser::Program *program) override;
checker::ETSChecker *Checker()
{
return checker_;
}
varbinder::ETSBinder *Varbinder()
{
return varbinder_;
}
private:
struct FunctionInfo {
ArenaVector<ir::Expression *> &¶ms;
ArenaVector<ir::Statement *> &&body;
ir::TypeNode *returnTypeAnnotation;
const ir::TSEnumDeclaration *enumDecl;
ir::ModifierFlags flags;
};
void LogError(const diagnostic::DiagnosticKind &diagnostic, const util::DiagnosticMessageParams &diagnosticParams,
const lexer::SourcePosition &pos);
template <EnumLoweringPhase::EnumType TYPE_NODE>
bool CheckEnumMemberType(const ArenaVector<ir::AstNode *> &enumMembers, bool &hasLoggedError, bool isAnnoted,
bool *hasLongLiteral = nullptr);
template <EnumLoweringPhase::EnumType TYPE_NODE>
void HandleIntEnumLongLiteralError(ir::TSEnumMember *member, const lexer::Number &asNumber, bool &hasLoggedError,
bool *hasLongLiteral);
[[nodiscard]] ir::ScriptFunction *MakeFunction(FunctionInfo &&functionInfo);
ir::ClassDeclaration *CreateClass(ir::TSEnumDeclaration *const enumDecl, const DeclarationFlags flags,
EnumType enumType);
ir::ClassProperty *CreateOrdinalField(ir::ClassDefinition *const enumClass);
ir::MemberExpression *CreateOrdinalAccessExpression();
void CreateCCtorForEnumClass(ir::ClassDefinition *const enumClass);
void CreateCtorForEnumClass(ir::ClassDefinition *const enumClass, ir::TypeNode *enumType);
ir::ScriptFunction *CreateFunctionForCtorOfEnumClass(ir::ClassDefinition *const enumClass, ir::TypeNode *enumType);
void ProcessEnumClassDeclaration(ir::TSEnumDeclaration *const enumDecl, const DeclarationFlags &flags,
ir::ClassDeclaration *enumClassDecl);
template <EnumType>
ir::ClassDeclaration *CreateEnumNumericClassFromEnumDeclaration(ir::TSEnumDeclaration *const enumDecl,
const DeclarationFlags flags);
static void AppendParentNames(util::UString &qualifiedName, const ir::AstNode *const node);
template <typename ElementMaker>
[[nodiscard]] ir::Identifier *MakeArray(const ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *enumClass,
const util::StringView &name, ir::TypeNode *const typeAnnotation,
ElementMaker &&elementMaker);
ir::TypeNode *CreateType(EnumLoweringPhase::EnumType enumType, ir::TSEnumDeclaration *enumDecl,
ir::ClassDefinition *parent);
void CreateEnumItemFields(const ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *enumClass,
EnumType enumType);
ir::Identifier *CreateEnumItemsArray(const ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *enumClass);
void CreateEnumGetValueOfMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass,
ir::Identifier *const itemsArrayIdent);
void CreateEnumFromValueMethod(ir::TSEnumDeclaration *const enumDecl, ir::ClassDefinition *const enumClass,
ir::Identifier *const itemsArrayIdent,
std::optional<ir::PrimitiveType> primitiveType);
void CreateEnumValuesMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass,
ir::Identifier *const itemsArrayIdent);
void CreateEnumGetOrdinalMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass);
void CreateEnumDollarGetMethod(ir::TSEnumDeclaration const *const enumDecl, ir::ClassDefinition *const enumClass);
void SetDefaultPositionInUnfilledClassNodes(const ir::ClassDeclaration *enumClassDecl,
ir::TSEnumDeclaration const *const enumDecl);
ir::Expression *CheckEnumTypeForItemFields(EnumType enumType, ir::TSEnumMember *const member);
checker::AstNodePtr TransformEnumChildrenRecursively(checker::AstNodePtr &ast);
ir::ClassDeclaration *CreateEnumClassByPrimitiveType(ir::TSEnumDeclaration *const enumDecl,
const DeclarationFlags &flags, bool &hasLoggedError,
ir::TypeNode *typeAnnotation);
checker::AstNodePtr TransformAnnotedEnumChildrenRecursively(checker::AstNodePtr &ast);
void CheckEnumInitializerConstraints(ir::TSEnumDeclaration *enumDecl);
ArenaAllocator *Allocator();
template <typename T, typename... Args>
T *AllocNode(Args &&...args);
private:
public_lib::Context *context_ {nullptr};
checker::ETSChecker *checker_ {nullptr};
parser::Program *program_ {nullptr};
varbinder::ETSBinder *varbinder_ {nullptr};
};
}
#endif