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 std::tuple<util::StringView, bool> ParamName(ArenaAllocator *allocator, const ir::AstNode *param,
162 uint32_t index);
163
164 template <typename T, typename V>
ConvertVector(const ArenaVector<V * > & src)165 static ArenaVector<T *> ConvertVector(const ArenaVector<V *> &src)
166 {
167 ArenaVector<T *> dst(src.begin(), src.end(), src.get_allocator());
168 return dst;
169 }
170
171 template <typename Source, typename Target>
IsTargetFitInSourceRange(Target target)172 static bool IsTargetFitInSourceRange(Target target)
173 {
174 if (!std::isfinite(target)) {
175 return true;
176 }
177
178 // NOLINTNEXTLINE(misc-redundant-expression)
179 return target >= std::numeric_limits<Source>::lowest() &&
180 target <= static_cast<Target>(std::numeric_limits<Source>::max());
181 }
182
183 static const uint32_t INVALID_INDEX = 4294967295L;
184
185 static std::string CreateEscapedString(const std::string &str);
186 static std::string UTF16toUTF8(const char16_t c);
187
188 template <typename... Elements>
189 static void LogDebug(Elements &&...elems);
190 template <typename... Elements>
191 static void LogInfo(Elements &&...elems);
192 template <typename... Elements>
193 static void LogWarning(Elements &&...elems);
194 template <typename... Elements>
195 static void LogError(Elements &&...elems);
196 template <typename... Elements>
197 static void LogFatal(Elements &&...elems);
198
199 template <typename... Elements>
200 static std::string AppendAll(Elements &&...elems);
201
202 static std::pair<std::string_view, std::string_view> SplitSignature(std::string_view signature);
203
204 static std::vector<std::string> &StdLib();
205 static bool IsStdLib(const parser::Program *program);
206
207 private:
208 template <LogLevel LOG_L, typename... Elements>
209 static void Log(Elements &&...elems);
210 };
211
212 template <typename T>
IsInteger(double number)213 bool Helpers::IsInteger(double number)
214 {
215 if (std::fabs(number) <= static_cast<double>(std::numeric_limits<T>::max())) {
216 T intNum = static_cast<T>(number);
217
218 if (static_cast<double>(intNum) == number) {
219 return true;
220 }
221 }
222
223 return false;
224 }
225
226 template <LogLevel LOG_L, typename... Elements>
Log(Elements &&...elems)227 void Helpers::Log(Elements &&...elems)
228 {
229 constexpr auto ES2PANDA = ark::Logger::Component::ES2PANDA;
230 constexpr auto LOG_LEVEL = []() {
231 switch (LOG_L) {
232 case LogLevel::DEBUG: {
233 return ark::Logger::Level::DEBUG;
234 }
235 case LogLevel::INFO: {
236 return ark::Logger::Level::INFO;
237 }
238 case LogLevel::WARNING: {
239 return ark::Logger::Level::WARNING;
240 }
241 case LogLevel::ERROR: {
242 return ark::Logger::Level::ERROR;
243 }
244 case LogLevel::FATAL: {
245 return ark::Logger::Level::FATAL;
246 }
247 default: {
248 UNREACHABLE_CONSTEXPR();
249 }
250 }
251 }();
252
253 #ifndef NDEBUG
254 const bool isMessageSuppressed = ark::Logger::IsMessageSuppressed(LOG_LEVEL, ES2PANDA);
255 #else
256 const bool isMessageSuppressed = false;
257 #endif
258 if (!ark::Logger::IsLoggingOnOrAbort(LOG_LEVEL, ES2PANDA) || isMessageSuppressed) {
259 return;
260 }
261
262 (ark::Logger::Message(LOG_LEVEL, ES2PANDA, false).GetStream() << ... << std::forward<Elements>(elems));
263 }
264
265 template <typename... Elements>
LogDebug(Elements &&...elems)266 void Helpers::LogDebug(Elements &&...elems)
267 {
268 Helpers::Log<LogLevel::DEBUG>(std::forward<Elements>(elems)...);
269 }
270
271 template <typename... Elements>
LogInfo(Elements &&...elems)272 void Helpers::LogInfo(Elements &&...elems)
273 {
274 Helpers::Log<LogLevel::INFO>(std::forward<Elements>(elems)...);
275 }
276
277 template <typename... Elements>
LogWarning(Elements &&...elems)278 void Helpers::LogWarning(Elements &&...elems)
279 {
280 Helpers::Log<LogLevel::WARNING>(std::forward<Elements>(elems)...);
281 }
282
283 template <typename... Elements>
LogError(Elements &&...elems)284 void Helpers::LogError(Elements &&...elems)
285 {
286 Helpers::Log<LogLevel::ERROR>(std::forward<Elements>(elems)...);
287 }
288
289 template <typename... Elements>
LogFatal(Elements &&...elems)290 void Helpers::LogFatal(Elements &&...elems)
291 {
292 Helpers::Log<LogLevel::FATAL>(std::forward<Elements>(elems)...);
293 }
294
295 template <typename... Elements>
AppendAll(Elements &&...elems)296 std::string Helpers::AppendAll(Elements &&...elems)
297 {
298 std::string ret {};
299 ((ret += std::forward<Elements>(elems)), ...);
300 return ret;
301 }
302
303 } // namespace ark::es2panda::util
304
305 #endif
306