/* * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H #define ES2PANDA_COMPILER_CHECKER_ETS_ARITHMETIC_H #include "checker/ETSchecker.h" namespace ark::es2panda::checker { template typename TargetType::UType ETSChecker::GetOperand(Type *type) { switch (ETSType(type)) { case TypeFlag::BYTE: { return type->AsByteType()->GetValue(); } case TypeFlag::CHAR: { return type->AsCharType()->GetValue(); } case TypeFlag::SHORT: { return type->AsShortType()->GetValue(); } case TypeFlag::INT: { return type->AsIntType()->GetValue(); } case TypeFlag::LONG: { return type->AsLongType()->GetValue(); } case TypeFlag::FLOAT: { return type->AsFloatType()->GetValue(); } case TypeFlag::DOUBLE: { return type->AsDoubleType()->GetValue(); } case TypeFlag::ETS_BOOLEAN: { return type->AsETSBooleanType()->GetValue(); } default: { UNREACHABLE(); } } } template Type *ETSChecker::PerformRelationOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) { using UType = typename TargetType::UType; UType leftValue = GetOperand(left); UType rightValue = GetOperand(right); bool result {}; switch (operationType) { case lexer::TokenType::PUNCTUATOR_LESS_THAN: { result = leftValue < rightValue; break; } case lexer::TokenType::PUNCTUATOR_LESS_THAN_EQUAL: { result = leftValue <= rightValue; break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN: { result = leftValue > rightValue; break; } case lexer::TokenType::PUNCTUATOR_GREATER_THAN_EQUAL: { result = leftValue >= rightValue; break; } case lexer::TokenType::PUNCTUATOR_EQUAL: { result = leftValue == rightValue; break; } case lexer::TokenType::PUNCTUATOR_NOT_EQUAL: { result = leftValue != rightValue; break; } default: { UNREACHABLE(); } } return CreateETSBooleanType(result); } template Type *ETSChecker::PerformArithmeticOperationOnTypes(Type *left, Type *right, lexer::TokenType operationType) { using UType = typename TargetType::UType; UType leftValue = GetOperand(left); UType rightValue = GetOperand(right); auto result = leftValue; auto isForbiddenZeroDivision = [&rightValue]() { return std::is_integral::value && rightValue == 0; }; switch (operationType) { case lexer::TokenType::PUNCTUATOR_PLUS: case lexer::TokenType::PUNCTUATOR_PLUS_EQUAL: { result = leftValue + rightValue; break; } case lexer::TokenType::PUNCTUATOR_MINUS: case lexer::TokenType::PUNCTUATOR_MINUS_EQUAL: { result = leftValue - rightValue; break; } case lexer::TokenType::PUNCTUATOR_DIVIDE: case lexer::TokenType::PUNCTUATOR_DIVIDE_EQUAL: { if (isForbiddenZeroDivision()) { return nullptr; } result = leftValue / rightValue; break; } case lexer::TokenType::PUNCTUATOR_MULTIPLY: case lexer::TokenType::PUNCTUATOR_MULTIPLY_EQUAL: { result = leftValue * rightValue; break; } case lexer::TokenType::PUNCTUATOR_MOD: case lexer::TokenType::PUNCTUATOR_MOD_EQUAL: { if (isForbiddenZeroDivision()) { return nullptr; } result = HandleModulo(leftValue, rightValue); break; } default: { UNREACHABLE(); } } return Allocator()->New(result); } template <> inline IntType::UType ark::es2panda::checker::ETSChecker::HandleModulo(IntType::UType leftValue, IntType::UType rightValue) { ASSERT(rightValue != 0); return leftValue % rightValue; } template <> inline LongType::UType ark::es2panda::checker::ETSChecker::HandleModulo(LongType::UType leftValue, LongType::UType rightValue) { ASSERT(rightValue != 0); return leftValue % rightValue; } template <> inline FloatType::UType ark::es2panda::checker::ETSChecker::HandleModulo(FloatType::UType leftValue, FloatType::UType rightValue) { return std::fmod(leftValue, rightValue); } template <> inline DoubleType::UType ark::es2panda::checker::ETSChecker::HandleModulo( DoubleType::UType leftValue, DoubleType::UType rightValue) { return std::fmod(leftValue, rightValue); } template inline IntegerUType CastIfFloat(FloatOrIntegerUType num) { if constexpr (std::is_floating_point_v) { return CastFloatToInt(num); } else { return num; } } template Type *ETSChecker::HandleBitWiseArithmetic(Type *left, Type *right, lexer::TokenType operationType) { using IntegerUType = typename IntegerType::UType; using UnsignedUType = std::make_unsigned_t; UnsignedUType result = 0; UnsignedUType unsignedLeftValue = CastIfFloat(GetOperand(left)); UnsignedUType unsignedRightValue = CastIfFloat(GetOperand(right)); auto mask = std::numeric_limits::digits - 1U; auto shift = unsignedRightValue & mask; switch (operationType) { case lexer::TokenType::PUNCTUATOR_BITWISE_AND: case lexer::TokenType::PUNCTUATOR_BITWISE_AND_EQUAL: { result = unsignedLeftValue & unsignedRightValue; break; } case lexer::TokenType::PUNCTUATOR_BITWISE_OR: case lexer::TokenType::PUNCTUATOR_BITWISE_OR_EQUAL: { result = unsignedLeftValue | unsignedRightValue; break; } case lexer::TokenType::PUNCTUATOR_BITWISE_XOR: case lexer::TokenType::PUNCTUATOR_BITWISE_XOR_EQUAL: { result = unsignedLeftValue ^ unsignedRightValue; break; } case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT: case lexer::TokenType::PUNCTUATOR_LEFT_SHIFT_EQUAL: { static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8); result = unsignedLeftValue << shift; break; } case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_RIGHT_SHIFT_EQUAL: { static_assert(sizeof(IntegerUType) == 4 || sizeof(IntegerUType) == 8); result = static_cast(unsignedLeftValue) >> shift; // NOLINT(hicpp-signed-bitwise) break; } case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT: case lexer::TokenType::PUNCTUATOR_UNSIGNED_RIGHT_SHIFT_EQUAL: { static_assert(sizeof(UnsignedUType) == 4 || sizeof(UnsignedUType) == 8); result = unsignedLeftValue >> shift; break; } default: { UNREACHABLE(); } } return Allocator()->New(result); } } // namespace ark::es2panda::checker #endif