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
This commit is contained in:
RJ Catalano
2016-05-09 11:41:02 -05:00
committed by VoR0220
parent 9e36bdda8a
commit 9a075458ad
13 changed files with 1019 additions and 144 deletions
+405 -73
View File
@@ -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_value > 0)
if (m_scalingFactor == 0) //if current type is integer
{
if (m_value <= (u256(-1) >> (256 - targetType->numBits() + forSignBit)))
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 (targetType->isSigned() && -m_value <= (u256(1) << (targetType->numBits() - forSignBit)))
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_scalingFactor == 0) //if the current type is an integer, focus on the integer bits
{
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 (_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;
case Token::Exp:
if (other.m_value < 0)
return TypePointer();
else if (other.m_value > numeric_limits<unsigned int>::max())
return TypePointer();
else if (fixedPointType)
{
value = m_value;
bigint integers = m_value.numerator() / m_value.denominator();
value -= integers;
}
else
value = boost::multiprecision::pow(m_value, other.m_value.convert_to<unsigned int>());
value = m_value.numerator() % other.m_value.numerator();
break;
case Token::Exp:
{
bigint newDenominator;
bigint newNumerator;
if (other.m_value.denominator() != 1)
return TypePointer();
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
{
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())
{
+60 -11
View File
@@ -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.
* There is one distinct type per value.
* A fixed point type number (signed, unsigned).
*/
class IntegerConstantType: public Type
class FixedPointType: public Type
{
public:
virtual Category category() const override { return Category::IntegerConstant; }
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 ConstantNumberType: public Type
{
public:
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;
};
/**