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