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