• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-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 "varbinder/ETSBinder.h"
17 #include "stringComparison.h"
18 #include "checker/ETSchecker.h"
19 #include "parser/parserImpl.h"
20 #include "utils/arena_containers.h"
21 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
22 #include "compiler/lowering/util.h"
23 
24 namespace ark::es2panda::compiler {
25 
26 /**
27  * Check if we got String comparison such like < , <=, >, >=, e.g.
28  *
29  *   let a:String = "AAAA"
30  *   let b:String = "BBB"
31  *   ..
32  *   if (a >= b) {..}
33  *
34  * so such test has to be updated by our lowering to
35  *
36  *   if (a.CompareTo(b) >= 0)
37  */
38 
CheckOperatorType(ir::BinaryExpression * expr)39 bool CheckOperatorType(ir::BinaryExpression *expr)
40 {
41     switch (expr->OperatorType()) {
42         case lexer::TokenType::PUNCTUATOR_LESS_THAN:
43         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL:
44         case lexer::TokenType::PUNCTUATOR_GREATER_THAN:
45         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
46             return true;
47         }
48         default:
49             return false;
50     }
51 }
52 
IsStringComparison(ir::AstNode * node)53 bool StringComparisonLowering::IsStringComparison(ir::AstNode *node)
54 {
55     if (node->IsBinaryExpression()) {
56         auto *expr = node->AsBinaryExpression();
57 
58         if (!CheckOperatorType(expr)) {
59             return false;
60         }
61 
62         if ((expr->Left()->TsType() == nullptr) || (expr->Right()->TsType() == nullptr)) {
63             return false;
64         }
65 
66         if (expr->Left()->TsType()->IsETSStringType() && expr->Right()->TsType()->IsETSStringType()) {
67             return true;
68         }
69     }
70     return false;
71 }
72 
ProcessBinaryExpression(ir::BinaryExpression * expr,public_lib::Context * ctx)73 void StringComparisonLowering::ProcessBinaryExpression(ir::BinaryExpression *expr, public_lib::Context *ctx)
74 {
75     ES2PANDA_ASSERT(expr->IsBinaryExpression());
76     ES2PANDA_ASSERT(expr->Left()->TsType()->IsETSStringType() && expr->Right()->TsType()->IsETSStringType());
77 
78     // reset types is any, will re-run checker to set them once again properly
79     expr->SetTsType(nullptr);
80 
81     checker::ETSChecker *checker = ctx->checker->AsETSChecker();
82     ArenaVector<ir::Expression *> callArgs(checker->Allocator()->Adapter());
83     ir::Expression *accessor = nullptr;
84     auto *zeroExpr = checker->AllocNode<ir::NumberLiteral>(util::StringView("0"));
85     auto *const callee = checker->AllocNode<ir::Identifier>("compareTo", checker->Allocator());
86     ES2PANDA_ASSERT(callee != nullptr);
87     auto *var = checker->GlobalBuiltinETSStringType()->GetProperty(callee->AsIdentifier()->Name(),
88                                                                    checker::PropertySearchFlags::SEARCH_METHOD);
89     callee->SetVariable(var);
90     accessor = checker->AllocNode<ir::MemberExpression>(expr->Left(), callee, ir::MemberExpressionKind::PROPERTY_ACCESS,
91                                                         false, false);
92 
93     callArgs.push_back(expr->Right());
94     auto callExpression = checker->AllocNode<ir::CallExpression>(accessor, std::move(callArgs), nullptr, false, false);
95     expr->SetLeft(callExpression);
96     expr->SetRight(zeroExpr);
97 
98     auto *parent = expr->Parent();
99     InitScopesPhaseETS::RunExternalNode(expr, ctx->checker->VarBinder());
100     checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(parent, NearestScope(parent));
101 
102     if (parent->IsBinaryExpression() || parent->IsConditionalExpression()) {
103         parent->AsExpression()->SetTsType(nullptr);
104         parent->Check(checker);
105     } else {
106         expr->Check(checker);
107     }
108 }
109 
PerformForModule(public_lib::Context * ctx,parser::Program * program)110 bool StringComparisonLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program)
111 {
112     checker::ETSChecker *checker = ctx->checker->AsETSChecker();
113     [[maybe_unused]] ArenaVector<ir::BinaryExpression *> foundNodes(checker->Allocator()->Adapter());
114     // CC-OFFNXT(G.FMT.14-CPP) project code style
115     program->Ast()->IterateRecursively([&foundNodes, this](ir::AstNode *ast) -> ir::AstNode * {
116         if (IsStringComparison(ast)) {
117             foundNodes.push_back(ast->AsBinaryExpression());
118         }
119         return ast;
120     });
121 
122     for ([[maybe_unused]] auto &it : foundNodes) {
123         ProcessBinaryExpression(it, ctx);
124     }
125 
126     return true;
127 }
128 }  // namespace ark::es2panda::compiler
129