diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index d5e989ac4..c9df00864 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -362,6 +362,7 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons FixedPointType::FixedPointType(int _integerBits, int _fractionalBits, FixedPointType::Modifier _modifier): m_integerBits(_integerBits), m_fractionalBits(_fractionalBits), m_modifier(_modifier) { + cout << "FIXED POINT CONSTRUCTOR: " << _integerBits << "x" << _fractionalBits << endl; solAssert( m_integerBits + m_fractionalBits > 0 && m_integerBits + m_fractionalBits <= 256 && @@ -469,7 +470,6 @@ bool ConstantNumberType::isValidLiteral(Literal const& _literal) { //problem here. If the first digit is a 0 in the string, it won't //turn it into a integer...Using find if not to count the leading 0s. - auto leadingZeroes = find_if_not( radixPoint + 1, _literal.value().end(), @@ -516,18 +516,17 @@ ConstantNumberType::ConstantNumberType(Literal const& _literal) distance(radixPoint + 1, _literal.value().end()) ); numerator = bigint(string(_literal.value().begin(), radixPoint)); - m_value = numerator + denominator; } else m_value = bigint(_literal.value()); + switch (_literal.subDenomination()) { case Literal::SubDenomination::None: case Literal::SubDenomination::Wei: case Literal::SubDenomination::Second: break; - } case Literal::SubDenomination::Szabo: m_value *= bigint("1000000000000"); break; @@ -573,24 +572,6 @@ bool ConstantNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const return false; } else if (_convertTo.category() == Category::FixedPoint) - { - auto targetType = dynamic_cast(&_convertTo); - if (m_value == 0) - return true; - int forSignBit = (targetType->isSigned() ? 1 : 0); - if (m_value > 0) - { - bool properlyScaledBits = m_scalingFactor <= targetType->fractionalBits() ? - true : m_scalingFactor == 1 && targetType->fractionalBits() == 0 ? true : false; - if (m_value <= (u256(-1) >> (256 - targetType->numBits() + forSignBit)) && properlyScaledBits) - return true; - else if (targetType->isSigned() && -m_value <= (u256(1) << (targetType->numBits() - forSignBit)) && properlyScaledBits) - return true; - return false; - } - - } - else if (_convertTo.category() == Category::FixedPoint) { cout << "IMPLICIT CONVERSION" << endl; if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) @@ -598,6 +579,12 @@ bool ConstantNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const return false; } + else if (_convertTo.category() == Category::FixedPoint) + { + if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) + return true; + return false; + } else if (_convertTo.category() == Category::FixedBytes) { FixedBytesType const& fixedBytes = dynamic_cast(_convertTo); @@ -613,6 +600,7 @@ bool ConstantNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const TypePointer intType = integerType(); return intType && intType->isExplicitlyConvertibleTo(_convertTo); } + cout << "EXPLICIT CONVERSION" << endl; TypePointer fixType = fixedPointType(); return fixType && fixType->isExplicitlyConvertibleTo(_convertTo); } @@ -628,10 +616,10 @@ TypePointer ConstantNumberType::unaryOperatorResult(Token::Value _operator) cons value = ~m_value.numerator(); break; case Token::Add: - value = m_value; + value = +(m_value); break; case Token::Sub: - value = -m_value; + value = -(m_value); break; case Token::After: return shared_from_this(); @@ -711,7 +699,6 @@ TypePointer ConstantNumberType::binaryOperatorResult(Token::Value _operator, Typ value = m_value - other.m_value; break; case Token::Mul: - scale = m_scalingFactor - other.m_scalingFactor; value = m_value * other.m_value; break; case Token::Div: @@ -734,6 +721,7 @@ TypePointer ConstantNumberType::binaryOperatorResult(Token::Value _operator, Typ break; case Token::Exp: { + cout << "Is this the source of the problem" << endl; bigint newDenominator; bigint newNumerator; if (other.m_value.denominator() != 1) @@ -781,7 +769,7 @@ u256 ConstantNumberType::literalValue(Literal const*) const { u256 value; // we ignore the literal and hope that the type was correctly determined - solAssert(m_value <= u256(-1), "Number constant too large."); + solAssert(m_value >= -(bigint(1) << 255), "Number constant too small."); if (m_value >= 0) @@ -807,7 +795,7 @@ TypePointer ConstantNumberType::mobileType() const shared_ptr ConstantNumberType::integerType() const { - bigint value = m_value.numerator() / m_value.denominator(); + bigint value = wholeNumbers(); bool negative = (value < 0); if (negative) // convert to positive number of same bit requirements value = ((0 - value) - 1) << 1; @@ -822,28 +810,51 @@ shared_ptr ConstantNumberType::integerType() const shared_ptr ConstantNumberType::fixedPointType() const { - rational value = m_value; - cout << "Original value: " << value << endl; - bool negative = (value < 0); - if (negative) // convert to absolute value - value = abs(value); - if (value > u256(-1)) + //do calculations up here + bigint integers = wholeNumbers(); + //bigint _remainder = abs(m_value.numerator() % m_value.denominator()); + bool fractionalSignBit = integers == 0; //sign the fractional side or the integer side + bool negative = (m_value < 0); + //todo: change name + bigint fractionalBits = fractionalBitsNeeded(); + + if (negative && !fractionalSignBit) // convert to positive number of same bit requirements + { + integers = ((0 - integers) - 1) << 1; + fractionalBits = ((0 - fractionalBits) - 1) << 1; + } + else if (negative && fractionalSignBit) + fractionalBits = ((0 - fractionalBits) - 1) << 1; + + if (fractionalBits > u256(-1)) return shared_ptr(); else { - // need to fix this because these aren't the proper M and N - bigint integerBits = m_value.numerator() / m_value.denominator(); - bigint remains = m_value.numerator() % m_value.denominator(); - cout << "Integer: " << integerBits.str() << endl; - cout << "Remains: " << remains.str() << endl << endl; - bigint fractionalBits; + unsigned totalBytesRequired = bytesRequired(fractionalBits) * 8; + unsigned integerBytesRequired = bytesRequired(integers) * 8; return make_shared( - max(bytesRequired(integerBits), 1u) * 8, max(bytesRequired(fractionalBits), 1u) * 8, + integerBytesRequired, totalBytesRequired - integerBytesRequired, negative ? FixedPointType::Modifier::Signed : FixedPointType::Modifier::Unsigned ); } } +//todo: change name of function +bigint ConstantNumberType::fractionalBitsNeeded() const +{ + auto value = m_value; + for (unsigned fractionalBits = 0; value < boost::multiprecision::pow(bigint(2), 256); fractionalBits += 8, value *= 10) + { + if (value.denominator() == 1) + return value.numerator()/value.denominator(); + for ( ; value.denominator() != 1 && value < boost::multiprecision::pow(bigint(2), fractionalBits); value *= 10) + if (value.denominator() == 1) + return value.numerator()/value.denominator(); + } + cout << "too big :(" << endl; + return value.numerator()/value.denominator(); +} + StringLiteralType::StringLiteralType(Literal const& _literal): diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index e0beabf8b..2039c85e2 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -387,8 +387,11 @@ public: std::shared_ptr integerType() const; /// @returns the smallest fixed type that can hold the value or an empty pointer std::shared_ptr fixedPointType() const; + + bigint fractionalBitsNeeded() const; bigint denominator() const { return m_value.denominator(); } - + bigint wholeNumbers() const { return m_value.numerator() / m_value.denominator(); } + private: rational m_value; }; diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index a2c44cd3d..15446978b 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -436,19 +436,6 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp ); break; } - /*case Type::Category::Fixed: - { - if (targetTypeCategory == Type::Category::Integer) - { - //need some guidance here - } - else if (targetTypeCategory == Type::Category::FixedBytes) - { - //need some guidance here - } - else - //need some guidance here - }*/ case Type::Category::Array: { solAssert(targetTypeCategory == stackTypeCategory, ""); diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp index cbe0c0de1..ef817d5d0 100644 --- a/libsolidity/parsing/Token.cpp +++ b/libsolidity/parsing/Token.cpp @@ -153,9 +153,9 @@ tuple Token::fromIdentifierOrKeyword(s positionM < positionX && positionX < _literal.end() && *positionX == 'x' && - all_of(++positionX, _literal.end(), ::isdigit) + all_of(positionX + 1, _literal.end(), ::isdigit) ) { - int n = parseSize(positionX, _literal.end()); + int n = parseSize(positionX + 1, _literal.end()); if ( 0 <= m && m <= 256 && 0 <= n && n <= 256 && diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 9c41dab85..42d06fd7c 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -3354,6 +3354,303 @@ BOOST_AUTO_TEST_CASE(fixed_type_literal_expression) BOOST_CHECK(success(text)); } +BOOST_AUTO_TEST_CASE(fixed_type_invalid_size_conversion) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 1/3; + ufixed248x8 b = a + 2.5; + } + } + )"; + BOOST_CHECK(!success(text)); +} + +BOOST_AUTO_TEST_CASE(fixed_type_valid_size_conversion) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 1/3; + ufixed248x8 b = ufixed248x8(a) + 2.5; + } + } + )"; + BOOST_CHECK(!success(text)); +} + +BOOST_AUTO_TEST_CASE(uint_array_declaration_with_fixed_type) +{ + char const* text = R"( + contract test { + function f() { + uint[fixed(3.56)] a; + } + } + )"; + BOOST_CHECK(!success(text)); +} + +BOOST_AUTO_TEST_CASE(array_declaration_with_fixed_literal) +{ + char const* text = R"( + contract test { + function f() { + uint[3.56] a; + } + } + )"; + BOOST_CHECK(!success(text)); +} + +BOOST_AUTO_TEST_CASE(mapping_with_fixed_literal) +{ + char const* text = R"( + contract test { + mapping(fixed => string) fixedString; + function f() { + fixedString[3.14] = "Pi"; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(inline_array_fixed_type) +{ + char const* text = R"( + contract test { + function f() { + fixed[3] memory a = [fixed(3.5), fixed(4.1234), fixed(967.32)]; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(inline_array_fixed_rationals) +{ + char const* text = R"( + contract test { + function f() { + ufixed8x16[3] memory a = [3.5, 4.1234, 2.5]; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types) +{ + char const* text = R"( + contract test { + function f() { + ufixed0x64 a = 0.12345678; + ufixed8x0 b = 12345678.0; + ufixed0x64 c = 0.00000009; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(var_capable_of_holding_constant_rationals) +{ + char const* text = R"( + contract test { + function f() { + var a = 0.12345678; + var b = 12345678.0; + var c = 0.00000009; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(invalid_rational_exponent_usage) +{ + char const* text = R"( + contract test { + function f() { + fixed8x8 a = 3 ** 1.5; + fixed24x24 b = 2 ** (1/2); + fixed40x40 c = 42 ** (-1/4); + fixed48x48 d = 16 ** -0.33; + } + } + )"; + BOOST_CHECK(!success(text)); +} + +BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 3 ** fixed(1.5); + fixed b = 2 ** fixed(1/2); + fixed c = 42 ** fixed(-1/4); + fixed d = 16 ** fixed(-0.33); + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(rational_unary_operation) +{ + char const* text = R"( + contract test { + function f() { + fixed a = +3.5134; + fixed b = -2.5145; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(rational_bitnot_unary_operation) +{ + char const* text = R"( + contract test { + function f() { + fixed a = ~3.56; + } + } + )"; + BOOST_CHECK(!success(text)); +} + +BOOST_AUTO_TEST_CASE(rational_bitor_binary_operation) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 1.56 | 3; + } + } + )"; + BOOST_CHECK(!success(text)); +} + +BOOST_AUTO_TEST_CASE(rational_bitxor_binary_operation) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 1.56 ^ 3; + } + } + )"; + BOOST_CHECK(!success(text)); +} + +BOOST_AUTO_TEST_CASE(rational_bitand_binary_operation) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 1.56 & 3; + } + } + )"; + + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(valid_fraction_fixed_type) +{ + char const* text = R"( + contract test { + function f(){ + fixed8x8 a = (2**24)/127; + fixed0x8 b = 1/256; + } + } + )"; + + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(valid_fixed_types) +{ + char const* text = R"( + contract test { + function f(){ + fixed8x8 a = 87654321.12345678; + fixed16x16 b = a**2; + fixed24x24 c = b**3; + fixed32x32 d = b**2; + fixed40x40 e = a**5; + } + } + )"; + + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(fixed_type_int_conversion) +{ + char const* text = R"( + contract test { + function f() { + uint128 a = 3; + int128 b = 4; + fixed c = b; + ufixed d = a; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(fixed_type_const_int_conversion) +{ + char const* text = R"( + contract test { + function f() { + fixed c = 3; + ufixed d = 4; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(fixed_type_literal) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 3.14; + ufixed d = 2.555555; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(fixed_type_literal_expression) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 3.14 * 3; + ufixed b = 4 - 2.555555; + fixed c = 1.0 / 3.0; + ufixed d = 599 + .5367; + ufixed e = 35.245 % 12.9; + ufixed f = 1.2 % 2.00000; + fixed g = 2 ** -2; + } + } + )"; + BOOST_CHECK(success(text)); +} + BOOST_AUTO_TEST_CASE(uint_array_declaration_with_fixed_type) { char const* text = R"( @@ -3367,7 +3664,7 @@ BOOST_AUTO_TEST_CASE(uint_array_declaration_with_fixed_type) } -BOOST_AUTO_TEST_CASE(array_declaration_with_fixed_literal) +BOOST_AUTO_TEST_CASE(array_declaration_with_rational) { char const* text = R"( contract test { @@ -3543,216 +3840,9 @@ BOOST_AUTO_TEST_CASE(rational_bitand_binary_operation) } } )"; - - BOOST_CHECK(success(text)); -} - - -BOOST_AUTO_TEST_CASE(invalid_non_mod_8_fixed_types) -{ - char const* text = R"( - contract test { - function f(){ - fixed8x10 a = 12345678.1234567890; - } - } - )"; - BOOST_CHECK(!success(text)); } -BOOST_AUTO_TEST_CASE(valid_fixed_types) -{ - char const* text = R"( - contract test { - function f(){ - fixed8x8 a = 87654321.12345678; - fixed16x16 b = a**2; - fixed24x24 c = b**(1.5); - fixed32x32 d = b**2; - fixed40x40 e = a**5; - } - } - )"; - - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(fixed_type_int_conversion) -{ - char const* text = R"( - contract test { - function f() { - uint128 a = 3; - int128 b = 4; - fixed c = b; - ufixed d = a; - } - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(fixed_type_const_int_conversion) -{ - char const* text = R"( - contract test { - function f() { - fixed c = 3; - ufixed d = 4; - } - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(fixed_type_literal) -{ - char const* text = R"( - contract test { - function f() { - fixed a = 3.14; - ufixed d = 2.555555; - } - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(fixed_type_literal_expression) -{ - char const* text = R"( - contract test { - function f() { - fixed a = 3.14 * 3; - ufixed b = 4 - 2.555555; - fixed c = 1.0 / 3.0; - ufixed d = 599 + .5367; - ufixed e = 35.245 % 12.9; - ufixed f = 1.2 % 2.00000; - //fixed g = 2 ** -1.5; - //fixed h = -3 ** -5.8; - } - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(fixed_type_literal_seconds_and_wei) -{ - char const* text = R"( - contract test { - function f() { - fixed a = 3.14 wei; - ufixed b = 4.5 seconds; - } - } - )"; - BOOST_CHECK(!success(text)); -} - -BOOST_AUTO_TEST_CASE(uint_array_declaration_with_fixed_type) -{ - char const* text = R"( - contract test { - function f() { - uint[fixed(3.56)] a; - } - } - )"; - BOOST_CHECK(!success(text)); -} - - -BOOST_AUTO_TEST_CASE(array_declaration_with_fixed_literal) -{ - char const* text = R"( - contract test { - function f() { - uint[3.56] a; - } - } - )"; - BOOST_CHECK(!success(text)); -} - -BOOST_AUTO_TEST_CASE(mapping_with_fixed_literal) -{ - char const* text = R"( - contract test { - mapping(fixed => string) fixedString; - function f() { - fixedString[3.14] = "Pi"; - } - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(inline_array_fixed_type) -{ - char const* text = R"( - contract test { - function f() { - fixed[3] memory a = [fixed(3.5), fixed(4.1234), fixed(967.32)]; - } - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(inline_array_fixed_literals) -{ - char const* text = R"( - contract test { - function f() { - fixed[3] memory a = [3.5, 4.1234, 967.32]; - } - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(zero_and_eight_variants_fixed) -{ - char const* text = R"( - contract A { - fixed8x0 someInt = 4; - fixed0x8 half = 0.5; - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types) -{ - char const* text = R"( - contract test { - function f() { - fixed0x8 a = 0.12345678; - fixed8x0 b = 12345678.0; - fixed0x8 c = 0.00000009; - } - } - )"; - BOOST_CHECK(success(text)); -} - -BOOST_AUTO_TEST_CASE(var_capable_of_holding_fixed_constants) -{ - char const* text = R"( - contract test { - function f() { - var a = 0.12345678; - var b = 12345678.0; - var c = 0.00000009; - } - } - )"; - BOOST_CHECK(success(text)); -} - - BOOST_AUTO_TEST_SUITE_END() }