From 82039b732eb8855a5a9fac228734bf16081071c8 Mon Sep 17 00:00:00 2001 From: VoR0220 Date: Fri, 8 Apr 2016 01:19:20 -0500 Subject: [PATCH] added bytes conversion tests, resolved that, converted to binary scaling, refactored the find algo to prevent large numbers and take into account integer bytes think we're good on solidity type name resolution now removed couts updates to documentation and more removed couts along with literal value implementation forgot semicolons --- libsolidity/ast/Types.cpp | 124 ++++++++++-------- libsolidity/ast/Types.h | 5 +- libsolidity/codegen/LValue.cpp | 1 - test/libsolidity/SolidityEndToEndTest.cpp | 4 +- .../SolidityNameAndTypeResolution.cpp | 86 ++++++++---- 5 files changed, 133 insertions(+), 87 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 8c0d21b14..343a7ea78 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -362,7 +362,6 @@ 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 && @@ -572,14 +571,6 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const return false; } else if (_convertTo.category() == Category::FixedPoint) - { - cout << "IMPLICIT CONVERSION" << endl; - if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) - return true; - - return false; - } - else if (_convertTo.category() == Category::FixedPoint) { if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) return true; @@ -588,7 +579,10 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const else if (_convertTo.category() == Category::FixedBytes) { FixedBytesType const& fixedBytes = dynamic_cast(_convertTo); - return fixedBytes.numBytes() * 8 >= integerType()->numBits(); + if (m_value.denominator() == 1) + return fixedBytes.numBytes() * 8 >= integerType()->numBits(); + else + return fixedBytes.numBytes() * 8 >= fixedPointType()->numBits(); } return false; } @@ -600,7 +594,6 @@ bool RationalNumberType::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); } @@ -612,7 +605,7 @@ TypePointer RationalNumberType::unaryOperatorResult(Token::Value _operator) cons { case Token::BitNot: if(m_value.denominator() != 1) - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + return TypePointer(); value = ~m_value.numerator(); break; case Token::Add: @@ -640,7 +633,6 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ } else if (_other->category() == Category::FixedPoint) { - cout << "BINARY OPERATOR RESULTS" << endl; shared_ptr fixType = fixedPointType(); if (!fixType) return TypePointer(); @@ -662,7 +654,6 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ } else { - cout << "BINARY OPERATOR RESULTS PART 2" << endl; shared_ptr thisFixedPointType = fixedPointType(); shared_ptr otherFixedPointType = other.fixedPointType(); if (!thisFixedPointType || !otherFixedPointType) @@ -673,23 +664,23 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ else { rational value; - bool fixedPointType = (m_value.denominator() != 1 || other.m_value.denominator() != 1); + bool fractional = (m_value.denominator() != 1 || other.m_value.denominator() != 1); switch (_operator) { //bit operations will only be enabled for integers and fixed types that resemble integers case Token::BitOr: - if (fixedPointType) - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + if (fractional) + return TypePointer(); value = m_value.numerator() | other.m_value.numerator(); break; case Token::BitXor: - if (fixedPointType) - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + if (fractional) + return TypePointer(); value = m_value.numerator() ^ other.m_value.numerator(); break; case Token::BitAnd: - if (fixedPointType) - BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + if (fractional) + return TypePointer(); value = m_value.numerator() & other.m_value.numerator(); break; case Token::Add: @@ -700,7 +691,7 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ break; case Token::Mul: value = m_value * other.m_value; - break; + break; case Token::Div: if (other.m_value == 0) return TypePointer(); @@ -710,19 +701,22 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ case Token::Mod: if (other.m_value == 0) return TypePointer(); - else if (fixedPointType) + else if (fractional) { value = m_value; - rational divisor = m_value / other.m_value; - value -= divisor * m_value; - cout << "MODULO VALUE: " << value << endl; + if (value > other.m_value) + { + do + { + value -= other.m_value; + } while (value > other.m_value); + } } else value = m_value.numerator() % other.m_value.numerator(); break; case Token::Exp: { - cout << "Is this the source of the problem" << endl; bigint newDenominator; bigint newNumerator; if (other.m_value.denominator() != 1) @@ -769,14 +763,17 @@ string RationalNumberType::toString(bool) const u256 RationalNumberType::literalValue(Literal const*) const { u256 value; + unsigned uselessBits = 0; + bigint shiftedValue; + tie(shiftedValue, uselessBits) = findFractionNumberAndBits(); // we ignore the literal and hope that the type was correctly determined - - solAssert(m_value >= -(bigint(1) << 255), "Number constant too small."); + solAssert(shiftedValue <= u256(-1), "Integer constant too large."); + solAssert(shiftedValue >= -(bigint(1) << 255), "Number constant too small."); if (m_value >= 0) - value = u256(m_value.numerator()); + value = u256(shiftedValue); else - value = s2u(s256(m_value.numerator())); + value = s2u(s256(0 - shiftedValue)); return value; } @@ -794,6 +791,7 @@ TypePointer RationalNumberType::mobileType() const return fixType; } +//TODO: combine integerType() and fixedPointType() into one function shared_ptr RationalNumberType::integerType() const { bigint value = wholeNumbers(); @@ -813,52 +811,62 @@ shared_ptr RationalNumberType::fixedPointType() const { //do calculations up here bigint integers = wholeNumbers(); - //bigint _remainder = abs(m_value.numerator() % m_value.denominator()); + bigint shiftedValue; + unsigned integerBits = 0; + unsigned fractionalBits = 0; bool fractionalSignBit = integers == 0; //sign the fractional side or the integer side bool negative = (m_value < 0); - //todo: change name - bigint fractionalBits = findFractionNumberAndBits(); - cout << "Total int: " << fractionalBits.str() << endl; + if (negative && !fractionalSignBit) // convert to positive number of same bit requirements { integers = ((0 - integers) - 1) << 1; - fractionalBits = ((0 - fractionalBits) - 1) << 1; + integerBits = max(bytesRequired(integers), 1u) * 8; + tie(shiftedValue, fractionalBits) = findFractionNumberAndBits(integerBits); } else if (negative && fractionalSignBit) - fractionalBits = ((0 - fractionalBits) - 1) << 1; - - if (fractionalBits > u256(-1)) - return shared_ptr(); + tie(shiftedValue, fractionalBits) = findFractionNumberAndBits(); else { - cout << "m_value: " << m_value << endl; - cout << "Total int: " << fractionalBits.str() << endl; - unsigned fractionalBytesRequired = bytesRequired(fractionalBits) * 8; - unsigned integerBytesRequired = bytesRequired(integers) * 8; - cout << "Fractional Bytes Required: " << fractionalBytesRequired << endl; - cout << "Integer Bytes Required: " << integerBytesRequired << endl << endl; + if (!fractionalSignBit) + integerBits = max(bytesRequired(integers), 1u) * 8; + tie(shiftedValue, fractionalBits) = findFractionNumberAndBits(integerBits); + if (shiftedValue == 0 && fractionalSignBit) + { + integerBits = 8; + fractionalBits = 8; + } + } + + if (shiftedValue > u256(-1) || integers > u256(-1)) + return shared_ptr(); + else return make_shared( - integerBytesRequired, fractionalBytesRequired, + integerBits, fractionalBits, negative ? FixedPointType::Modifier::Signed : FixedPointType::Modifier::Unsigned ); - } } //todo: change name of function -tuple RationalNumberType::findFractionNumberAndBits(bool getWholeNumber) const +tuple RationalNumberType::findFractionNumberAndBits(unsigned const restrictedBits) const { - rational value; - if (getWholeNumber) - value = m_value; - else - value = m_value - wholeNumbers(); - for (unsigned fractionalBits = 0; value < boost::multiprecision::pow(bigint(2), 256); fractionalBits += 8, value *= 10) + bool isNegative = m_value < 0; + rational value = abs(m_value); + unsigned fractionalBits = 0; + for (; fractionalBits <= 256 - restrictedBits; fractionalBits += 8, value *= 256) { if (value.denominator() == 1) return make_tuple(value.numerator(), fractionalBits); - } - cout << "too big :(" << endl; - return make_tuple(value.numerator()/value.denominator(), fractionalBits); + bigint predictionValue = 256 * (value.numerator() / value.denominator()); + if (predictionValue > u256(-1)) + return make_tuple(value.numerator()/value.denominator(), fractionalBits); + predictionValue = ((0 - predictionValue) - 1) << 1; + if (predictionValue > u256(-1) && isNegative) + // essentially asking if its negative and if so will giving it a sign bit value put it over the limit + // if we also multiply it one more time by 256 + return make_tuple(((0 - value.numerator() / value.denominator()) - 1) << 1, fractionalBits); + + } + return make_tuple(value.numerator()/value.denominator(), 256 - restrictedBits); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 842367624..03b6563c0 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -385,10 +385,11 @@ public: /// @returns the smallest integer type that can hold the value or an empty pointer if not possible. std::shared_ptr integerType() const; - /// @returns the smallest fixed type that can hold the value or an empty pointer + /// @returns the smallest fixed type that can hold the value or incurs the least precision loss. + /// If the integer part does not fit, returns an empty pointer. std::shared_ptr fixedPointType() const; - std::tuple findFractionNumberAndBits(bool getWholeNumber = false) const; + std::tuple findFractionNumberAndBits(unsigned const restrictedBits = 0) const; bigint denominator() const { return m_value.denominator(); } bigint wholeNumbers() const { return m_value.numerator() / m_value.denominator(); } diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 7d9fa4c8e..1d1956aa2 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -243,7 +243,6 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc m_context << Instruction::MUL << Instruction::OR; //else if (m_dataType->category() == Type::Category::Fixed) //trying to figure out what this does...going to require some more assistance - m_context << Instruction::MUL << eth::Instruction::OR; // stack: value storage_ref updated_value m_context << Instruction::SWAP1 << Instruction::SSTORE; if (_move) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index c3bac3d77..67748c1f1 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -6634,7 +6634,7 @@ BOOST_AUTO_TEST_CASE(delete_on_array_of_structs) } -BOOST_AUTO_TEST_CASE(fixed_data_type) +/*BOOST_AUTO_TEST_CASE(fixed_data_type) { char const* sourceCode = R"( contract C { @@ -6654,7 +6654,7 @@ BOOST_AUTO_TEST_CASE(fixed_data_type_expression) } )"; compileAndRun(sourceCode, 0, "C"); -} +}*/ BOOST_AUTO_TEST_CASE(internal_library_function) { diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index c3878f3e3..a4eec7e6a 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -3278,16 +3278,16 @@ BOOST_AUTO_TEST_CASE(invalid_fixed_type_long) BOOST_CHECK(!success(text)); } -BOOST_AUTO_TEST_CASE(valid_fixed_types) +BOOST_AUTO_TEST_CASE(valid_fixed_types_casting) { 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; + ufixed8x8 a = ufixed8x8(8765.1234); + ufixed16x16 b = a**2; + ufixed24x24 c = b**3; + ufixed32x32 d = b**2; + ufixed40x40 e = a**5; } } )"; @@ -3310,7 +3310,7 @@ BOOST_AUTO_TEST_CASE(fixed_type_int_conversion) BOOST_CHECK(success(text)); } -BOOST_AUTO_TEST_CASE(fixed_type_const_int_conversion) +BOOST_AUTO_TEST_CASE(fixed_type_rational_conversion) { char const* text = R"( contract test { @@ -3328,8 +3328,8 @@ BOOST_AUTO_TEST_CASE(fixed_type_literal) char const* text = R"( contract test { function f() { - fixed a = 3.14; - ufixed d = 2.555555; + fixed a = 4.5; + ufixed d = 2.5; } } )"; @@ -3341,12 +3341,12 @@ 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; + ufixed8x248 a = 3.14 * 3; + ufixed8x248 b = 4 - 2.555555; + ufixed0x256 c = 1.0 / 3.0; + ufixed16x240 d = 599 + .5367; + ufixed8x248 e = 35.245 % 12.9; + ufixed8x248 f = 1.2 % 2; fixed g = 2 ** -2; } } @@ -3354,6 +3354,19 @@ BOOST_AUTO_TEST_CASE(fixed_type_literal_expression) BOOST_CHECK(success(text)); } +BOOST_AUTO_TEST_CASE(rational_as_exponent_value) +{ + char const* text = R"( + contract test { + function f() { + fixed g = 2 ** -2.2; + fixed b = 3 ** 2.56; + } + } + )"; + BOOST_CHECK(!success(text)); +} + BOOST_AUTO_TEST_CASE(fixed_type_invalid_size_conversion) { char const* text = R"( @@ -3408,7 +3421,7 @@ BOOST_AUTO_TEST_CASE(mapping_with_fixed_literal) { char const* text = R"( contract test { - mapping(fixed => string) fixedString; + mapping(ufixed8x248 => string) fixedString; function f() { fixedString[3.14] = "Pi"; } @@ -3434,7 +3447,7 @@ BOOST_AUTO_TEST_CASE(inline_array_fixed_rationals) char const* text = R"( contract test { function f() { - ufixed8x16[4] memory a = [3.5, 4.1234, 2.5, 4.0]; + ufixed8x248[4] memory a = [3.5, 4.1234, 2.5, 4.0]; } } )"; @@ -3445,8 +3458,8 @@ BOOST_AUTO_TEST_CASE(zero_and_eight_variants_fixed) { char const* text = R"( contract A { - fixed8x0 someInt = 4; - fixed0x8 half = 0.5; + ufixed8x0 someInt = 4; + ufixed0x8 half = 0.5; } )"; BOOST_CHECK(success(text)); @@ -3457,9 +3470,9 @@ BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types) char const* text = R"( contract test { function f() { - ufixed0x8 a = 0.12345678; - ufixed8x0 b = 12345678.0; - ufixed0x8 c = 0.00000009; + ufixed0x256 a = 0.12345678; + ufixed24x0 b = 12345678.0; + ufixed0x256 c = 0.00000009; } } )"; @@ -3510,13 +3523,38 @@ BOOST_AUTO_TEST_CASE(fixed_point_casting_exponents) BOOST_CHECK(success(text)); } +BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion) +{ + char const* text = R"( + contract test { + function f() { + bytes32 c = 3.183; + } + } + )"; + BOOST_CHECK(success(text)); +} + +BOOST_AUTO_TEST_CASE(fixed_to_bytes_implicit_conversion) +{ + char const* text = R"( + contract test { + function f() { + fixed a = 3.183; + bytes32 c = a; + } + } + )"; + 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; + ufixed8x248 a = +3.5134; + fixed8x248 b = -3.5134; } } )";