diff options
author | RJ Catalano <rcatalano@macsales.com> | 2016-02-19 06:39:11 +0800 |
---|---|---|
committer | VoR0220 <catalanor0220@gmail.com> | 2016-05-10 00:41:02 +0800 |
commit | 9a075458ad104921c9d747cd34d3e5c299638406 (patch) | |
tree | c2005fb8b8032c54c7ab65196e952d01ab747327 /libsolidity/ast | |
parent | 9e36bdda8a9552f1885e0a63a85db588623b39b2 (diff) | |
download | dexon-solidity-9a075458ad104921c9d747cd34d3e5c299638406.tar.gz dexon-solidity-9a075458ad104921c9d747cd34d3e5c299638406.tar.zst dexon-solidity-9a075458ad104921c9d747cd34d3e5c299638406.zip |
initial work for fixed types...potentially needing a constant literal type for this
notation
Rational implemented...trying to figure out exponential
fix for token bug, also quick fix for the wei and seconds
fixed problem with var...probably a conversion problem for fixed in size capabilities
adding fixed type tests
Removing bitshift and regrouping fixed type tests together
size capabilities functioning properly for fixed types
got exponents up and working with their inverse, changed a few of the tests....something is working that likely shouldn't be
slight changes to how to flip the rational negative around...still trying to figure it out
tests added
updated tests
odd differences in trying soltest from solc binary, let me know if you can replicate
test not working for odd reason
fixed test problem with fixed literals...still need a way to log this error
broken up the tests, added some, changed some things in types and began compiler work
moar tests and prepping for rebuilding much of the types.cpp file
further fixing
initial work for fixed types...potentially needing a constant literal type for this
Diffstat (limited to 'libsolidity/ast')
-rw-r--r-- | libsolidity/ast/Types.cpp | 472 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 69 |
2 files changed, 461 insertions, 80 deletions
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index d541de23..b1a0f4e6 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -32,6 +32,7 @@ using namespace std; using namespace dev; using namespace dev::solidity; +using rational = boost::rational<bigint>; void StorageOffsets::computeOffsets(TypePointers const& _types) { @@ -123,6 +124,7 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type) Token::Value token = _type.token(); unsigned int m = _type.firstNumber(); + unsigned int n = _type.secondNumber(); switch (token) { @@ -132,10 +134,18 @@ TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type) return make_shared<IntegerType>(m, IntegerType::Modifier::Unsigned); case Token::BytesM: return make_shared<FixedBytesType>(m); + case Token::FixedMxN: + return make_shared<FixedPointType>(m, n, FixedPointType::Modifier::Signed); + case Token::UFixedMxN: + return make_shared<FixedPointType>(m, n, FixedPointType::Modifier::Unsigned); case Token::Int: return make_shared<IntegerType>(256, IntegerType::Modifier::Signed); case Token::UInt: return make_shared<IntegerType>(256, IntegerType::Modifier::Unsigned); + case Token::Fixed: + return make_shared<FixedPointType>(128, 128, FixedPointType::Modifier::Signed); + case Token::UFixed: + return make_shared<FixedPointType>(128, 128, FixedPointType::Modifier::Unsigned); case Token::Byte: return make_shared<FixedBytesType>(1); case Token::Address: @@ -171,9 +181,10 @@ TypePointer Type::forLiteral(Literal const& _literal) case Token::FalseLiteral: return make_shared<BoolType>(); case Token::Number: - if (!IntegerConstantType::isValidLiteral(_literal)) - return TypePointer(); - return make_shared<IntegerConstantType>(_literal); + if (ConstantNumberType::isValidLiteral(_literal)) + return make_shared<ConstantNumberType>(_literal); + else + return TypePointer(); case Token::StringLiteral: return make_shared<StringLiteralType>(_literal); default: @@ -246,17 +257,30 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const { - if (_convertTo.category() != category()) - return false; - IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo); - if (convertTo.m_bits < m_bits) - return false; - if (isAddress()) - return convertTo.isAddress(); - else if (isSigned()) - return convertTo.isSigned(); + if (_convertTo.category() == category()) + { + IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo); + if (convertTo.m_bits < m_bits) + return false; + if (isAddress()) + return convertTo.isAddress(); + else if (isSigned()) + return convertTo.isSigned(); + else + return !convertTo.isSigned() || convertTo.m_bits > m_bits; + } + else if (_convertTo.category() == Category::FixedPoint) + { + FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo); + if (convertTo.integerBits() < m_bits) + return false; + else if (isSigned()) + return convertTo.isSigned(); + else + return !convertTo.isSigned() || convertTo.integerBits() > m_bits; + } else - return !convertTo.isSigned() || convertTo.m_bits > m_bits; + return false; } bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const @@ -302,7 +326,7 @@ string IntegerType::toString(bool) const TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { - if (_other->category() != Category::IntegerConstant && _other->category() != category()) + if (_other->category() != Category::NumberConstant && _other->category() != category()) return TypePointer(); auto commonType = dynamic_pointer_cast<IntegerType const>(Type::commonType(shared_from_this(), _other)); @@ -335,11 +359,134 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons return MemberList::MemberMap(); } -bool IntegerConstantType::isValidLiteral(const Literal& _literal) +FixedPointType::FixedPointType(int _integerBits, int _fractionalBits, FixedPointType::Modifier _modifier): + m_integerBits(_integerBits), m_fractionalBits(_fractionalBits), m_modifier(_modifier) +{ + solAssert( + m_integerBits + m_fractionalBits > 0 && + m_integerBits + m_fractionalBits <= 256 && + m_integerBits % 8 == 0 && + m_fractionalBits % 8 == 0, + "Invalid bit number(s) for fixed type: " + + dev::toString(_integerBits) + "x" + dev::toString(_fractionalBits) + ); +} + +bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const +{ + if (_convertTo.category() == category()) + { + FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo); + if (convertTo.m_integerBits < m_integerBits || convertTo.m_fractionalBits < m_fractionalBits) + return false; + else if (isSigned()) + return convertTo.isSigned(); + else + return !convertTo.isSigned() || (convertTo.m_integerBits > m_integerBits); + } + else if (_convertTo.category() == Category::Integer) + { + IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo); + if (convertTo.numBits() < m_integerBits) + return false; + else if (isSigned()) + return convertTo.isSigned(); + else + return !convertTo.isSigned() || convertTo.numBits() > m_integerBits; + } + else + return false; +} + +bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const +{ + return _convertTo.category() == category() || + _convertTo.category() == Category::Integer || + _convertTo.category() == Category::Enum || + _convertTo.category() == Category::FixedBytes; +} + +TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const +{ + // "delete" is ok for all fixed types + if (_operator == Token::Delete) + return make_shared<TupleType>(); + // for fixed, we allow +, -, ++ and -- + else if ( + _operator == Token::Add || + _operator == Token::Sub || + _operator == Token::Inc || + _operator == Token::Dec || + _operator == Token::After + ) + return shared_from_this(); + else + return TypePointer(); +} + +bool FixedPointType::operator==(Type const& _other) const +{ + if (_other.category() != category()) + return false; + FixedPointType const& other = dynamic_cast<FixedPointType const&>(_other); + return other.m_integerBits == m_integerBits && other.m_fractionalBits == m_fractionalBits && other.m_modifier == m_modifier; +} + +string FixedPointType::toString(bool) const +{ + string prefix = isSigned() ? "fixed" : "ufixed"; + return prefix + dev::toString(m_integerBits) + "x" + dev::toString(m_fractionalBits); +} + +TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const +{ + if (_other->category() != Category::NumberConstant + && _other->category() != category() + && _other->category() != Category::Integer + ) + return TypePointer(); + auto commonType = dynamic_pointer_cast<FixedPointType const>(Type::commonType(shared_from_this(), _other)); + + if (!commonType) + return TypePointer(); + + // All fixed types can be compared + if (Token::isCompareOp(_operator)) + return commonType; + if (Token::isBooleanOp(_operator)) + return TypePointer(); + return commonType; +} + +bool ConstantNumberType::isValidLiteral(Literal const& _literal) { try { - bigint x(_literal.value()); + rational numerator; + rational denominator(1); + auto radixPoint = find(_literal.value().begin(), _literal.value().end(), '.'); + if (radixPoint != _literal.value().end()) + { + //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(), + [](char const& a) { return a == '0'; } + ); + auto fractionalBegin = leadingZeroes != _literal.value().end() ? + leadingZeroes : radixPoint + 1; + denominator = bigint(string(fractionalBegin, _literal.value().end())); + denominator /= boost::multiprecision::pow( + bigint(10), + distance(radixPoint + 1, _literal.value().end()) + ); + numerator = bigint(string(_literal.value().begin(), radixPoint)); + rational x = numerator + denominator; + } + else + rational x = bigint(_literal.value()); } catch (...) { @@ -348,16 +495,40 @@ bool IntegerConstantType::isValidLiteral(const Literal& _literal) return true; } -IntegerConstantType::IntegerConstantType(Literal const& _literal) +ConstantNumberType::ConstantNumberType(Literal const& _literal) { - m_value = bigint(_literal.value()); + rational numerator; + rational denominator = bigint(1); + auto radixPoint = find(_literal.value().begin(), _literal.value().end(), '.'); + if (radixPoint != _literal.value().end()) + { + auto leadingZeroes = find_if_not( + radixPoint + 1, + _literal.value().end(), + [](char const& a) { return a == '0'; } + ); + auto fractionalBegin = leadingZeroes != _literal.value().end() ? + leadingZeroes : radixPoint + 1; + //separatly grabbing the numerator, denominator for conversions + denominator = bigint(string(fractionalBegin, _literal.value().end())); + denominator /= boost::multiprecision::pow( + bigint(10), + 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: - case Literal::SubDenomination::None: break; + } case Literal::SubDenomination::Szabo: m_value *= bigint("1000000000000"); break; @@ -385,20 +556,79 @@ IntegerConstantType::IntegerConstantType(Literal const& _literal) } } -bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) const +bool ConstantNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const { - if (auto targetType = dynamic_cast<IntegerType const*>(&_convertTo)) + if (_convertTo.category() == Category::Integer) + { + auto targetType = dynamic_cast<IntegerType const*>(&_convertTo); + if (m_value == 0) + return true; + int forSignBit = (targetType->isSigned() ? 1 : 0); + if (m_scalingFactor == 0) //if current type is integer + { + if (m_value > 0) + { + if (m_value <= (u256(-1) >> (256 - targetType->numBits() + forSignBit))) + return true; + } + else if (targetType->isSigned() && -m_value <= (u256(1) << (targetType->numBits() - forSignBit))) + return true; + return false; + } + else if (m_scalingFactor != 0) //if current type is fixed point + { + if (m_value > 0) + { + if (leftOfRadix() <= (u256(-1) >> (256 - targetType->numBits() + forSignBit))) + return true; + } + else if (targetType->isSigned() && -leftOfRadix() <= (u256(1) << (targetType->numBits() - forSignBit))) + return true; + return false; + } + } + else if (_convertTo.category() == Category::FixedPoint) { + auto targetType = dynamic_cast<FixedPointType const*>(&_convertTo); if (m_value == 0) return true; int forSignBit = (targetType->isSigned() ? 1 : 0); - if (m_value > 0) + if (m_scalingFactor == 0) //if the current type is an integer, focus on the integer bits { - if (m_value <= (u256(-1) >> (256 - targetType->numBits() + forSignBit))) + if (m_value > 0) + { + if (m_value <= (u256(-1) >> (256 - targetType->integerBits() + forSignBit))) + return true; + } + else if (targetType->isSigned() && -m_value <= (u256(1) << (targetType->integerBits() - forSignBit))) + return true; + return false; + } + else if (m_scalingFactor != 0) //if the current type is fixed point, focus on both the + { //integer bits and fractional bits and ensure they fit + if (m_value > 0) + { + if ( + leftOfRadix() <= (u256(-1) >> (256 - targetType->integerBits() + forSignBit)) && + rightOfRadix() <= (u256(-1) >> (256 - targetType->fractionalBits() + forSignBit)) + ) + return true; + } + else if ( + targetType->isSigned() && + -leftOfRadix() <= (u256(1) >> (256 - targetType->integerBits() + forSignBit)) && + -rightOfRadix() <= (u256(1) >> (256 - targetType->fractionalBits() + forSignBit)) + ) return true; + return false; } - else if (targetType->isSigned() && -m_value <= (u256(1) << (targetType->numBits() - forSignBit))) + } + else if (_convertTo.category() == Category::FixedPoint) + { + cout << "IMPLICIT CONVERSION" << endl; + if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) return true; + return false; } else if (_convertTo.category() == Category::FixedBytes) @@ -406,23 +636,29 @@ bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) cons FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo); return fixedBytes.numBytes() * 8 >= integerType()->numBits(); } - else - return false; + return false; } -bool IntegerConstantType::isExplicitlyConvertibleTo(Type const& _convertTo) const +bool ConstantNumberType::isExplicitlyConvertibleTo(Type const& _convertTo) const { - TypePointer intType = integerType(); - return intType && intType->isExplicitlyConvertibleTo(_convertTo); + if (m_value.denominator() == 1) + { + TypePointer intType = integerType(); + return intType && intType->isExplicitlyConvertibleTo(_convertTo); + } + TypePointer fixType = fixedPointType(); + return fixType && fixType->isExplicitlyConvertibleTo(_convertTo); } -TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) const +TypePointer ConstantNumberType::unaryOperatorResult(Token::Value _operator) const { - bigint value; + rational value; switch (_operator) { case Token::BitNot: - value = ~m_value; + if(m_value.denominator() != 1) + BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + value = ~m_value.numerator(); break; case Token::Add: value = m_value; @@ -435,10 +671,10 @@ TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) con default: return TypePointer(); } - return make_shared<IntegerConstantType>(value); + return make_shared<ConstantNumberType>(value); } -TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const +TypePointer ConstantNumberType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { if (_other->category() == Category::Integer) { @@ -447,106 +683,176 @@ TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, Ty return TypePointer(); return intType->binaryOperatorResult(_operator, _other); } + else if (_other->category() == Category::FixedPoint) + { + cout << "BINARY OPERATOR RESULTS" << endl; + shared_ptr<FixedPointType const> fixType = fixedPointType(); + if (!fixType) + return TypePointer(); + return fixType->binaryOperatorResult(_operator, _other); + } else if (_other->category() != category()) return TypePointer(); - IntegerConstantType const& other = dynamic_cast<IntegerConstantType const&>(*_other); + ConstantNumberType const& other = dynamic_cast<ConstantNumberType const&>(*_other); if (Token::isCompareOp(_operator)) { - shared_ptr<IntegerType const> thisIntegerType = integerType(); - shared_ptr<IntegerType const> otherIntegerType = other.integerType(); - if (!thisIntegerType || !otherIntegerType) - return TypePointer(); - return thisIntegerType->binaryOperatorResult(_operator, otherIntegerType); + if (m_value.denominator() == 1) + { + shared_ptr<IntegerType const> thisIntegerType = integerType(); + shared_ptr<IntegerType const> otherIntegerType = other.integerType(); + if (!thisIntegerType || !otherIntegerType) + return TypePointer(); + return thisIntegerType->binaryOperatorResult(_operator, otherIntegerType); + } + else + { + cout << "BINARY OPERATOR RESULTS PART 2" << endl; + shared_ptr<FixedPointType const> thisFixedPointType = fixedPointType(); + shared_ptr<FixedPointType const> otherFixedPointType = other.fixedPointType(); + if (!thisFixedPointType || !otherFixedPointType) + return TypePointer(); + return thisFixedPointType->binaryOperatorResult(_operator, otherFixedPointType); + } } else { - bigint value; + rational value; + bool fixedPointType = (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: - value = m_value | other.m_value; + if (fixedPointType) + BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + value = m_value.numerator() | other.m_value.numerator(); break; case Token::BitXor: - value = m_value ^ other.m_value; + if (fixedPointType) + BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + value = m_value.numerator() ^ other.m_value.numerator(); break; case Token::BitAnd: - value = m_value & other.m_value; + if (fixedPointType) + BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Cannot perform bit operations on non integer fixed type.")); + value = m_value.numerator() & other.m_value.numerator(); break; case Token::Add: - value = m_value + other.m_value; + value = leftOfRadix() + other.leftOfRadix(); + value *= boost::multiprecision::pow(bigint(10), scale); + value += rightOfRadix() + other.rightOfRadix();; break; case Token::Sub: - value = m_value - other.m_value; + value = leftOfRadix() - other.leftOfRadix(); + if (rightOfRadix() < other.rightOfRadix()) + scale = other.m_scalingFactor; + value *= boost::multiprecision::pow(bigint(10), scale); + value += (rightOfRadix() - other.rightOfRadix()); break; + //these next 4 need to be scaled accordingly if it's a fixed type case Token::Mul: + scale = m_scalingFactor - other.m_scalingFactor; value = m_value * other.m_value; - break; + break; case Token::Div: if (other.m_value == 0) return TypePointer(); - value = m_value / other.m_value; + else + value = m_value / other.m_value; break; case Token::Mod: + { if (other.m_value == 0) return TypePointer(); - value = m_value % other.m_value; - break; + else if (fixedPointType) + { + value = m_value; + bigint integers = m_value.numerator() / m_value.denominator(); + value -= integers; + } + else + value = m_value.numerator() % other.m_value.numerator(); + break; case Token::Exp: - if (other.m_value < 0) + { + bigint newDenominator; + bigint newNumerator; + if (other.m_value.denominator() != 1) return TypePointer(); - else if (other.m_value > numeric_limits<unsigned int>::max()) + else if (abs(other.m_value) > numeric_limits<unsigned int>::max()) return TypePointer(); + else if (other.m_value < 0) //apply inverse + { + rational absoluteValue = abs(other.m_value); + newDenominator = boost::multiprecision::pow(m_value.numerator(), absoluteValue.numerator().convert_to<unsigned int>()); + newNumerator = boost::multiprecision::pow(m_value.denominator(), absoluteValue.numerator().convert_to<unsigned int>()); + value = rational(newNumerator, newDenominator); + } else - value = boost::multiprecision::pow(m_value, other.m_value.convert_to<unsigned int>()); + { + newNumerator = boost::multiprecision::pow(m_value.numerator(), other.m_value.numerator().convert_to<unsigned int>()); + newDenominator = boost::multiprecision::pow(m_value.denominator(), other.m_value.numerator().convert_to<unsigned int>()); + value = rational(newNumerator, newDenominator); + } break; + } default: return TypePointer(); } - return make_shared<IntegerConstantType>(value); + return make_shared<ConstantNumberType>(value); } } -bool IntegerConstantType::operator==(Type const& _other) const +bool ConstantNumberType::operator==(Type const& _other) const { if (_other.category() != category()) return false; - return m_value == dynamic_cast<IntegerConstantType const&>(_other).m_value; + ConstantNumberType const& other = dynamic_cast<ConstantNumberType const&>(_other); + return m_value == other.m_value; } -string IntegerConstantType::toString(bool) const +string ConstantNumberType::toString(bool) const { - return "int_const " + m_value.str(); + if (m_value.denominator() == 1) + return "int_const " + m_value.numerator().str(); + + return "rational_const " + m_value.numerator().str() + '/' + m_value.denominator().str(); } -u256 IntegerConstantType::literalValue(Literal const*) const +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), "Integer constant too large."); - solAssert(m_value >= -(bigint(1) << 255), "Integer constant too small."); + solAssert(m_value <= u256(-1), "Number constant too large."); + solAssert(m_value >= -(bigint(1) << 255), "Number constant too small."); if (m_value >= 0) - value = u256(m_value); + value = u256(m_value.numerator()); else - value = s2u(s256(m_value)); + value = s2u(s256(m_value.numerator())); return value; } -TypePointer IntegerConstantType::mobileType() const +TypePointer ConstantNumberType::mobileType() const { - auto intType = integerType(); - solAssert(!!intType, "mobileType called with invalid integer constant " + toString(false)); - return intType; + if (m_value.denominator() == 1) + { + auto intType = integerType(); + solAssert(!!intType, "mobileType called with invalid integer constant " + toString(false)); + return intType; + } + auto fixType = fixedPointType(); + solAssert(!!fixType, "mobileType called with invalid fixed constant " + toString(false)); + return fixType; } -shared_ptr<IntegerType const> IntegerConstantType::integerType() const +shared_ptr<IntegerType const> ConstantNumberType::integerType() const { - bigint value = m_value; + bigint value = m_value.numerator() / m_value.denominator(); bool negative = (value < 0); if (negative) // convert to positive number of same bit requirements - value = ((-value) - 1) << 1; + value = ((0 - value) - 1) << 1; if (value > u256(-1)) return shared_ptr<IntegerType const>(); else @@ -556,6 +862,32 @@ shared_ptr<IntegerType const> IntegerConstantType::integerType() const ); } +shared_ptr<FixedPointType const> 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)) + return shared_ptr<FixedPointType const>(); + 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; + return make_shared<FixedPointType>( + max(bytesRequired(integerBits), 1u) * 8, max(bytesRequired(fractionalBits), 1u) * 8, + negative ? FixedPointType::Modifier::Signed : FixedPointType::Modifier::Unsigned + ); + } +} + + + StringLiteralType::StringLiteralType(Literal const& _literal): m_value(_literal.value()) { diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index d42bb5dd..e0beabf8 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -26,6 +26,7 @@ #include <string> #include <map> #include <boost/noncopyable.hpp> +#include <boost/rational.hpp> #include <libdevcore/Common.h> #include <libdevcore/CommonIO.h> #include <libsolidity/interface/Exceptions.h> @@ -43,6 +44,7 @@ class FunctionType; // forward using TypePointer = std::shared_ptr<Type const>; using FunctionTypePointer = std::shared_ptr<FunctionType const>; using TypePointers = std::vector<TypePointer>; +using rational = boost::rational<bigint>; enum class DataLocation { Storage, CallData, Memory }; @@ -133,7 +135,7 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this<Type public: enum class Category { - Integer, IntegerConstant, StringLiteral, Bool, Real, Array, + Integer, NumberConstant, StringLiteral, Bool, FixedPoint, Array, FixedBytes, Contract, Struct, Function, Enum, Tuple, Mapping, TypeType, Modifier, Magic, Module }; @@ -202,7 +204,7 @@ public: virtual bool isValueType() const { return false; } virtual unsigned sizeOnStack() const { return 1; } /// @returns the mobile (in contrast to static) type corresponding to the given type. - /// This returns the corresponding integer type for IntegerConstantTypes and the pointer type + /// This returns the corresponding integer type for ConstantTypes and the pointer type /// for storage reference types. virtual TypePointer mobileType() const { return shared_from_this(); } /// @returns true if this is a non-value type and the data of this type is stored at the @@ -309,20 +311,64 @@ private: }; /** - * Integer constants either literals or computed. Example expressions: 2, 2+10, ~10. + * A fixed point type number (signed, unsigned). + */ +class FixedPointType: public Type +{ +public: + enum class Modifier + { + Unsigned, Signed + }; + virtual Category category() const override { return Category::FixedPoint; } + + explicit FixedPointType(int _integerBits, int _fractionalBits, Modifier _modifier = Modifier::Unsigned); + + virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; + virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; + virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; + + virtual bool operator==(Type const& _other) const override; + + virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : (m_integerBits + m_fractionalBits) / 8; } + virtual unsigned storageBytes() const override { return (m_integerBits + m_fractionalBits) / 8; } + virtual bool isValueType() const override { return true; } + + virtual std::string toString(bool _short) const override; + + virtual TypePointer encodingType() const override { return shared_from_this(); } + virtual TypePointer interfaceType(bool) const override { return shared_from_this(); } + + int numBits() const { return m_integerBits + m_fractionalBits; } + int integerBits() const { return m_integerBits; } + int fractionalBits() const { return m_fractionalBits; } + bool isSigned() const { return m_modifier == Modifier::Signed; } + +private: + int m_integerBits; + int m_fractionalBits; + Modifier m_modifier; +}; + +/** + * Integer and fixed point constants either literals or computed. + * Example expressions: 2, 3.14, 2+10.2, ~10. * There is one distinct type per value. */ -class IntegerConstantType: public Type +class ConstantNumberType: public Type { public: - virtual Category category() const override { return Category::IntegerConstant; } + + virtual Category category() const override { return Category::NumberConstant; } /// @returns true if the literal is a valid integer. static bool isValidLiteral(Literal const& _literal); - explicit IntegerConstantType(Literal const& _literal); - explicit IntegerConstantType(bigint _value): m_value(_value) {} - + explicit ConstantNumberType(Literal const& _literal); + explicit ConstantNumberType(rational _value): + m_value(_value) + {} virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; @@ -339,9 +385,12 @@ public: /// @returns the smallest integer type that can hold the value or an empty pointer if not possible. std::shared_ptr<IntegerType const> integerType() const; - + /// @returns the smallest fixed type that can hold the value or an empty pointer + std::shared_ptr<FixedPointType const> fixedPointType() const; + bigint denominator() const { return m_value.denominator(); } + private: - bigint m_value; + rational m_value; }; /** |