1/**
2 * Copyright (c) 2021-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_UTIL_HELPERS_H
17#define ES2PANDA_UTIL_HELPERS_H
18
19#include "varbinder/variableFlags.h"
20#include "mem/pool_manager.h"
21#include "util/ustring.h"
22#include "ir/module/importSpecifier.h"
23#include "parser/program/program.h"
24
25#include <cmath>
26#include <string>
27
28namespace ark::es2panda::varbinder {
29class Variable;
30}  // namespace ark::es2panda::varbinder
31
32namespace ark::es2panda::checker {
33class ETSObjectType;
34class Type;
35}  // namespace ark::es2panda::checker
36
37namespace ark::es2panda::compiler {
38class Literal;
39}  // namespace ark::es2panda::compiler
40
41namespace ark::es2panda::ir {
42class Expression;
43class ScriptFunction;
44class ClassDefinition;
45class ClassProperty;
46class Identifier;
47class MethodDefinition;
48class AstNode;
49class ReturnStatement;
50class CallExpression;
51class ClassStaticBlock;
52class TSInterfaceDeclaration;
53class TSEnumDeclaration;
54class ETSImportDeclaration;
55enum class AstNodeType;
56}  // namespace ark::es2panda::ir
57
58namespace ark::es2panda::util {
59enum class LogLevel : std::uint8_t {
60    DEBUG,
61    INFO,
62    WARNING,
63    ERROR,
64    FATAL,
65    INVALID,
66};
67
68class NodeAllocator {
69public:
70    template <typename T, typename... Args>
71    static T *NoSetParent(ArenaAllocator *alloc, Args &&...args)
72    {
73        return alloc->New<T>(std::forward<Args>(args)...);
74    }
75
76    template <typename T, typename... Args>
77    static T *ForceSetParent(ArenaAllocator *alloc, Args &&...args)
78    {
79        auto *ret = NoSetParent<T>(alloc, std::forward<Args>(args)...);
80        if (ret == nullptr) {
81            return nullptr;
82        }
83        ret->Iterate([ret](ir::AstNode *child) { child->SetParent(ret); });
84        return ret;
85    }
86
87    template <typename T, typename... Args>
88    static T *Alloc(ArenaAllocator *alloc, Args &&...args)
89    {
90        auto *ret = NoSetParent<T>(alloc, std::forward<Args>(args)...);
91        if (ret == nullptr) {
92            return nullptr;
93        }
94        ret->Iterate([ret](ir::AstNode *child) {
95            ASSERT(child->Parent() == nullptr);
96            child->SetParent(ret);
97        });
98        return ret;
99    }
100};
101
102class Helpers {
103public:
104    Helpers() = delete;
105
106    static bool IsGlobalIdentifier(const util::StringView &str);
107    static bool ContainSpreadElement(const ArenaVector<ir::Expression *> &args);
108    static util::StringView LiteralToPropName(const ir::Expression *lit);
109
110    template <typename T>
111    static bool IsInteger(double number);
112    static bool IsIndex(double number);
113    static int64_t GetIndex(const util::StringView &str);
114
115    static std::string ToString(double number);
116    static util::StringView ToStringView(ArenaAllocator *allocator, double number);
117    static util::StringView ToStringView(ArenaAllocator *allocator, int32_t number);
118    static util::StringView ToStringView(ArenaAllocator *allocator, uint32_t number);
119    static bool EndsWith(const std::string &str, const std::string &suffix);
120
121    static const ir::ScriptFunction *GetContainingConstructor(const ir::AstNode *node);
122    static const ir::ScriptFunction *GetContainingConstructor(const ir::ClassProperty *node);
123
124    template <typename T,
125              typename U = std::enable_if_t<
126                  std::is_convertible_v<std::remove_const_t<std::remove_pointer_t<T>> *, ir::AstNode *>,
127                  std::conditional_t<std::is_const_v<std::remove_pointer_t<T>>, const ir::AstNode *, ir::AstNode *>>>
128    static U FindAncestorGivenByType(T node, ir::AstNodeType type)
129    {
130        U iter = node->Parent();
131
132        while (iter->Type() != type) {
133            if (iter->Parent() != nullptr) {
134                iter = iter->Parent();
135                continue;
136            }
137
138            return nullptr;
139        }
140
141        return iter;
142    }
143
144    static const checker::ETSObjectType *GetContainingObjectType(const ir::AstNode *node);
145    static const ir::TSEnumDeclaration *GetContainingEnumDeclaration(const ir::AstNode *node);
146    static const ir::ClassDefinition *GetContainingClassDefinition(const ir::AstNode *node);
147    static const ir::TSInterfaceDeclaration *GetContainingInterfaceDeclaration(const ir::AstNode *node);
148    static const ir::MethodDefinition *GetContainingClassMethodDefinition(const ir::AstNode *node);
149    static const ir::ClassStaticBlock *GetContainingClassStaticBlock(const ir::AstNode *node);
150    static const ir::ScriptFunction *GetContainingFunction(const ir::AstNode *node);
151    static const ir::ClassDefinition *GetClassDefiniton(const ir::ScriptFunction *node);
152    static bool IsSpecialPropertyKey(const ir::Expression *expr);
153    static bool IsConstantPropertyKey(const ir::Expression *expr, bool isComputed);
154    static compiler::Literal ToConstantLiteral(const ir::Expression *expr);
155    static bool IsBindingPattern(const ir::AstNode *node);
156    static bool IsPattern(const ir::AstNode *node);
157    static std::vector<ir::Identifier *> CollectBindingNames(ir::AstNode *node);
158    static util::StringView FunctionName(ArenaAllocator *allocator, const ir::ScriptFunction *func);
159    static void CheckImportedName(const ArenaVector<ir::ImportSpecifier *> &specifiers,
160                                  const ir::ImportSpecifier *specifier, const std::string &fileName);
161    static void CheckDefaultImportedName(const ArenaVector<ir::ImportDefaultSpecifier *> &specifiers,
162                                         const ir::ImportDefaultSpecifier *specifier, const std::string &fileName);
163    static void CheckDefaultImport(const ArenaVector<ir::ETSImportDeclaration *> &statements);
164    static std::tuple<util::StringView, bool> ParamName(ArenaAllocator *allocator, const ir::AstNode *param,
165                                                        uint32_t index);
166
167    template <typename T, typename V>
168    static ArenaVector<T *> ConvertVector(const ArenaVector<V *> &src)
169    {
170        ArenaVector<T *> dst(src.begin(), src.end(), src.get_allocator());
171        return dst;
172    }
173
174    template <typename Source, typename Target>
175    static bool IsTargetFitInSourceRange(Target target)
176    {
177        if (!std::isfinite(target)) {
178            return true;
179        }
180
181        // NOLINTNEXTLINE(misc-redundant-expression)
182        return target >= std::numeric_limits<Source>::lowest() &&
183               target <= static_cast<Target>(std::numeric_limits<Source>::max());
184    }
185
186    static const uint32_t INVALID_INDEX = 4294967295L;
187
188    static std::string CreateEscapedString(const std::string &str);
189    static std::string UTF16toUTF8(const char16_t c);
190
191    template <typename... Elements>
192    static void LogDebug(Elements &&...elems);
193    template <typename... Elements>
194    static void LogInfo(Elements &&...elems);
195    template <typename... Elements>
196    static void LogWarning(Elements &&...elems);
197    template <typename... Elements>
198    static void LogError(Elements &&...elems);
199    template <typename... Elements>
200    static void LogFatal(Elements &&...elems);
201
202    template <typename... Elements>
203    static std::string AppendAll(Elements &&...elems);
204
205    static std::pair<std::string_view, std::string_view> SplitSignature(std::string_view signature);
206
207    static std::vector<std::string> &StdLib();
208    static bool IsStdLib(const parser::Program *program);
209
210private:
211    template <LogLevel LOG_L, typename... Elements>
212    static void Log(Elements &&...elems);
213};
214
215template <typename T>
216bool Helpers::IsInteger(double number)
217{
218    if (std::fabs(number) <= static_cast<double>(std::numeric_limits<T>::max())) {
219        T intNum = static_cast<T>(number);
220
221        if (static_cast<double>(intNum) == number) {
222            return true;
223        }
224    }
225
226    return false;
227}
228
229template <LogLevel LOG_L, typename... Elements>
230void Helpers::Log(Elements &&...elems)
231{
232    constexpr auto ES2PANDA = ark::Logger::Component::ES2PANDA;
233    constexpr auto LOG_LEVEL = []() {
234        switch (LOG_L) {
235            case LogLevel::DEBUG: {
236                return ark::Logger::Level::DEBUG;
237            }
238            case LogLevel::INFO: {
239                return ark::Logger::Level::INFO;
240            }
241            case LogLevel::WARNING: {
242                return ark::Logger::Level::WARNING;
243            }
244            case LogLevel::ERROR: {
245                return ark::Logger::Level::ERROR;
246            }
247            case LogLevel::FATAL: {
248                return ark::Logger::Level::FATAL;
249            }
250            default: {
251                UNREACHABLE_CONSTEXPR();
252            }
253        }
254    }();
255
256#ifndef NDEBUG
257    const bool isMessageSuppressed = ark::Logger::IsMessageSuppressed(LOG_LEVEL, ES2PANDA);
258#else
259    const bool isMessageSuppressed = false;
260#endif
261    if (!ark::Logger::IsLoggingOnOrAbort(LOG_LEVEL, ES2PANDA) || isMessageSuppressed) {
262        return;
263    }
264
265    (ark::Logger::Message(LOG_LEVEL, ES2PANDA, false).GetStream() << ... << std::forward<Elements>(elems));
266}
267
268template <typename... Elements>
269void Helpers::LogDebug(Elements &&...elems)
270{
271    Helpers::Log<LogLevel::DEBUG>(std::forward<Elements>(elems)...);
272}
273
274template <typename... Elements>
275void Helpers::LogInfo(Elements &&...elems)
276{
277    Helpers::Log<LogLevel::INFO>(std::forward<Elements>(elems)...);
278}
279
280template <typename... Elements>
281void Helpers::LogWarning(Elements &&...elems)
282{
283    Helpers::Log<LogLevel::WARNING>(std::forward<Elements>(elems)...);
284}
285
286template <typename... Elements>
287void Helpers::LogError(Elements &&...elems)
288{
289    Helpers::Log<LogLevel::ERROR>(std::forward<Elements>(elems)...);
290}
291
292template <typename... Elements>
293void Helpers::LogFatal(Elements &&...elems)
294{
295    Helpers::Log<LogLevel::FATAL>(std::forward<Elements>(elems)...);
296}
297
298template <typename... Elements>
299std::string Helpers::AppendAll(Elements &&...elems)
300{
301    std::string ret {};
302    ((ret += std::forward<Elements>(elems)), ...);
303    return ret;
304}
305
306}  // namespace ark::es2panda::util
307
308#endif
309