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 #include "helpers.h"
17 
18 #include "generated/signatures.h"
19 #include "varbinder/privateBinding.h"
20 #include "checker/types/ets/types.h"
21 #include "ir/astNode.h"
22 #include "ir/base/classDefinition.h"
23 #include "ir/base/classProperty.h"
24 #include "ir/base/methodDefinition.h"
25 #include "ir/base/property.h"
26 #include "ir/base/scriptFunction.h"
27 #include "ir/base/spreadElement.h"
28 #include "ir/expressions/arrayExpression.h"
29 #include "ir/expressions/assignmentExpression.h"
30 #include "ir/expressions/callExpression.h"
31 #include "ir/expressions/functionExpression.h"
32 #include "ir/expressions/identifier.h"
33 #include "ir/expressions/literals/numberLiteral.h"
34 #include "ir/expressions/literals/stringLiteral.h"
35 #include "ir/expressions/literals/booleanLiteral.h"
36 #include "ir/expressions/literals/nullLiteral.h"
37 #include "ir/expressions/objectExpression.h"
38 #include "ir/statements/returnStatement.h"
39 #include "ir/statements/variableDeclaration.h"
40 #include "ir/statements/variableDeclarator.h"
41 #include "ir/module/importSpecifier.h"
42 #include "ir/ets/etsImportDeclaration.h"
43 #include "ir/ts/tsParameterProperty.h"
44 #include "ir/ts/tsInterfaceDeclaration.h"
45 #include "ir/ts/tsEnumDeclaration.h"
46 #include "ir/ets/etsParameterExpression.h"
47 #include "ir/module/importDeclaration.h"
48 #include "lexer/token/letters.h"
49 #include "libpandabase/utils/utf.h"
50 #include "libpandabase/os/filesystem.h"
51 #include "ir/module/importDefaultSpecifier.h"
52 #include <iomanip>
53 
54 namespace ark::es2panda::util {
55 // Helpers
56 
IsGlobalIdentifier(const util::StringView &str)57 bool Helpers::IsGlobalIdentifier(const util::StringView &str)
58 {
59     return (str.Is("NaN") || str.Is("undefined") || str.Is("Infinity"));
60 }
61 
ContainSpreadElement(const ArenaVector<ir::Expression *> &args)62 bool Helpers::ContainSpreadElement(const ArenaVector<ir::Expression *> &args)
63 {
64     return std::any_of(args.begin(), args.end(), [](const auto *it) { return it->IsSpreadElement(); });
65 }
66 
LiteralToPropName(const ir::Expression *lit)67 util::StringView Helpers::LiteralToPropName(const ir::Expression *lit)
68 {
69     switch (lit->Type()) {
70         case ir::AstNodeType::IDENTIFIER: {
71             return lit->AsIdentifier()->Name();
72         }
73         case ir::AstNodeType::STRING_LITERAL: {
74             return lit->AsStringLiteral()->Str();
75         }
76         case ir::AstNodeType::NUMBER_LITERAL: {
77             return lit->AsNumberLiteral()->Str();
78         }
79         case ir::AstNodeType::NULL_LITERAL: {
80             return "null";
81         }
82         case ir::AstNodeType::UNDEFINED_LITERAL: {
83             return "undefined";
84         }
85         default: {
86             UNREACHABLE();
87         }
88     }
89 }
90 
IsIndex(double number)91 bool Helpers::IsIndex(double number)
92 {
93     if (number >= 0 && number < static_cast<double>(INVALID_INDEX)) {
94         auto intNum = static_cast<uint32_t>(number);
95 
96         if (static_cast<double>(intNum) == number) {
97             return true;
98         }
99     }
100 
101     return false;
102 }
103 
IsDigit(char c)104 static bool IsDigit(char c)
105 {
106     return (c >= '0' && c <= '9');
107 }
108 
GetIndex(const util::StringView &str)109 int64_t Helpers::GetIndex(const util::StringView &str)
110 {
111     const auto &s = str.Utf8();
112 
113     if (s.empty() || (*s.begin() == '0' && s.length() > 1)) {
114         return INVALID_INDEX;
115     }
116 
117     int64_t value = 0;
118     for (const auto c : s) {
119         if (!IsDigit(c)) {
120             return INVALID_INDEX;
121         }
122 
123         constexpr auto MULTIPLIER = 10;
124         value *= MULTIPLIER;
125         value += (c - '0');
126 
127         if (value >= INVALID_INDEX) {
128             return INVALID_INDEX;
129         }
130     }
131 
132     return value;
133 }
134 
ToString(double number)135 std::string Helpers::ToString(double number)
136 {
137     std::string str;
138 
139     if (Helpers::IsInteger<int32_t>(number)) {
140         str = std::to_string(static_cast<int32_t>(number));
141     } else {
142         str = std::to_string(number);
143     }
144 
145     return str;
146 }
147 
ToStringView(ArenaAllocator *allocator, double number)148 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, double number)
149 {
150     util::UString str(ToString(number), allocator);
151     return str.View();
152 }
153 
ToStringView(ArenaAllocator *allocator, uint32_t number)154 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, uint32_t number)
155 {
156     ASSERT(number <= static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
157     return ToStringView(allocator, static_cast<int32_t>(number));
158 }
159 
ToStringView(ArenaAllocator *allocator, int32_t number)160 util::StringView Helpers::ToStringView(ArenaAllocator *allocator, int32_t number)
161 {
162     util::UString str(ToString(number), allocator);
163     return str.View();
164 }
165 
EndsWith(const std::string &str, const std::string &suffix)166 bool Helpers::EndsWith(const std::string &str, const std::string &suffix)
167 {
168     if (str.length() < suffix.length()) {
169         return false;
170     }
171     size_t expectPos = str.length() - suffix.length();
172     return str.find(suffix, expectPos) == expectPos;
173 }
174 
GetContainingConstructor(const ir::AstNode *node)175 const ir::ScriptFunction *Helpers::GetContainingConstructor(const ir::AstNode *node)
176 {
177     const ir::ScriptFunction *iter = GetContainingFunction(node);
178 
179     while (iter != nullptr) {
180         if (iter->IsConstructor()) {
181             return iter;
182         }
183 
184         if (!iter->IsArrow()) {
185             return nullptr;
186         }
187 
188         iter = GetContainingFunction(iter);
189     }
190 
191     return iter;
192 }
193 
GetContainingEnumDeclaration(const ir::AstNode *node)194 const ir::TSEnumDeclaration *Helpers::GetContainingEnumDeclaration(const ir::AstNode *node)
195 {
196     auto *iter = node;
197 
198     while (iter != nullptr) {
199         if (iter->IsTSEnumDeclaration()) {
200             return iter->AsTSEnumDeclaration();
201         }
202 
203         iter = iter->Parent();
204     }
205 
206     return nullptr;
207 }
208 
GetContainingObjectType(const ir::AstNode *node)209 const checker::ETSObjectType *Helpers::GetContainingObjectType(const ir::AstNode *node)
210 {
211     const auto *iter = node;
212 
213     while (iter != nullptr) {
214         if (iter->IsClassDefinition()) {
215             auto *ret = iter->AsClassDefinition()->TsType();
216             return ret != nullptr ? ret->AsETSObjectType() : nullptr;
217         }
218 
219         if (iter->IsTSInterfaceDeclaration()) {
220             auto *ret = iter->AsTSInterfaceDeclaration()->TsType();
221             return ret != nullptr ? ret->AsETSObjectType() : nullptr;
222         }
223 
224         if (iter->IsTSEnumDeclaration()) {
225             auto *ret = iter->AsTSEnumDeclaration()->TsType();
226             return ret != nullptr ? ret->AsETSObjectType() : nullptr;
227         }
228 
229         iter = iter->Parent();
230     }
231 
232     return nullptr;
233 }
234 
GetContainingClassDefinition(const ir::AstNode *node)235 const ir::ClassDefinition *Helpers::GetContainingClassDefinition(const ir::AstNode *node)
236 {
237     const auto *iter = node;
238 
239     while (iter != nullptr) {
240         if (iter->IsClassDefinition()) {
241             return iter->AsClassDefinition();
242         }
243 
244         iter = iter->Parent();
245     }
246 
247     return nullptr;
248 }
249 
GetContainingInterfaceDeclaration(const ir::AstNode *node)250 const ir::TSInterfaceDeclaration *Helpers::GetContainingInterfaceDeclaration(const ir::AstNode *node)
251 {
252     const auto *iter = node;
253 
254     while (iter != nullptr) {
255         if (iter->IsTSInterfaceDeclaration()) {
256             return iter->AsTSInterfaceDeclaration();
257         }
258 
259         iter = iter->Parent();
260     }
261 
262     return nullptr;
263 }
264 
GetContainingClassMethodDefinition(const ir::AstNode *node)265 const ir::MethodDefinition *Helpers::GetContainingClassMethodDefinition(const ir::AstNode *node)
266 {
267     const auto *iter = node;
268 
269     while (iter != nullptr) {
270         if (iter->IsMethodDefinition()) {
271             return iter->AsMethodDefinition();
272         }
273 
274         if (iter->IsClassDefinition()) {
275             break;
276         }
277 
278         iter = iter->Parent();
279     }
280 
281     return nullptr;
282 }
283 
GetContainingClassStaticBlock(const ir::AstNode *node)284 const ir::ClassStaticBlock *Helpers::GetContainingClassStaticBlock(const ir::AstNode *node)
285 {
286     const auto *iter = node;
287 
288     while (iter != nullptr) {
289         if (iter->IsClassStaticBlock()) {
290             return iter->AsClassStaticBlock();
291         }
292 
293         if (iter->IsClassDefinition()) {
294             break;
295         }
296 
297         iter = iter->Parent();
298     }
299 
300     return nullptr;
301 }
302 
GetContainingConstructor(const ir::ClassProperty *node)303 const ir::ScriptFunction *Helpers::GetContainingConstructor(const ir::ClassProperty *node)
304 {
305     for (const auto *parent = node->Parent(); parent != nullptr; parent = parent->Parent()) {
306         if (parent->IsClassDefinition()) {
307             ASSERT(parent->AsClassDefinition()->Ctor() != nullptr);
308             return parent->AsClassDefinition()->Ctor()->Function();
309         }
310     }
311 
312     return nullptr;
313 }
314 
GetContainingFunction(const ir::AstNode *node)315 const ir::ScriptFunction *Helpers::GetContainingFunction(const ir::AstNode *node)
316 {
317     for (const auto *parent = node->Parent(); parent != nullptr; parent = parent->Parent()) {
318         if (parent->IsScriptFunction()) {
319             return parent->AsScriptFunction();
320         }
321     }
322 
323     return nullptr;
324 }
325 
GetClassDefiniton(const ir::ScriptFunction *node)326 const ir::ClassDefinition *Helpers::GetClassDefiniton(const ir::ScriptFunction *node)
327 {
328     ASSERT(node->IsConstructor());
329     ASSERT(node->Parent()->IsFunctionExpression());
330     ASSERT(node->Parent()->Parent()->IsMethodDefinition());
331     ASSERT(node->Parent()->Parent()->Parent()->IsClassDefinition());
332 
333     return node->Parent()->Parent()->Parent()->AsClassDefinition();
334 }
335 
IsSpecialPropertyKey(const ir::Expression *expr)336 bool Helpers::IsSpecialPropertyKey(const ir::Expression *expr)
337 {
338     if (!expr->IsStringLiteral()) {
339         return false;
340     }
341 
342     auto *lit = expr->AsStringLiteral();
343     return lit->Str().Is("prototype") || lit->Str().Is("constructor");
344 }
345 
IsConstantPropertyKey(const ir::Expression *expr, bool isComputed)346 bool Helpers::IsConstantPropertyKey(const ir::Expression *expr, bool isComputed)
347 {
348     switch (expr->Type()) {
349         case ir::AstNodeType::IDENTIFIER: {
350             return !isComputed;
351         }
352         case ir::AstNodeType::NUMBER_LITERAL:
353         case ir::AstNodeType::STRING_LITERAL:
354         case ir::AstNodeType::BOOLEAN_LITERAL:
355         case ir::AstNodeType::NULL_LITERAL: {
356             return true;
357         }
358         default:
359             break;
360     }
361 
362     return false;
363 }
364 
ToConstantLiteral(const ir::Expression *expr)365 compiler::Literal Helpers::ToConstantLiteral(const ir::Expression *expr)
366 {
367     switch (expr->Type()) {
368         case ir::AstNodeType::NUMBER_LITERAL: {
369             auto *lit = expr->AsNumberLiteral();
370             if (util::Helpers::IsInteger<uint32_t>(lit->Number().GetDouble())) {
371                 return compiler::Literal(static_cast<uint32_t>(lit->Number().GetDouble()));
372             }
373             return compiler::Literal(lit->Number().GetDouble());
374         }
375         case ir::AstNodeType::STRING_LITERAL: {
376             auto *lit = expr->AsStringLiteral();
377             return compiler::Literal(lit->Str());
378         }
379         case ir::AstNodeType::BOOLEAN_LITERAL: {
380             auto *lit = expr->AsBooleanLiteral();
381             return compiler::Literal(lit->Value());
382         }
383         case ir::AstNodeType::NULL_LITERAL: {
384             return compiler::Literal::NullLiteral();
385         }
386         case ir::AstNodeType::UNDEFINED_LITERAL: {
387             return compiler::Literal::UndefinedLiteral();
388         }
389         default:
390             break;
391     }
392 
393     return compiler::Literal();
394 }
395 
IsBindingPattern(const ir::AstNode *node)396 bool Helpers::IsBindingPattern(const ir::AstNode *node)
397 {
398     return node->IsArrayPattern() || node->IsObjectPattern();
399 }
400 
IsPattern(const ir::AstNode *node)401 bool Helpers::IsPattern(const ir::AstNode *node)
402 {
403     return node->IsArrayPattern() || node->IsObjectPattern() || node->IsAssignmentPattern();
404 }
405 
CollectBindingName(ir::AstNode *node, std::vector<ir::Identifier *> *bindings)406 static void CollectBindingName(ir::AstNode *node, std::vector<ir::Identifier *> *bindings)
407 {
408     switch (node->Type()) {
409         case ir::AstNodeType::IDENTIFIER: {
410             if (!Helpers::IsGlobalIdentifier(node->AsIdentifier()->Name())) {
411                 bindings->push_back(node->AsIdentifier());
412             }
413 
414             break;
415         }
416         case ir::AstNodeType::OBJECT_PATTERN: {
417             for (auto *prop : node->AsObjectPattern()->Properties()) {
418                 CollectBindingName(prop, bindings);
419             }
420             break;
421         }
422         case ir::AstNodeType::ARRAY_PATTERN: {
423             for (auto *element : node->AsArrayPattern()->Elements()) {
424                 CollectBindingName(element, bindings);
425             }
426             break;
427         }
428         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
429             CollectBindingName(node->AsAssignmentPattern()->Left(), bindings);
430             break;
431         }
432         case ir::AstNodeType::PROPERTY: {
433             CollectBindingName(node->AsProperty()->Value(), bindings);
434             break;
435         }
436         case ir::AstNodeType::REST_ELEMENT: {
437             CollectBindingName(node->AsRestElement()->Argument(), bindings);
438             break;
439         }
440         default:
441             break;
442     }
443 }
444 
CollectBindingNames(ir::AstNode *node)445 std::vector<ir::Identifier *> Helpers::CollectBindingNames(ir::AstNode *node)
446 {
447     std::vector<ir::Identifier *> bindings;
448     CollectBindingName(node, &bindings);
449     return bindings;
450 }
451 
CheckImportedName(const ArenaVector<ir::ImportSpecifier *> &specifiers, const ir::ImportSpecifier *specifier, const std::string &fileName)452 void Helpers::CheckImportedName(const ArenaVector<ir::ImportSpecifier *> &specifiers,
453                                 const ir::ImportSpecifier *specifier, const std::string &fileName)
454 {
455     auto newIdentName = specifier->Imported()->Name();
456     auto newAliasName = specifier->Local()->Name();
457     std::stringstream message {};
458 
459     for (auto *it : specifiers) {
460         auto savedIdentName = it->Imported()->Name();
461         auto savedAliasName = it->Local()->Name();
462         if (savedIdentName == savedAliasName && savedAliasName == newIdentName) {
463             message << "Warning: '" << newIdentName << "' has already imported ";
464             break;
465         }
466         if (savedIdentName == newIdentName && newAliasName != savedAliasName) {
467             message << "Warning: '" << newIdentName << "' is explicitly used with alias several times ";
468             break;
469         }
470     }
471 
472     if (message.rdbuf()->in_avail() > 0) {
473         std::cerr << message.str() << "[" << fileName.c_str() << ":" << specifier->Start().line << ":"
474                   << specifier->Start().index << "]" << std::endl;
475     }
476 }
477 
CheckDefaultImportedName(const ArenaVector<ir::ImportDefaultSpecifier *> &specifiers, const ir::ImportDefaultSpecifier *specifier, const std::string &fileName)478 void Helpers::CheckDefaultImportedName(const ArenaVector<ir::ImportDefaultSpecifier *> &specifiers,
479                                        const ir::ImportDefaultSpecifier *specifier, const std::string &fileName)
480 {
481     for (auto *it : specifiers) {
482         if (specifier->Local()->Name() != it->Local()->Name()) {
483             std::cerr << "Warning: default element is explicitly used with alias several times [" << fileName.c_str()
484                       << ":" << specifier->Start().line << ":" << specifier->Start().index << "]" << std::endl;
485             return;
486         }
487     }
488 }
489 
CheckDefaultImport(const ArenaVector<ir::ETSImportDeclaration *> &statements)490 void Helpers::CheckDefaultImport(const ArenaVector<ir::ETSImportDeclaration *> &statements)
491 {
492     for (auto statement : statements) {
493         for (auto specifier : statement->Specifiers()) {
494             if (specifier->Type() == ir::AstNodeType::IMPORT_DEFAULT_SPECIFIER) {
495                 auto fileName = statement->ResolvedSource()->Str();
496                 std::cerr << "Warning: default element has already imported [" << fileName << ":"
497                           << specifier->Start().line << ":" << specifier->Start().index << "]" << std::endl;
498                 return;
499             }
500         }
501     }
502 }
503 
FunctionNameFromParent(const ir::AstNode *parent, ArenaAllocator *allocator)504 static util::StringView FunctionNameFromParent(const ir::AstNode *parent, ArenaAllocator *allocator)
505 {
506     switch (parent->Type()) {
507         case ir::AstNodeType::VARIABLE_DECLARATOR: {
508             const ir::VariableDeclarator *varDecl = parent->AsVariableDeclarator();
509 
510             if (varDecl->Id()->IsIdentifier()) {
511                 return varDecl->Id()->AsIdentifier()->Name();
512             }
513 
514             break;
515         }
516         case ir::AstNodeType::METHOD_DEFINITION: {
517             const ir::MethodDefinition *methodDef = parent->AsMethodDefinition();
518 
519             if (methodDef->Key()->IsIdentifier()) {
520                 auto *ident = methodDef->Id();
521                 ASSERT(ident != nullptr);
522 
523                 if (!ident->IsPrivateIdent()) {
524                     return ident->Name();
525                 }
526 
527                 return util::UString(varbinder::PrivateBinding::ToPrivateBinding(ident->Name()), allocator).View();
528             }
529 
530             break;
531         }
532         case ir::AstNodeType::ASSIGNMENT_EXPRESSION: {
533             const ir::AssignmentExpression *assignment = parent->AsAssignmentExpression();
534 
535             if (assignment->Left()->IsIdentifier()) {
536                 return assignment->Left()->AsIdentifier()->Name();
537             }
538 
539             break;
540         }
541         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
542             const ir::AssignmentExpression *assignment = parent->AsAssignmentPattern();
543 
544             if (assignment->Left()->IsIdentifier()) {
545                 return assignment->Left()->AsIdentifier()->Name();
546             }
547 
548             break;
549         }
550         case ir::AstNodeType::PROPERTY: {
551             const ir::Property *prop = parent->AsProperty();
552 
553             if (prop->Kind() != ir::PropertyKind::PROTO &&
554                 Helpers::IsConstantPropertyKey(prop->Key(), prop->IsComputed())) {
555                 return Helpers::LiteralToPropName(prop->Key());
556             }
557 
558             break;
559         }
560         default:
561             break;
562     }
563 
564     return util::StringView();
565 }
566 
FunctionName(ArenaAllocator *allocator, const ir::ScriptFunction *func)567 util::StringView Helpers::FunctionName(ArenaAllocator *allocator, const ir::ScriptFunction *func)
568 {
569     if (func->Id() != nullptr) {
570         return func->Id()->Name();
571     }
572 
573     if (func->Parent()->IsFunctionDeclaration()) {
574         return "*default*";
575     }
576 
577     const ir::AstNode *parent = func->Parent()->Parent();
578 
579     if (func->IsConstructor()) {
580         parent = parent->Parent();
581         if (parent->AsClassDefinition()->Ident() != nullptr) {
582             return parent->AsClassDefinition()->Ident()->Name();
583         }
584 
585         parent = parent->Parent()->Parent();
586     }
587 
588     return FunctionNameFromParent(parent, allocator);
589 }
590 
ParamName(ArenaAllocator *allocator, const ir::AstNode *param, uint32_t index)591 std::tuple<util::StringView, bool> Helpers::ParamName(ArenaAllocator *allocator, const ir::AstNode *param,
592                                                       uint32_t index)
593 {
594     switch (param->Type()) {
595         case ir::AstNodeType::IDENTIFIER: {
596             return {param->AsIdentifier()->Name(), false};
597         }
598         case ir::AstNodeType::ASSIGNMENT_PATTERN: {
599             const auto *lhs = param->AsAssignmentPattern()->Left();
600             if (lhs->IsIdentifier()) {
601                 return {param->AsAssignmentPattern()->Left()->AsIdentifier()->Name(), false};
602             }
603             break;
604         }
605         case ir::AstNodeType::REST_ELEMENT: {
606             if (param->AsRestElement()->Argument()->IsIdentifier()) {
607                 return {param->AsRestElement()->Argument()->AsIdentifier()->Name(), false};
608             }
609             break;
610         }
611         case ir::AstNodeType::TS_PARAMETER_PROPERTY: {
612             return ParamName(allocator, param->AsTSParameterProperty()->Parameter(), index);
613         }
614         case ir::AstNodeType::ETS_PARAMETER_EXPRESSION: {
615             return {param->AsETSParameterExpression()->Ident()->Name(), false};
616         }
617         default:
618             break;
619     }
620 
621     return {Helpers::ToStringView(allocator, index), true};
622 }
623 
GetEscapedCharacter(const unsigned char c)624 static std::string GetEscapedCharacter(const unsigned char c)
625 {
626     std::stringstream escapedStr;
627     escapedStr << '\\';
628     switch (c) {
629         case lexer::LEX_CHAR_DOUBLE_QUOTE: {
630             escapedStr << '"';
631             break;
632         }
633         case lexer::LEX_CHAR_BS: {
634             escapedStr << 'b';
635             break;
636         }
637         case lexer::LEX_CHAR_TAB: {
638             escapedStr << 't';
639             break;
640         }
641         case lexer::LEX_CHAR_LF: {
642             escapedStr << 'n';
643             break;
644         }
645         case lexer::LEX_CHAR_VT: {
646             escapedStr << 'v';
647             break;
648         }
649         case lexer::LEX_CHAR_FF: {
650             escapedStr << 'f';
651             break;
652         }
653         case lexer::LEX_CHAR_CR: {
654             escapedStr << 'r';
655             break;
656         }
657         case lexer::LEX_CHAR_NULL: {
658             escapedStr << '0';
659             break;
660         }
661         default: {
662             escapedStr << 'u' << std::hex << std::setw(4U) << std::setfill('0') << static_cast<unsigned int>(c);
663             break;
664         }
665     }
666     return escapedStr.str();
667 }
668 
CreateEscapedString(const std::string &str)669 std::string Helpers::CreateEscapedString(const std::string &str)
670 {
671     std::string escapedStr;
672     for (const unsigned char c : str) {
673         // check if a given character is printable
674         // the cast is necessary to avoid undefined behaviour
675         if (LIKELY((std::isprint(c) != 0U || c >= lexer::LEX_ASCII_MAX_BITS) && c != lexer::LEX_CHAR_DOUBLE_QUOTE)) {
676             escapedStr += c;
677         } else {
678             escapedStr += GetEscapedCharacter(c);
679         }
680     }
681     return escapedStr;
682 }
683 
UTF16toUTF8(const char16_t c)684 std::string Helpers::UTF16toUTF8(const char16_t c)
685 {
686     const utf::Utf8Char utf8Ch = utf::ConvertUtf16ToUtf8(c, 0, false);
687     return std::string(reinterpret_cast<const char *>(utf8Ch.ch.data()), utf8Ch.n);
688 }
689 
SplitSignature(std::string_view signature)690 std::pair<std::string_view, std::string_view> Helpers::SplitSignature(std::string_view signature)
691 {
692     auto idx = signature.find_last_of(':');
693     auto stripped = signature.substr(0, idx);
694     idx = stripped.find_last_of('.');
695     auto fullClassName = stripped.substr(0, idx);
696     auto methodName = stripped.substr(idx + 1);
697     idx = fullClassName.find_last_of('.');
698     auto className = fullClassName.substr(idx + 1);
699     return {className, methodName};
700 }
701 
StdLib()702 std::vector<std::string> &Helpers::StdLib()
703 {
704     static std::vector<std::string> stdlib {"std/core",       "std/math",  "std/containers",        "std/time",
705                                             "std/interop/js", "std/debug", "std/debug/concurrency", "std/testing",
706                                             "escompat"};
707     return stdlib;
708 }
709 
IsStdLib(const parser::Program *program)710 bool Helpers::IsStdLib(const parser::Program *program)
711 {
712     auto stdlib = StdLib();
713 
714     // NOTE(rsipka): early check: if program is not a package module then it is not part of the stdlib either
715     if (!program->IsPackageModule()) {
716         return false;
717     }
718 
719     stdlib.emplace_back("std/math/consts");
720 
721     auto fileFolder = program->ModuleName().Mutf8();
722     std::replace(fileFolder.begin(), fileFolder.end(), *compiler::Signatures::METHOD_SEPARATOR.begin(),
723                  *compiler::Signatures::NAMESPACE_SEPARATOR.begin());
724     return std::count(stdlib.begin(), stdlib.end(), fileFolder) != 0;
725 }
726 
727 }  // namespace ark::es2panda::util
728