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
33 namespace ark::es2panda::checker {
34 class Type;
35 } // namespace ark::es2panda::checker
36
37 namespace ark::es2panda::ir {
38 class BlockStatement;
39 class Identifier;
40 class TypeNode;
41 class ETSTypeReference;
42 class ClassProperty;
43 } // namespace ark::es2panda::ir
44
45 namespace ark::es2panda::parser {
46 class Program;
47 } // namespace ark::es2panda::parser
48
49 namespace ark::es2panda::evaluate::helpers {
50
51 class SafeStateScope final {
52 public:
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
63 private:
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
74 static 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
CreateGetterName(panda_file::Type::TypeId typeId)118 constexpr inline std::string_view CreateGetterName(panda_file::Type::TypeId typeId)
119 {
120 TYPED_ACCESSOR_NAME_SWITCH(getLocal);
121 }
122
CreateSetterName(panda_file::Type::TypeId typeId)123 constexpr 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
130 template <typename F>
DoScopedAction(checker::ETSChecker *checker, varbinder::ETSBinder *varBinder, parser::Program *program, varbinder::Scope *scope, ir::AstNode *parentClass, F &&action)131 void 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
168 ir::TypeNode *ToTypeNode(std::string_view typeSignature, checker::ETSChecker *checker);
169
170 ir::TypeNode *PandaTypeToTypeNode(const panda_file::File &pf, panda_file::FieldDataAccessor &fda,
171 checker::ETSChecker *checker);
172
173 ir::TypeNode *PandaTypeToTypeNode(const panda_file::File &pf, panda_file::Type pandaType,
174 panda_file::File::EntityId classId, checker::ETSChecker *checker);
175
176 std::optional<std::string> ToTypeName(std::string_view typeSignature, checker::GlobalTypesHolder *globalTypes);
177
178 panda_file::Type::TypeId GetTypeId(std::string_view typeSignature);
179
180 ir::BlockStatement *GetEnclosingBlock(ir::Identifier *ident);
181
182 template <typename AccessorType>
GetModifierFlags(AccessorType &da, bool forceAddPublicFlag)183 ir::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
225 ir::ModifierFlags GetModifierFlags(panda_file::ClassDataAccessor &da);
226
227 // Adds `extProgram` into external programs list of the given `program`.
228 void AddExternalProgram(parser::Program *program, parser::Program *extProgram, std::string_view moduleName);
229
230 ir::ETSTypeReference *CreateETSTypeReference(checker::ETSChecker *checker, util::StringView name);
231
232 std::pair<std::string_view, std::string_view> SplitRecordName(std::string_view recordName);
233
234 ir::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