• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2025 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 
33 namespace ark::es2panda::evaluate::helpers {
34 
35 namespace {
36 
PrimitiveToTypeNode(panda_file::Type::TypeId typeId,checker::ETSChecker * checker)37 ir::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             ES2PANDA_UNREACHABLE();
70     }
71 
72     return checker->AllocNode<ir::ETSPrimitiveType>(irType, checker->Allocator());
73 }
74 
ClassReferenceToTypeNode(std::string_view name,checker::ETSChecker * checker)75 ir::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 
ReferenceToTypeNode(std::string_view typeSignature,checker::ETSChecker * checker)81 ir::TypeNode *ReferenceToTypeNode(std::string_view typeSignature, checker::ETSChecker *checker)
82 {
83     ES2PANDA_ASSERT(checker);
84     ES2PANDA_ASSERT(!typeSignature.empty());
85     switch (typeSignature[0]) {
86         case 'L': {
87             // Variable is a reference.
88             ES2PANDA_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, checker->Allocator());
106                 }
107                 return elementType;
108             }
109             return nullptr;
110         }
111         default:
112             return nullptr;
113     }
114     return nullptr;
115 }
116 
117 }  // namespace
118 
ToTypeNode(std::string_view typeSignature,checker::ETSChecker * checker)119 ir::TypeNode *ToTypeNode(std::string_view typeSignature, checker::ETSChecker *checker)
120 {
121     ES2PANDA_ASSERT(checker);
122     ES2PANDA_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 
PandaTypeToTypeNode(const panda_file::File & pf,panda_file::FieldDataAccessor & fda,checker::ETSChecker * checker)133 ir::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 
PandaTypeToTypeNode(const panda_file::File & pf,panda_file::Type pandaType,panda_file::File::EntityId classId,checker::ETSChecker * checker)145 ir::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         ES2PANDA_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 
PrimitiveToCheckerType(panda_file::Type::TypeId typeId,checker::GlobalTypesHolder * globalTypes)156 static checker::Type *PrimitiveToCheckerType(panda_file::Type::TypeId typeId, checker::GlobalTypesHolder *globalTypes)
157 {
158     ES2PANDA_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 
ReferenceToName(std::string_view typeSignature,checker::GlobalTypesHolder * globalTypes)190 static 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     ES2PANDA_ASSERT(globalTypes);
196     ES2PANDA_ASSERT(!typeSignature.empty());
197 
198     switch (typeSignature[0]) {
199         case 'L': {
200             // Variable is a reference.
201             ES2PANDA_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             ES2PANDA_UNREACHABLE();
230     }
231     return {};
232 }
233 
ToTypeName(std::string_view typeSignature,checker::GlobalTypesHolder * globalTypes)234 std::optional<std::string> ToTypeName(std::string_view typeSignature, checker::GlobalTypesHolder *globalTypes)
235 {
236     ES2PANDA_ASSERT(globalTypes);
237     ES2PANDA_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     ES2PANDA_ASSERT(checkerType != nullptr);
247     return checkerType->ToString();
248 }
249 
GetTypeId(std::string_view typeSignature)250 panda_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 
GetEnclosingBlock(ir::Identifier * ident)262 ir::BlockStatement *GetEnclosingBlock(ir::Identifier *ident)
263 {
264     ES2PANDA_ASSERT(ident);
265 
266     ir::AstNode *iter = ident;
267 
268     while (iter->Parent() != nullptr && !iter->IsBlockStatement()) {
269         iter = iter->Parent();
270     }
271 
272     ES2PANDA_ASSERT(iter);
273     return iter->AsBlockStatement();
274 }
275 
SafeStateScope(checker::ETSChecker * checker,varbinder::ETSBinder * varBinder)276 SafeStateScope::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 
~SafeStateScope()288 SafeStateScope::~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     ES2PANDA_ASSERT(checkerScope_ == checker_->Scope());
299     ES2PANDA_ASSERT(binderTopScope_ == varBinder_->TopScope());
300     ES2PANDA_ASSERT(binderVarScope_ == varBinder_->VarScope());
301     ES2PANDA_ASSERT(binderScope_ == varBinder_->GetScope());
302     ES2PANDA_ASSERT(binderProgram_ == varBinder_->Program());
303     ES2PANDA_ASSERT(recordTable_ == varBinder_->GetRecordTable());
304 }
305 
AddExternalProgram(parser::Program * program,parser::Program * extProgram,std::string_view moduleName)306 void AddExternalProgram(parser::Program *program, parser::Program *extProgram, std::string_view moduleName)
307 {
308     ES2PANDA_ASSERT(program);
309     ES2PANDA_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 
CreateETSTypeReference(checker::ETSChecker * checker,util::StringView name)318 ir::ETSTypeReference *CreateETSTypeReference(checker::ETSChecker *checker, util::StringView name)
319 {
320     auto *identRef = checker->AllocNode<ir::Identifier>(name, checker->Allocator());
321     auto *typeRefPart = checker->AllocNode<ir::ETSTypeReferencePart>(identRef, checker->Allocator());
322     return checker->AllocNode<ir::ETSTypeReference>(typeRefPart, checker->Allocator());
323 }
324 
325 // Be aware of lifecycle of string and string_view
SplitRecordName(std::string_view recordName)326 std::pair<std::string_view, std::string_view> SplitRecordName(std::string_view recordName)
327 {
328     std::string_view moduleName;
329     std::string_view newRecordName;
330 
331     if (auto pos = recordName.find_last_of('.'); pos != std::string_view::npos) {
332         moduleName = recordName.substr(0, pos);
333         newRecordName = recordName.substr(pos + 1, recordName.size());
334     } else {
335         newRecordName = recordName;
336     }
337 
338     return std::make_pair(moduleName, newRecordName);
339 }
340 
CreateClassProperty(checker::ETSChecker * checker,std::string_view name,ir::TypeNode * type,ir::ModifierFlags modifiers)341 ir::ClassProperty *CreateClassProperty(checker::ETSChecker *checker, std::string_view name, ir::TypeNode *type,
342                                        ir::ModifierFlags modifiers)
343 {
344     ES2PANDA_ASSERT(type);
345 
346     auto *fieldIdent = checker->AllocNode<ir::Identifier>(name, checker->Allocator());
347     auto *field =
348         checker->AllocNode<ir::ClassProperty>(fieldIdent, nullptr, type, modifiers, checker->Allocator(), false);
349 
350     return field;
351 }
352 
GetModifierFlags(panda_file::ClassDataAccessor & da)353 ir::ModifierFlags GetModifierFlags(panda_file::ClassDataAccessor &da)
354 {
355     auto modifierFlags = ir::ModifierFlags::NONE;
356     auto accFlags = da.GetAccessFlags();
357     if ((accFlags & ACC_ABSTRACT) != 0) {
358         modifierFlags |= ir::ModifierFlags::ABSTRACT;
359     }
360     if ((accFlags & ACC_FINAL) != 0) {
361         modifierFlags |= ir::ModifierFlags::FINAL;
362     }
363     return modifierFlags;
364 }
365 
366 }  // namespace ark::es2panda::evaluate::helpers
367