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 
28 namespace ark::es2panda::varbinder {
29 class Variable;
30 }  // namespace ark::es2panda::varbinder
31 
32 namespace ark::es2panda::checker {
33 class ETSObjectType;
34 class Type;
35 }  // namespace ark::es2panda::checker
36 
37 namespace ark::es2panda::compiler {
38 class Literal;
39 }  // namespace ark::es2panda::compiler
40 
41 namespace ark::es2panda::ir {
42 class Expression;
43 class ScriptFunction;
44 class ClassDefinition;
45 class ClassProperty;
46 class Identifier;
47 class MethodDefinition;
48 class AstNode;
49 class ReturnStatement;
50 class CallExpression;
51 class ClassStaticBlock;
52 class TSInterfaceDeclaration;
53 class TSEnumDeclaration;
54 class ETSImportDeclaration;
55 enum class AstNodeType;
56 }  // namespace ark::es2panda::ir
57 
58 namespace ark::es2panda::util {
59 enum class LogLevel : std::uint8_t {
60     DEBUG,
61     INFO,
62     WARNING,
63     ERROR,
64     FATAL,
65     INVALID,
66 };
67 
68 class NodeAllocator {
69 public:
70     template <typename T, typename... Args>
NoSetParent(ArenaAllocator *alloc, Args &&...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>
ForceSetParent(ArenaAllocator *alloc, Args &&...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>
Alloc(ArenaAllocator *alloc, Args &&...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 
102 class Helpers {
103 public:
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 *>>>
FindAncestorGivenByType(T node, ir::AstNodeType type)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>
ConvertVector(const ArenaVector<V *> &src)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>
IsTargetFitInSourceRange(Target 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 
210 private:
211     template <LogLevel LOG_L, typename... Elements>
212     static void Log(Elements &&...elems);
213 };
214 
215 template <typename T>
IsInteger(double number)216 bool 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 
229 template <LogLevel LOG_L, typename... Elements>
Log(Elements &&....elems)230 void 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 
268 template <typename... Elements>
LogDebug(Elements &&....elems)269 void Helpers::LogDebug(Elements &&...elems)
270 {
271     Helpers::Log<LogLevel::DEBUG>(std::forward<Elements>(elems)...);
272 }
273 
274 template <typename... Elements>
LogInfo(Elements &&....elems)275 void Helpers::LogInfo(Elements &&...elems)
276 {
277     Helpers::Log<LogLevel::INFO>(std::forward<Elements>(elems)...);
278 }
279 
280 template <typename... Elements>
LogWarning(Elements &&....elems)281 void Helpers::LogWarning(Elements &&...elems)
282 {
283     Helpers::Log<LogLevel::WARNING>(std::forward<Elements>(elems)...);
284 }
285 
286 template <typename... Elements>
LogError(Elements &&....elems)287 void Helpers::LogError(Elements &&...elems)
288 {
289     Helpers::Log<LogLevel::ERROR>(std::forward<Elements>(elems)...);
290 }
291 
292 template <typename... Elements>
LogFatal(Elements &&....elems)293 void Helpers::LogFatal(Elements &&...elems)
294 {
295     Helpers::Log<LogLevel::FATAL>(std::forward<Elements>(elems)...);
296 }
297 
298 template <typename... Elements>
AppendAll(Elements &&....elems)299 std::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