* Copyright (c) 2023-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bigintLowering.h"
#include "compiler/lowering/scopesInit/scopesInitPhase.h"
#include "compiler/lowering/util.h"
namespace ark::es2panda::compiler {
std::string_view BigIntLowering::Name() const
{
return "BigIntLowering";
}
static bool IsNumericType(public_lib::Context *ctx, checker::Type *type)
{
if (type == nullptr) {
return false;
}
auto checker = ctx->GetChecker()->AsETSChecker();
return checker->CheckIfNumeric(type);
}
static bool IsFloatingPoint(ir::Expression *expr, public_lib::Context *ctx)
{
if (expr->IsNumberLiteral()) {
auto number = expr->AsNumberLiteral()->Number();
return number.IsFloat() || number.IsDouble();
}
if (expr->TsType() != nullptr) {
auto checker = ctx->GetChecker()->AsETSChecker();
return checker->CheckIfFloatingPoint(expr->TsType());
}
return false;
}
static ir::Expression *CreateBigInt(public_lib::Context *ctx, ir::BigIntLiteral *literal)
{
auto parser = ctx->parser->AsETSParser();
auto checker = ctx->GetChecker()->AsETSChecker();
std::string src {"new "};
src += Signatures::BUILTIN_BIGINT_CLASS;
src += "(\"";
src += literal->Str().Utf8();
src += "\")";
auto loweringResult = parser->CreateExpression(src);
loweringResult->SetParent(literal->Parent());
InitScopesPhaseETS::RunExternalNode(loweringResult, checker->VarBinder());
checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(loweringResult, NearestScope(loweringResult));
loweringResult->Check(checker);
return loweringResult;
}
static ir::Expression *CovertBigIntToNumber(public_lib::Context *ctx, ir::Expression *expr)
{
ES2PANDA_ASSERT(expr->TsType()->IsETSBigIntType());
auto checker = ctx->GetChecker()->AsETSChecker();
auto parser = ctx->parser->AsETSParser();
ir::Expression *loweringResult =
parser->CreateFormattedExpression("@@E1.doubleValue()", expr->Clone(ctx->Allocator(), nullptr))->AsExpression();
loweringResult->SetRange(expr->Range());
loweringResult->SetParent(expr->Parent());
InitScopesPhaseETS::RunExternalNode(loweringResult, checker->VarBinder());
checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(loweringResult, NearestScope(loweringResult));
loweringResult->Check(checker);
return loweringResult;
}
static ir::Expression *CreateBigIntFromNumericExpression(public_lib::Context *ctx, ir::Expression *expr)
{
auto parser = ctx->parser->AsETSParser();
auto checker = ctx->GetChecker()->AsETSChecker();
auto *argumentExpr = expr->Clone(ctx->allocator, nullptr)->AsExpression();
ir::Expression *loweringResult = parser->CreateFormattedExpression("new BigInt(@@E1)", argumentExpr);
loweringResult->SetRange(expr->Range());
loweringResult->SetParent(expr->Parent());
InitScopesPhaseETS::RunExternalNode(loweringResult, checker->VarBinder());
checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(loweringResult, NearestScope(loweringResult));
loweringResult->Check(checker);
return loweringResult;
}
static bool IsRelationOp(lexer::TokenType opType)
{
return opType == lexer::TokenType::PUNCTUATOR_EQUAL || opType == lexer::TokenType::PUNCTUATOR_NOT_EQUAL ||
opType == lexer::TokenType::PUNCTUATOR_STRICT_EQUAL ||
opType == lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL ||
opType == lexer::TokenType::PUNCTUATOR_LESS_THAN || opType == lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL ||
opType == lexer::TokenType::PUNCTUATOR_GREATER_THAN ||
opType == lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL;
}
static bool IsEqualityOp(lexer::TokenType opType)
{
return (opType == lexer::TokenType::PUNCTUATOR_EQUAL) || (opType == lexer::TokenType::PUNCTUATOR_NOT_EQUAL) ||
(opType == lexer::TokenType::PUNCTUATOR_STRICT_EQUAL) ||
(opType == lexer::TokenType::PUNCTUATOR_NOT_STRICT_EQUAL);
}
static bool ConvertToSuitableCompareExpression(public_lib::Context *ctx, ir::BinaryExpression *expr)
{
auto op = expr->OperatorType();
if (op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND || op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR ||
op == lexer::TokenType::PUNCTUATOR_LOGICAL_AND_EQUAL || op == lexer::TokenType::PUNCTUATOR_LOGICAL_OR_EQUAL ||
op == lexer::TokenType::KEYW_INSTANCEOF) {
return false;
}
auto *left = expr->Left();
auto *right = expr->Right();
bool leftIsBigInt = (left->TsType() != nullptr && left->TsType()->IsETSBigIntType()) || left->IsBigIntLiteral();
bool rightIsBigInt = (right->TsType() != nullptr && right->TsType()->IsETSBigIntType()) || right->IsBigIntLiteral();
if (leftIsBigInt && !rightIsBigInt && IsNumericType(ctx, right->TsType())) {
if (IsEqualityOp(expr->OperatorType())) {
return false;
}
if (IsFloatingPoint(right, ctx) && IsRelationOp(op)) {
ir::Expression *newLeft = CovertBigIntToNumber(ctx, left);
expr->SetLeft(newLeft);
return true;
}
ir::Expression *newRight = CreateBigIntFromNumericExpression(ctx, right);
expr->SetRight(newRight);
return true;
}
if (rightIsBigInt && !leftIsBigInt && IsNumericType(ctx, left->TsType())) {
if (IsEqualityOp(expr->OperatorType())) {
return false;
}
if (IsFloatingPoint(left, ctx) && IsRelationOp(op)) {
ir::Expression *newRight = CovertBigIntToNumber(ctx, right);
expr->SetRight(newRight);
return true;
}
ir::Expression *newLeft = CreateBigIntFromNumericExpression(ctx, left);
expr->SetLeft(newLeft);
return true;
}
return false;
}
bool BigIntLowering::PerformForProgram(parser::Program *const program)
{
program->Ast()->TransformChildrenRecursivelyPostorder(
[ctx = Context()](ir::AstNode *ast) -> ir::AstNode * {
if (ast->IsBigIntLiteral() && ast->Parent() != nullptr && ast->Parent()->IsClassProperty()) {
return CreateBigInt(ctx, ast->AsBigIntLiteral());
}
if (ast->IsBinaryExpression()) {
auto expr = ast->AsBinaryExpression();
bool doCheck = ConvertToSuitableCompareExpression(ctx, expr);
if (doCheck) {
expr->SetTsType(nullptr);
expr->Check(ctx->GetChecker()->AsETSChecker());
}
}
return ast;
},
Name());
return true;
}
}