1 /**
2  * Copyright (c) 2023-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 "bigintLowering.h"
17 
18 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
19 #include "compiler/lowering/util.h"
20 
21 namespace ark::es2panda::compiler {
22 
Name() const23 std::string_view BigIntLowering::Name() const
24 {
25     return "BigIntLowering";
26 }
27 
CreateBigInt(public_lib::Context *ctx, ir::BigIntLiteral *literal)28 ir::Expression *CreateBigInt(public_lib::Context *ctx, ir::BigIntLiteral *literal)
29 {
30     auto parser = ctx->parser->AsETSParser();
31     auto checker = ctx->checker->AsETSChecker();
32 
33     // This will change the bigint literal node into the new class instance expression:
34     // 123456n => new BigInt("123456")
35     std::string src {"new "};
36     src += Signatures::BUILTIN_BIGINT_CLASS;
37     src += "(\"";
38     src += literal->Str().Utf8();
39     src += "\")";
40 
41     auto loweringResult = parser->CreateExpression(src);
42     loweringResult->SetParent(literal->Parent());
43 
44     InitScopesPhaseETS::RunExternalNode(loweringResult, checker->VarBinder());
45     checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(loweringResult, NearestScope(loweringResult));
46     loweringResult->Check(checker);
47 
48     return loweringResult;
49 }
50 
ReplaceStrictEqualByNormalEqual(ir::BinaryExpression *expr)51 bool ReplaceStrictEqualByNormalEqual(ir::BinaryExpression *expr)
52 {
53     auto left = expr->Left()->TsType();
54     auto isBigintLeft = (left != nullptr && left->IsETSBigIntType()) || expr->Left()->IsBigIntLiteral();
55     auto right = expr->Right()->TsType();
56     auto isBigintRight = (right != nullptr && right->IsETSBigIntType()) || expr->Right()->IsBigIntLiteral();
57     if (!isBigintLeft && !isBigintRight) {
58         return false;
59     }
60 
61     if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_STRICT_EQUAL) {
62         expr->SetOperator(lexer::TokenType::PUNCTUATOR_EQUAL);
63     } else if (expr->OperatorType() == lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL) {
64         expr->SetOperator(lexer::TokenType::PUNCTUATOR_NOT_EQUAL);
65     } else {
66         return false;
67     }
68 
69     return true;
70 }
71 
72 // Currently there are no compile time operations for bigint.
RemoveConst(ir::BinaryExpression *expr)73 bool RemoveConst(ir::BinaryExpression *expr)
74 {
75     bool isRemoved = false;
76     auto left = expr->Left()->TsType();
77     if (left != nullptr && left->IsETSBigIntType()) {
78         left->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
79         isRemoved = true;
80     }
81 
82     auto right = expr->Right()->TsType();
83     if (right != nullptr && right->IsETSBigIntType()) {
84         right->RemoveTypeFlag(checker::TypeFlag::CONSTANT);
85         isRemoved = true;
86     }
87 
88     return isRemoved;
89 }
90 
Perform(public_lib::Context *const ctx, parser::Program *const program)91 bool BigIntLowering::Perform(public_lib::Context *const ctx, parser::Program *const program)
92 {
93     for (const auto &[_, ext_programs] : program->ExternalSources()) {
94         (void)_;
95         for (auto *const extProg : ext_programs) {
96             Perform(ctx, extProg);
97         }
98     }
99 
100     auto checker = ctx->checker->AsETSChecker();
101 
102     program->Ast()->TransformChildrenRecursively(
103         [ctx, checker](ir::AstNode *ast) -> ir::AstNode * {
104             if (ast->IsBigIntLiteral() && ast->Parent() != nullptr && ast->Parent()->IsClassProperty()) {
105                 return CreateBigInt(ctx, ast->AsBigIntLiteral());
106             }
107 
108             if (ast->IsBinaryExpression()) {
109                 auto expr = ast->AsBinaryExpression();
110                 bool doCheck = ReplaceStrictEqualByNormalEqual(expr);
111                 doCheck |= RemoveConst(expr);
112                 if (doCheck) {
113                     expr->Check(checker);
114                 }
115             }
116 
117             return ast;
118         },
119         Name());
120 
121     return true;
122 }
123 
124 }  // namespace ark::es2panda::compiler
125