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#include "evaluate/helpers.h" 17#include "checker/types/globalTypesHolder.h" 18#include "ir/ets/etsPrimitiveType.h" 19#include "ir/ets/etsTypeReference.h" 20#include "ir/ets/etsTypeReferencePart.h" 21#include "ir/expressions/identifier.h" 22#include "ir/statements/blockStatement.h" 23#include "ir/ts/tsArrayType.h" 24#include "ir/typeNode.h" 25 26#include "assembler/assembly-type.h" 27#include "libpandafile/field_data_accessor-inl.h" 28#include "libpandafile/file-inl.h" 29 30#include <algorithm> 31#include <unordered_map> 32 33namespace ark::es2panda::evaluate::helpers { 34 35namespace { 36 37ir::TypeNode *PrimitiveToTypeNode(panda_file::Type::TypeId typeId, checker::ETSChecker *checker) 38{ 39 ir::PrimitiveType irType; 40 switch (typeId) { 41 case panda_file::Type::TypeId::VOID: 42 irType = ir::PrimitiveType::VOID; 43 break; 44 case panda_file::Type::TypeId::U1: 45 irType = ir::PrimitiveType::BOOLEAN; 46 break; 47 case panda_file::Type::TypeId::I8: 48 irType = ir::PrimitiveType::BYTE; 49 break; 50 case panda_file::Type::TypeId::U16: 51 irType = ir::PrimitiveType::CHAR; 52 break; 53 case panda_file::Type::TypeId::I16: 54 irType = ir::PrimitiveType::SHORT; 55 break; 56 case panda_file::Type::TypeId::I32: 57 irType = ir::PrimitiveType::INT; 58 break; 59 case panda_file::Type::TypeId::I64: 60 irType = ir::PrimitiveType::LONG; 61 break; 62 case panda_file::Type::TypeId::F32: 63 irType = ir::PrimitiveType::FLOAT; 64 break; 65 case panda_file::Type::TypeId::F64: 66 irType = ir::PrimitiveType::DOUBLE; 67 break; 68 default: 69 UNREACHABLE(); 70 } 71 72 return checker->AllocNode<ir::ETSPrimitiveType>(irType); 73} 74 75ir::TypeNode *ClassReferenceToTypeNode(std::string_view name, checker::ETSChecker *checker) 76{ 77 util::UString typeName(name, checker->Allocator()); 78 return CreateETSTypeReference(checker, typeName.View()); 79} 80 81ir::TypeNode *ReferenceToTypeNode(std::string_view typeSignature, checker::ETSChecker *checker) 82{ 83 ASSERT(checker); 84 ASSERT(!typeSignature.empty()); 85 switch (typeSignature[0]) { 86 case 'L': { 87 // Variable is a reference. 88 ASSERT(typeSignature.back() == ';'); 89 // Required to remove "std/core/" prefix, otherwise type name won't be parsed. 90 auto startPos = typeSignature.find_last_of('/'); 91 if (startPos == std::string_view::npos) { 92 startPos = 1; 93 } else { 94 startPos += 1; 95 } 96 return ClassReferenceToTypeNode(typeSignature.substr(startPos, typeSignature.size() - 1 - startPos), 97 checker); 98 } 99 case '[': { 100 // Variable is an array. 101 size_t rank = std::count(typeSignature.begin(), typeSignature.end(), '['); 102 auto *elementType = ToTypeNode(typeSignature.substr(rank), checker); 103 if (elementType != nullptr) { 104 for (size_t i = 0; i < rank; ++i) { 105 elementType = checker->AllocNode<ir::TSArrayType>(elementType); 106 } 107 return elementType; 108 } 109 return nullptr; 110 } 111 default: 112 return nullptr; 113 } 114 return nullptr; 115} 116 117} // namespace 118 119ir::TypeNode *ToTypeNode(std::string_view typeSignature, checker::ETSChecker *checker) 120{ 121 ASSERT(checker); 122 ASSERT(!typeSignature.empty()); 123 124 if (typeSignature[0] == 'L' || typeSignature[0] == '[') { 125 return ReferenceToTypeNode(typeSignature, checker); 126 } 127 128 pandasm::Type type = pandasm::Type::FromDescriptor(typeSignature); 129 130 return PrimitiveToTypeNode(type.GetId(), checker); 131} 132 133ir::TypeNode *PandaTypeToTypeNode(const panda_file::File &pf, panda_file::FieldDataAccessor &fda, 134 checker::ETSChecker *checker) 135{ 136 auto pandaType = panda_file::Type::GetTypeFromFieldEncoding(fda.GetType()); 137 if (pandaType.IsReference()) { 138 auto typeId = panda_file::FieldDataAccessor::GetTypeId(pf, fda.GetFieldId()); 139 std::string_view refSignature = utf::Mutf8AsCString(pf.GetStringData(typeId).data); 140 return ReferenceToTypeNode(refSignature, checker); 141 } 142 return PrimitiveToTypeNode(pandaType.GetId(), checker); 143} 144 145ir::TypeNode *PandaTypeToTypeNode(const panda_file::File &pf, panda_file::Type pandaType, 146 panda_file::File::EntityId classId, checker::ETSChecker *checker) 147{ 148 if (pandaType.IsReference()) { 149 ASSERT(classId.IsValid()); 150 std::string_view refSignature = utf::Mutf8AsCString(pf.GetStringData(classId).data); 151 return ReferenceToTypeNode(refSignature, checker); 152 } 153 return PrimitiveToTypeNode(pandaType.GetId(), checker); 154} 155 156static checker::Type *PrimitiveToCheckerType(panda_file::Type::TypeId typeId, checker::GlobalTypesHolder *globalTypes) 157{ 158 ASSERT(globalTypes); 159 switch (typeId) { 160 case panda_file::Type::TypeId::VOID: 161 return globalTypes->GlobalETSVoidType(); 162 case panda_file::Type::TypeId::U1: 163 return globalTypes->GlobalBooleanType(); 164 case panda_file::Type::TypeId::I8: 165 return globalTypes->GlobalCharType(); 166 case panda_file::Type::TypeId::U8: 167 return globalTypes->GlobalByteType(); 168 case panda_file::Type::TypeId::I16: 169 [[fallthrough]]; 170 case panda_file::Type::TypeId::U16: 171 return globalTypes->GlobalShortType(); 172 case panda_file::Type::TypeId::I32: 173 [[fallthrough]]; 174 case panda_file::Type::TypeId::U32: 175 return globalTypes->GlobalIntType(); 176 case panda_file::Type::TypeId::F32: 177 return globalTypes->GlobalFloatType(); 178 case panda_file::Type::TypeId::F64: 179 return globalTypes->GlobalDoubleType(); 180 case panda_file::Type::TypeId::I64: 181 [[fallthrough]]; 182 case panda_file::Type::TypeId::U64: 183 return globalTypes->GlobalLongType(); 184 default: 185 return nullptr; 186 } 187 return nullptr; 188} 189 190static std::optional<std::string> ReferenceToName(std::string_view typeSignature, 191 checker::GlobalTypesHolder *globalTypes) 192{ 193 static constexpr const size_t ARRAY_RANK_SYMBOLS = 2; 194 195 ASSERT(globalTypes); 196 ASSERT(!typeSignature.empty()); 197 198 switch (typeSignature[0]) { 199 case 'L': { 200 // Variable is a reference. 201 ASSERT(typeSignature.back() == ';'); 202 // Required to remove "std/core/" prefix, otherwise type name won't be parsed. 203 auto startPos = typeSignature.find_last_of('/'); 204 if (startPos == std::string_view::npos) { 205 startPos = 1; 206 } else { 207 startPos += 1; 208 } 209 return std::string(typeSignature.substr(startPos, typeSignature.size() - 1 - startPos)); 210 } 211 case '[': { 212 // Variable is an array. 213 auto rank = std::count(typeSignature.begin(), typeSignature.end(), '['); 214 auto elementType = ToTypeName(typeSignature.substr(rank), globalTypes); 215 if (!elementType) { 216 return elementType; 217 } 218 219 auto &arrayType = *elementType; 220 auto subtypeSize = arrayType.size(); 221 arrayType.resize(subtypeSize + rank * ARRAY_RANK_SYMBOLS); 222 for (size_t i = subtypeSize, end = arrayType.size(); i < end; i += ARRAY_RANK_SYMBOLS) { 223 arrayType[i] = '['; 224 arrayType[i + 1] = ']'; 225 } 226 return arrayType; 227 } 228 default: 229 UNREACHABLE(); 230 } 231 return {}; 232} 233 234std::optional<std::string> ToTypeName(std::string_view typeSignature, checker::GlobalTypesHolder *globalTypes) 235{ 236 ASSERT(globalTypes); 237 ASSERT(!typeSignature.empty()); 238 239 if (typeSignature[0] == 'L' || typeSignature[0] == '[') { 240 return ReferenceToName(typeSignature, globalTypes); 241 } 242 243 pandasm::Type type = pandasm::Type::FromDescriptor(typeSignature); 244 245 auto *checkerType = PrimitiveToCheckerType(type.GetId(), globalTypes); 246 ASSERT(checkerType); 247 return checkerType->ToString(); 248} 249 250panda_file::Type::TypeId GetTypeId(std::string_view typeSignature) 251{ 252 if (typeSignature.empty()) { 253 return panda_file::Type::TypeId::INVALID; 254 } 255 if (typeSignature[0] == 'L' || typeSignature[0] == '[') { 256 return panda_file::Type::TypeId::REFERENCE; 257 } 258 pandasm::Type type = pandasm::Type::FromDescriptor(typeSignature); 259 return type.GetId(); 260} 261 262ir::BlockStatement *GetEnclosingBlock(ir::Identifier *ident) 263{ 264 ASSERT(ident); 265 266 ir::AstNode *iter = ident; 267 268 while (iter->Parent() != nullptr && !iter->IsBlockStatement()) { 269 iter = iter->Parent(); 270 } 271 272 ASSERT(iter); 273 return iter->AsBlockStatement(); 274} 275 276SafeStateScope::SafeStateScope(checker::ETSChecker *checker, varbinder::ETSBinder *varBinder) 277 : checker_(checker), 278 varBinder_(varBinder), 279 checkerScope_(checker->Scope()), 280 binderTopScope_(varBinder->TopScope()), 281 binderVarScope_(varBinder->VarScope()), 282 binderScope_(varBinder->GetScope()), 283 binderProgram_(varBinder->Program()), 284 recordTable_(varBinder->GetRecordTable()) 285{ 286} 287 288SafeStateScope::~SafeStateScope() 289{ 290 (void)checker_; 291 (void)varBinder_; 292 (void)checkerScope_; 293 (void)binderTopScope_; 294 (void)binderVarScope_; 295 (void)binderScope_; 296 (void)binderProgram_; 297 (void)recordTable_; 298 ASSERT(checkerScope_ == checker_->Scope()); 299 ASSERT(binderTopScope_ == varBinder_->TopScope()); 300 ASSERT(binderVarScope_ == varBinder_->VarScope()); 301 ASSERT(binderScope_ == varBinder_->GetScope()); 302 ASSERT(binderProgram_ == varBinder_->Program()); 303 ASSERT(recordTable_ == varBinder_->GetRecordTable()); 304} 305 306void AddExternalProgram(parser::Program *program, parser::Program *extProgram, std::string_view moduleName) 307{ 308 ASSERT(program); 309 ASSERT(extProgram); 310 311 auto &extSources = program->ExternalSources(); 312 if (extSources.count(moduleName) == 0) { 313 extSources.emplace(moduleName, program->Allocator()->Adapter()); 314 } 315 extSources.at(moduleName).emplace_back(extProgram); 316} 317 318ir::ETSTypeReference *CreateETSTypeReference(checker::ETSChecker *checker, util::StringView name) 319{ 320 auto *identRef = checker->AllocNode<ir::Identifier>(name, checker->Allocator()); 321 identRef->AsIdentifier()->SetReference(); 322 323 auto *typeRefPart = checker->AllocNode<ir::ETSTypeReferencePart>(identRef); 324 return checker->AllocNode<ir::ETSTypeReference>(typeRefPart); 325} 326 327std::pair<std::string_view, std::string_view> SplitRecordName(std::string_view recordName) 328{ 329 std::string_view moduleName; 330 std::string_view newRecordName; 331 332 if (auto pos = recordName.find_last_of('.'); pos != std::string_view::npos) { 333 moduleName = recordName.substr(0, pos); 334 newRecordName = recordName.substr(pos + 1, recordName.size()); 335 } else { 336 newRecordName = recordName; 337 } 338 339 return std::make_pair(moduleName, newRecordName); 340} 341 342ir::ClassProperty *CreateClassProperty(checker::ETSChecker *checker, std::string_view name, ir::TypeNode *type, 343 ir::ModifierFlags modifiers) 344{ 345 ASSERT(type); 346 347 auto *fieldIdent = checker->AllocNode<ir::Identifier>(name, checker->Allocator()); 348 auto *field = 349 checker->AllocNode<ir::ClassProperty>(fieldIdent, nullptr, type, modifiers, checker->Allocator(), false); 350 351 return field; 352} 353 354ir::ModifierFlags GetModifierFlags(panda_file::ClassDataAccessor &da) 355{ 356 auto modifierFlags = ir::ModifierFlags::NONE; 357 auto accFlags = da.GetAccessFlags(); 358 if ((accFlags & ACC_ABSTRACT) != 0) { 359 modifierFlags |= ir::ModifierFlags::ABSTRACT; 360 } 361 if ((accFlags & ACC_FINAL) != 0) { 362 modifierFlags |= ir::ModifierFlags::FINAL; 363 } 364 return modifierFlags; 365} 366 367} // namespace ark::es2panda::evaluate::helpers 368