1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#ifndef ES2PANDA_EVALUATE_HELPERS_H 17#define ES2PANDA_EVALUATE_HELPERS_H 18 19#include "checker/ETSchecker.h" 20#include "evaluate/varbinderScopes.h" 21#include "ir/astNodeFlags.h" 22#include "varbinder/ETSBinder.h" 23 24#include "libpandafile/field_data_accessor.h" 25#include "libpandafile/method_data_accessor.h" 26#include "libpandafile/class_data_accessor.h" 27#include "libpandafile/file.h" 28#include "type.h" 29 30#include <optional> 31#include <string> 32 33namespace ark::es2panda::checker { 34class Type; 35} // namespace ark::es2panda::checker 36 37namespace ark::es2panda::ir { 38class BlockStatement; 39class Identifier; 40class TypeNode; 41class ETSTypeReference; 42class ClassProperty; 43} // namespace ark::es2panda::ir 44 45namespace ark::es2panda::parser { 46class Program; 47} // namespace ark::es2panda::parser 48 49namespace ark::es2panda::evaluate::helpers { 50 51class SafeStateScope final { 52public: 53 explicit SafeStateScope(checker::ETSChecker *checker, varbinder::ETSBinder *varBinder); 54 55 ~SafeStateScope(); 56 57 NO_COPY_SEMANTIC(SafeStateScope); 58 NO_MOVE_SEMANTIC(SafeStateScope); 59 60 void *operator new(size_t) = delete; 61 void *operator new[](size_t) = delete; 62 63private: 64 checker::ETSChecker *checker_ {nullptr}; 65 varbinder::ETSBinder *varBinder_ {nullptr}; 66 varbinder::Scope *checkerScope_ {nullptr}; 67 varbinder::GlobalScope *binderTopScope_ {nullptr}; 68 varbinder::VariableScope *binderVarScope_ {nullptr}; 69 varbinder::Scope *binderScope_ {nullptr}; 70 parser::Program *binderProgram_ {nullptr}; 71 varbinder::RecordTable *recordTable_ {nullptr}; 72}; 73 74static inline constexpr std::string_view DEBUGGER_API_CLASS_NAME = "DebuggerAPI"; 75 76// CC-OFFNXT(G.PRE.02-CPP) code generation 77// CC-OFFNXT(G.PRE.06) solid logic 78// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 79#define TYPED_ACCESSOR_NAME_SWITCH(TYPE_NAME_BASE) \ 80 do { \ 81 switch (typeId) { \ 82 case panda_file::Type::TypeId::U1: \ 83 /* CC-OFFNXT(G.PRE.05) function gen */ \ 84 return #TYPE_NAME_BASE "Boolean"; \ 85 case panda_file::Type::TypeId::I8: \ 86 /* CC-OFFNXT(G.PRE.05) function gen */ \ 87 return #TYPE_NAME_BASE "Byte"; \ 88 case panda_file::Type::TypeId::U16: \ 89 /* CC-OFFNXT(G.PRE.05) function gen */ \ 90 return #TYPE_NAME_BASE "Char"; \ 91 case panda_file::Type::TypeId::I16: \ 92 /* CC-OFFNXT(G.PRE.05) function gen */ \ 93 return #TYPE_NAME_BASE "Short"; \ 94 case panda_file::Type::TypeId::I32: \ 95 /* CC-OFFNXT(G.PRE.05) function gen */ \ 96 return #TYPE_NAME_BASE "Int"; \ 97 case panda_file::Type::TypeId::I64: \ 98 /* CC-OFFNXT(G.PRE.05) function gen */ \ 99 return #TYPE_NAME_BASE "Long"; \ 100 case panda_file::Type::TypeId::F32: \ 101 /* CC-OFFNXT(G.PRE.05) function gen */ \ 102 return #TYPE_NAME_BASE "Float"; \ 103 case panda_file::Type::TypeId::F64: \ 104 /* CC-OFFNXT(G.PRE.05) function gen */ \ 105 return #TYPE_NAME_BASE "Double"; \ 106 case panda_file::Type::TypeId::REFERENCE: \ 107 /* CC-OFFNXT(G.PRE.05) function gen */ \ 108 return #TYPE_NAME_BASE "Object"; \ 109 default: \ 110 UNREACHABLE(); \ 111 /* CC-OFFNXT(G.PRE.05) function gen */ \ 112 return {}; \ 113 } \ 114 /* CC-OFFNXT(G.PRE.05) function gen */ \ 115 return {}; \ 116 } while (false) 117 118constexpr inline std::string_view CreateGetterName(panda_file::Type::TypeId typeId) 119{ 120 TYPED_ACCESSOR_NAME_SWITCH(getLocal); 121} 122 123constexpr inline std::string_view CreateSetterName(panda_file::Type::TypeId typeId) 124{ 125 TYPED_ACCESSOR_NAME_SWITCH(setLocal); 126} 127 128#undef TYPED_ACCESSOR_NAME_SWITCH 129 130template <typename F> 131void DoScopedAction(checker::ETSChecker *checker, varbinder::ETSBinder *varBinder, parser::Program *program, 132 varbinder::Scope *scope, ir::AstNode *parentClass, F &&action) 133{ 134 ASSERT(checker); 135 ASSERT(varBinder); 136 // Must enter either program global scope or a local scope. 137 ASSERT(program != nullptr || scope != nullptr); 138 139 SafeStateScope s(checker, varBinder); 140 141 auto runInScope = [checker, varBinder, scope, parentClass](auto &&f) { 142 RecordTableClassScope recordTableScope(varBinder, parentClass); 143 if (scope != nullptr) { 144 auto lexScope = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, scope); 145 checker::ScopeContext checkerScope(checker, scope); 146 f(); 147 } else { 148 f(); 149 } 150 }; 151 152 if (program != nullptr && program != varBinder->Program()) { 153 // Save checker scope because it can differ from VarBinder's scope. 154 checker::ScopeContext savedCheckerScope(checker, checker->Scope()); 155 { 156 ProgramScope rcScope(varBinder, program); 157 checker->Initialize(varBinder); 158 159 runInScope(std::forward<F>(action)); 160 } 161 // Switch checker's state back after leaving another program's context. 162 checker->Initialize(varBinder); 163 } else { 164 runInScope(std::forward<F>(action)); 165 } 166} 167 168ir::TypeNode *ToTypeNode(std::string_view typeSignature, checker::ETSChecker *checker); 169 170ir::TypeNode *PandaTypeToTypeNode(const panda_file::File &pf, panda_file::FieldDataAccessor &fda, 171 checker::ETSChecker *checker); 172 173ir::TypeNode *PandaTypeToTypeNode(const panda_file::File &pf, panda_file::Type pandaType, 174 panda_file::File::EntityId classId, checker::ETSChecker *checker); 175 176std::optional<std::string> ToTypeName(std::string_view typeSignature, checker::GlobalTypesHolder *globalTypes); 177 178panda_file::Type::TypeId GetTypeId(std::string_view typeSignature); 179 180ir::BlockStatement *GetEnclosingBlock(ir::Identifier *ident); 181 182template <typename AccessorType> 183ir::ModifierFlags GetModifierFlags(AccessorType &da, bool forceAddPublicFlag) 184{ 185 auto flags = ir::ModifierFlags::NONE; 186 if (da.IsStatic()) { 187 flags |= ir::ModifierFlags::STATIC; 188 } 189 if (da.IsFinal()) { 190 flags |= ir::ModifierFlags::FINAL; 191 } 192 193 if (forceAddPublicFlag) { 194 flags |= ir::ModifierFlags::PUBLIC; 195 } else { 196 if (da.IsPublic()) { 197 flags |= ir::ModifierFlags::PUBLIC; 198 } 199 if (da.IsProtected()) { 200 flags |= ir::ModifierFlags::PROTECTED; 201 } 202 if (da.IsPrivate()) { 203 flags |= ir::ModifierFlags::PRIVATE; 204 } 205 } 206 207 if constexpr (std::is_same_v<AccessorType, panda_file::FieldDataAccessor>) { 208 if (da.IsReadonly()) { 209 flags |= ir::ModifierFlags::READONLY; 210 } 211 } else if constexpr (std::is_same_v<AccessorType, panda_file::MethodDataAccessor>) { 212 if (da.IsNative()) { 213 flags |= ir::ModifierFlags::NATIVE; 214 } 215 if (da.IsAbstract()) { 216 flags |= ir::ModifierFlags::ABSTRACT; 217 } 218 } else { 219 LOG(FATAL, ES2PANDA) << "Should be passed only reference on FieldDataAccessor or MethodDataAccessor."; 220 } 221 222 return flags; 223} 224 225ir::ModifierFlags GetModifierFlags(panda_file::ClassDataAccessor &da); 226 227// Adds `extProgram` into external programs list of the given `program`. 228void AddExternalProgram(parser::Program *program, parser::Program *extProgram, std::string_view moduleName); 229 230ir::ETSTypeReference *CreateETSTypeReference(checker::ETSChecker *checker, util::StringView name); 231 232std::pair<std::string_view, std::string_view> SplitRecordName(std::string_view recordName); 233 234ir::ClassProperty *CreateClassProperty(checker::ETSChecker *checker, std::string_view name, ir::TypeNode *type, 235 ir::ModifierFlags modifiers); 236 237} // namespace ark::es2panda::evaluate::helpers 238 239#endif // ES2PANDA_EVALUATE_HELPERS_H 240