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