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 #ifndef ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H
17 #define ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H
18 
19 #include "checker/ETSchecker.h"
20 
21 namespace ark::es2panda::checker {
22 
23 template <typename TargetType>
GetOperand(Type *type)24 typename TargetType::UType ETSChecker::GetOperand(Type *type)
25 {
26     switch (ETSType(type)) {
27         case TypeFlag::BYTE: {
28             return type->AsByteType()->GetValue();
29         }
30         case TypeFlag::CHAR: {
31             return type->AsCharType()->GetValue();
32         }
33         case TypeFlag::SHORT: {
34             return type->AsShortType()->GetValue();
35         }
36         case TypeFlag::INT: {
37             return type->AsIntType()->GetValue();
38         }
39         case TypeFlag::LONG: {
40             return type->AsLongType()->GetValue();
41         }
42         case TypeFlag::FLOAT: {
43             return type->AsFloatType()->GetValue();
44         }
45         case TypeFlag::DOUBLE: {
46             return type->AsDoubleType()->GetValue();
47         }
48         case TypeFlag::ETS_BOOLEAN: {
49             return type->AsETSBooleanType()->GetValue();
50         }
51         default: {
52             UNREACHABLE();
53         }
54     }
55 }
56 
57 template <typename TargetType>
PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)58 Type *ETSChecker::PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
59 {
60     using UType = typename TargetType::UType;
61 
62     UType leftValue = GetOperand<TargetType>(left);
63     UType rightValue = GetOperand<TargetType>(right);
64 
65     bool result {};
66     switch (operationType) {
67         case lexer::TokenType::PUNCTUATOR_LESS_THAN: {
68             result = leftValue < rightValue;
69             break;
70         }
71         case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: {
72             result = leftValue <= rightValue;
73             break;
74         }
75         case lexer::TokenType::PUNCTUATOR_GREATER_THAN: {
76             result = leftValue > rightValue;
77             break;
78         }
79         case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: {
80             result = leftValue >= rightValue;
81             break;
82         }
83         case lexer::TokenType::PUNCTUATOR_EQUAL: {
84             result = leftValue == rightValue;
85             break;
86         }
87         case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: {
88             result = leftValue != rightValue;
89             break;
90         }
91         default: {
92             UNREACHABLE();
93         }
94     }
95 
96     return CreateETSBooleanType(result);
97 }
98 
99 template <typename TargetType>
PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)100 Type *ETSChecker::PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType)
101 {
102     using UType = typename TargetType::UType;
103 
104     UType leftValue = GetOperand<TargetType>(left);
105     UType rightValue = GetOperand<TargetType>(right);
106     auto result = leftValue;
107     auto isForbiddenZeroDivision = [&rightValue]() { return std::is_integral<UType>::value && rightValue == 0; };
108 
109     switch (operationType) {
110         case lexer::TokenType::PUNCTUATOR_PLUS:
111         case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: {
112             result = leftValue + rightValue;
113             break;
114         }
115         case lexer::TokenType::PUNCTUATOR_MINUS:
116         case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: {
117             result = leftValue - rightValue;
118             break;
119         }
120         case lexer::TokenType::PUNCTUATOR_DIVIDE:
121         case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: {
122             if (isForbiddenZeroDivision()) {
123                 return nullptr;
124             }
125             result = leftValue / rightValue;
126             break;
127         }
128         case lexer::TokenType::PUNCTUATOR_MULTIPLY:
129         case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: {
130             result = leftValue * rightValue;
131             break;
132         }
133         case lexer::TokenType::PUNCTUATOR_MOD:
134         case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: {
135             if (isForbiddenZeroDivision()) {
136                 return nullptr;
137             }
138             result = HandleModulo<UType>(leftValue, rightValue);
139             break;
140         }
141         default: {
142             UNREACHABLE();
143         }
144     }
145 
146     return Allocator()->New<TargetType>(result);
147 }
148 
149 template <>
HandleModulo(IntType::UType leftValue, IntType::UType rightValue)150 inline IntType::UType ark::es2panda::checker::ETSChecker::HandleModulo<IntType::UType>(IntType::UType leftValue,
151                                                                                        IntType::UType rightValue)
152 {
153     ASSERT(rightValue != 0);
154     return leftValue % rightValue;
155 }
156 
157 template <>
HandleModulo(LongType::UType leftValue, LongType::UType rightValue)158 inline LongType::UType ark::es2panda::checker::ETSChecker::HandleModulo<LongType::UType>(LongType::UType leftValue,
159                                                                                          LongType::UType rightValue)
160 {
161     ASSERT(rightValue != 0);
162     return leftValue % rightValue;
163 }
164 
165 template <>
HandleModulo(FloatType::UType leftValue, FloatType::UType rightValue)166 inline FloatType::UType ark::es2panda::checker::ETSChecker::HandleModulo<FloatType::UType>(FloatType::UType leftValue,
167                                                                                            FloatType::UType rightValue)
168 {
169     return std::fmod(leftValue, rightValue);
170 }
171 
172 template <>
HandleModulo( DoubleType::UType leftValue, DoubleType::UType rightValue)173 inline DoubleType::UType ark::es2panda::checker::ETSChecker::HandleModulo<DoubleType::UType>(
174     DoubleType::UType leftValue, DoubleType::UType rightValue)
175 {
176     return std::fmod(leftValue, rightValue);
177 }
178 
179 template <typename IntegerUType, typename FloatOrIntegerUType>
CastIfFloat(FloatOrIntegerUType num)180 inline IntegerUType CastIfFloat(FloatOrIntegerUType num)
181 {
182     if constexpr (std::is_floating_point_v<FloatOrIntegerUType>) {
183         return CastFloatToInt<FloatOrIntegerUType, IntegerUType>(num);
184     } else {
185         return num;
186     }
187 }
188 
189 template <typename FloatOrIntegerType, typename IntegerType>
HandleBitWiseArithmetic(Type *left, Type *right, lexer::TokenType operationType)190 Type *ETSChecker::HandleBitWiseArithmetic(Type *left, Type *right, lexer::TokenType operationType)
191 {
192     using IntegerUType = typename IntegerType::UType;
193     using UnsignedUType = std::make_unsigned_t<IntegerUType>;
194 
195     UnsignedUType result = 0;
196     UnsignedUType unsignedLeftValue = CastIfFloat<IntegerUType>(GetOperand<FloatOrIntegerType>(left));
197     UnsignedUType unsignedRightValue = CastIfFloat<IntegerUType>(GetOperand<FloatOrIntegerType>(right));
198 
199     auto mask = std::numeric_limits<UnsignedUType>::digits - 1U;
200     auto shift = unsignedRightValue & mask;
201 
202     switch (operationType) {
203         case lexer::TokenType::PUNCTUATOR_BITWISE_AND:
204         case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: {
205             result = unsignedLeftValue & unsignedRightValue;
206             break;
207         }
208         case lexer::TokenType::PUNCTUATOR_BITWISE_OR:
209         case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: {
210             result = unsignedLeftValue | unsignedRightValue;
211             break;
212         }
213         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR:
214         case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: {
215             result = unsignedLeftValue ^ unsignedRightValue;
216             break;
217         }
218         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT:
219         case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: {
220             static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8);
221             result = unsignedLeftValue << shift;
222             break;
223         }
224         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT:
225         case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: {
226             static_assert(sizeof(IntegerUType) == 4 || sizeof(IntegerUType) == 8);
227             result = static_cast<IntegerUType>(unsignedLeftValue) >> shift;  // NOLINT(hicpp-signed-bitwise)
228             break;
229         }
230         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT:
231         case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: {
232             static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8);
233             result = unsignedLeftValue >> shift;
234             break;
235         }
236         default: {
237             UNREACHABLE();
238         }
239     }
240 
241     return Allocator()->New<IntegerType>(result);
242 }
243 }  // namespace ark::es2panda::checker
244 
245 #endif
246