• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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