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