mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
updated algorithm for bit finding...now to figure out literal value
tiny fixups changed location of the check got rid of extra space and fixed a couple of things added binary results bits change back literal value
This commit is contained in:
parent
5bddb2d6ff
commit
bfc238c8d1
@ -104,10 +104,8 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
|
||||
if (!length->annotation().type)
|
||||
ConstantEvaluator e(*length);
|
||||
auto const* lengthType = dynamic_cast<RationalNumberType const*>(length->annotation().type.get());
|
||||
if (!lengthType)
|
||||
fatalTypeError(length->location(), "Invalid array length.");
|
||||
else if (lengthType->denominator() != 1)
|
||||
fatalTypeError(length->location(), "Invalid input for array length, expected integer.");
|
||||
if (!lengthType || lengthType->denominator() != 1)
|
||||
fatalTypeError(length->location(), "Invalid array length, expected integer literal.");
|
||||
else
|
||||
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr));
|
||||
}
|
||||
|
@ -774,9 +774,10 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
solAssert(!var.typeName(), "");
|
||||
if (
|
||||
valueComponentType->category() == Type::Category::RationalNumber &&
|
||||
!dynamic_pointer_cast<RationalNumberType const>(valueComponentType)->integerType()
|
||||
!dynamic_pointer_cast<RationalNumberType const>(valueComponentType)->integerType() &&
|
||||
!dynamic_pointer_cast<RationalNumberType const>(valueComponentType)->fixedPointType()
|
||||
)
|
||||
fatalTypeError(_statement.initialValue()->location(), "Invalid integer constant " + valueComponentType->toString() + ".");
|
||||
fatalTypeError(_statement.initialValue()->location(), "Invalid rational " + valueComponentType->toString() + ".");
|
||||
var.annotation().type = valueComponentType->mobileType();
|
||||
var.accept(*this);
|
||||
}
|
||||
@ -800,8 +801,11 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
void TypeChecker::endVisit(ExpressionStatement const& _statement)
|
||||
{
|
||||
if (type(_statement.expression())->category() == Type::Category::RationalNumber)
|
||||
if (!dynamic_pointer_cast<RationalNumberType const>(type(_statement.expression()))->integerType())
|
||||
typeError(_statement.expression().location(), "Invalid integer constant.");
|
||||
if (
|
||||
!dynamic_pointer_cast<RationalNumberType const>(type(_statement.expression()))->integerType() &&
|
||||
!dynamic_pointer_cast<RationalNumberType const>(type(_statement.expression()))->fixedPointType()
|
||||
)
|
||||
typeError(_statement.expression().location(), "Invalid rational number.");
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(Conditional const& _conditional)
|
||||
@ -1107,8 +1111,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
if (functionType->takesArbitraryParameters())
|
||||
{
|
||||
if (auto t = dynamic_cast<RationalNumberType const*>(argType.get()))
|
||||
if (!t->integerType())
|
||||
typeError(arguments[i]->location(), "Integer constant too large.");
|
||||
if (!t->integerType() && !t->fixedPointType())
|
||||
typeError(arguments[i]->location(), "Rational number too large.");
|
||||
}
|
||||
else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
|
||||
typeError(
|
||||
@ -1343,8 +1347,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
expectType(*index, IntegerType(256));
|
||||
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
||||
{
|
||||
if (numberType->denominator() != 1)
|
||||
typeError(_access.location(), "Invalid type for array access.");
|
||||
solAssert(!numberType->denominator() != 1 ,"Invalid type for array access.");
|
||||
if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr))
|
||||
typeError(_access.location(), "Out of bounds array access.");
|
||||
}
|
||||
@ -1371,7 +1374,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
|
||||
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
|
||||
else
|
||||
{
|
||||
index->accept(*this);
|
||||
expectType(*index, IntegerType(256));
|
||||
if (auto length = dynamic_cast<RationalNumberType const*>(type(*index).get()))
|
||||
resultType = make_shared<TypeType>(make_shared<ArrayType>(
|
||||
DataLocation::Memory,
|
||||
|
@ -181,10 +181,13 @@ TypePointer Type::forLiteral(Literal const& _literal)
|
||||
case Token::FalseLiteral:
|
||||
return make_shared<BoolType>();
|
||||
case Token::Number:
|
||||
if (RationalNumberType::isValidLiteral(_literal))
|
||||
return make_shared<RationalNumberType>(_literal);
|
||||
{
|
||||
tuple<bool, rational> validLiteral = RationalNumberType::isValidLiteral(_literal);
|
||||
if (get<0>(validLiteral) == true)
|
||||
return make_shared<RationalNumberType>(get<1>(validLiteral));
|
||||
else
|
||||
return TypePointer();
|
||||
}
|
||||
case Token::StringLiteral:
|
||||
return make_shared<StringLiteralType>(_literal);
|
||||
default:
|
||||
@ -272,7 +275,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
else if (_convertTo.category() == Category::FixedPoint)
|
||||
{
|
||||
FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo);
|
||||
if (convertTo.integerBits() < m_bits)
|
||||
if (convertTo.integerBits() < m_bits || isAddress())
|
||||
return false;
|
||||
else if (isSigned())
|
||||
return convertTo.isSigned();
|
||||
@ -440,7 +443,8 @@ string FixedPointType::toString(bool) const
|
||||
|
||||
TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
|
||||
{
|
||||
if (_other->category() != Category::RationalNumber
|
||||
if (
|
||||
_other->category() != Category::RationalNumber
|
||||
&& _other->category() != category()
|
||||
&& _other->category() != Category::Integer
|
||||
)
|
||||
@ -453,22 +457,29 @@ TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePoi
|
||||
// All fixed types can be compared
|
||||
if (Token::isCompareOp(_operator))
|
||||
return commonType;
|
||||
if (Token::isBooleanOp(_operator))
|
||||
if (Token::isBitOp(_operator) || Token::isBooleanOp(_operator))
|
||||
return TypePointer();
|
||||
return commonType;
|
||||
}
|
||||
|
||||
bool RationalNumberType::isValidLiteral(Literal const& _literal)
|
||||
tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal)
|
||||
{
|
||||
rational x;
|
||||
try
|
||||
{
|
||||
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.
|
||||
if (
|
||||
!all_of(radixPoint + 1, _literal.value().end(), ::isdigit) ||
|
||||
!all_of(_literal.value().begin(), radixPoint, ::isdigit)
|
||||
)
|
||||
throw;
|
||||
//Only decimal notation allowed here, leading zeros would switch to octal.
|
||||
auto leadingZeroes = find_if_not(
|
||||
radixPoint + 1,
|
||||
_literal.value().end(),
|
||||
@ -476,81 +487,55 @@ bool RationalNumberType::isValidLiteral(Literal const& _literal)
|
||||
);
|
||||
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;
|
||||
x = numerator + denominator;
|
||||
}
|
||||
else
|
||||
rational x = bigint(_literal.value());
|
||||
x = bigint(_literal.value());
|
||||
switch (_literal.subDenomination())
|
||||
{
|
||||
case Literal::SubDenomination::None:
|
||||
case Literal::SubDenomination::Wei:
|
||||
case Literal::SubDenomination::Second:
|
||||
break;
|
||||
case Literal::SubDenomination::Szabo:
|
||||
x *= bigint("1000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Finney:
|
||||
x *= bigint("1000000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Ether:
|
||||
x *= bigint("1000000000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Minute:
|
||||
x *= bigint("60");
|
||||
break;
|
||||
case Literal::SubDenomination::Hour:
|
||||
x *= bigint("3600");
|
||||
break;
|
||||
case Literal::SubDenomination::Day:
|
||||
x *= bigint("86400");
|
||||
break;
|
||||
case Literal::SubDenomination::Week:
|
||||
x *= bigint("604800");
|
||||
break;
|
||||
case Literal::SubDenomination::Year:
|
||||
x *= bigint("31536000");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RationalNumberType::RationalNumberType(Literal const& _literal)
|
||||
{
|
||||
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:
|
||||
break;
|
||||
case Literal::SubDenomination::Szabo:
|
||||
m_value *= bigint("1000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Finney:
|
||||
m_value *= bigint("1000000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Ether:
|
||||
m_value *= bigint("1000000000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Minute:
|
||||
m_value *= bigint("60");
|
||||
break;
|
||||
case Literal::SubDenomination::Hour:
|
||||
m_value *= bigint("3600");
|
||||
break;
|
||||
case Literal::SubDenomination::Day:
|
||||
m_value *= bigint("86400");
|
||||
break;
|
||||
case Literal::SubDenomination::Week:
|
||||
m_value *= bigint("604800");
|
||||
break;
|
||||
case Literal::SubDenomination::Year:
|
||||
m_value *= bigint("31536000");
|
||||
break;
|
||||
return make_tuple(false, rational(0));
|
||||
}
|
||||
return make_tuple(true, x);
|
||||
}
|
||||
|
||||
bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
@ -560,19 +545,20 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
auto targetType = dynamic_cast<IntegerType const*>(&_convertTo);
|
||||
if (m_value == 0)
|
||||
return true;
|
||||
if (m_value.denominator() != 1)
|
||||
return false;
|
||||
int forSignBit = (targetType->isSigned() ? 1 : 0);
|
||||
if (m_value > 0)
|
||||
{
|
||||
if (m_value <= (u256(-1) >> (256 - targetType->numBits() + forSignBit)))
|
||||
if (integerPart() <= (u256(-1) >> (256 - targetType->numBits() + forSignBit)))
|
||||
return true;
|
||||
}
|
||||
else if (targetType->isSigned() && -m_value <= (u256(1) << (targetType->numBits() - forSignBit)))
|
||||
else if (targetType->isSigned() && -integerPart() <= (u256(1) << (targetType->numBits() - forSignBit)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
else if (_convertTo.category() == Category::FixedPoint)
|
||||
{
|
||||
cout << "hit here?" << endl;
|
||||
if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo))
|
||||
return true;
|
||||
return false;
|
||||
@ -583,7 +569,7 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
if (m_value.denominator() == 1)
|
||||
return fixedBytes.numBytes() * 8 >= integerType()->numBits();
|
||||
else
|
||||
return fixedBytes.numBytes() * 8 >= fixedPointType()->numBits();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -692,7 +678,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();
|
||||
@ -758,9 +744,7 @@ string RationalNumberType::toString(bool) const
|
||||
u256 RationalNumberType::literalValue(Literal const*) const
|
||||
{
|
||||
u256 value;
|
||||
unsigned uselessBits = 0;
|
||||
bigint shiftedValue;
|
||||
tie(shiftedValue, uselessBits) = findFractionNumberAndBits();
|
||||
bigint shiftedValue = integerPart();
|
||||
// we ignore the literal and hope that the type was correctly determined
|
||||
solAssert(shiftedValue <= u256(-1), "Integer constant too large.");
|
||||
solAssert(shiftedValue >= -(bigint(1) << 255), "Number constant too small.");
|
||||
@ -768,8 +752,7 @@ u256 RationalNumberType::literalValue(Literal const*) const
|
||||
if (m_value >= 0)
|
||||
value = u256(shiftedValue);
|
||||
else
|
||||
value = s2u(s256(0 - shiftedValue));
|
||||
|
||||
value = s2u(s256(shiftedValue));
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -789,7 +772,7 @@ TypePointer RationalNumberType::mobileType() const
|
||||
//TODO: combine integerType() and fixedPointType() into one function
|
||||
shared_ptr<IntegerType const> RationalNumberType::integerType() const
|
||||
{
|
||||
bigint value = wholeNumbers();
|
||||
bigint value = integerPart();
|
||||
bool negative = (value < 0);
|
||||
if (negative) // convert to positive number of same bit requirements
|
||||
value = ((0 - value) - 1) << 1;
|
||||
@ -806,26 +789,34 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
|
||||
{
|
||||
bool negative = (m_value < 0);
|
||||
unsigned fractionalBits = 0;
|
||||
unsigned integerBits = bytesRequired(wholeNumbers()) * 8;
|
||||
unsigned integerBits = 0;
|
||||
rational value = m_value;
|
||||
bigint l = bigint(1) << 256;
|
||||
rational maxValue = rational(l);
|
||||
bigint transitionValue = bigint(1) << 256;
|
||||
rational maxValue = rational(transitionValue);
|
||||
|
||||
if (!negative)
|
||||
maxValue -= 1;
|
||||
else
|
||||
value = -value;
|
||||
cout << "Max value: " << maxValue << endl;
|
||||
while (value * 0x100 <= maxValue && value.denominator() != 1 && fractionalBits < 256 - integerBits)
|
||||
{
|
||||
maxValue -= 1;
|
||||
integerBits = bytesRequired(integerPart()) * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = abs(value);
|
||||
if (integerPart() > 0)
|
||||
transitionValue = ((0 - integerPart()) - 1) << 1;
|
||||
else
|
||||
transitionValue = 0;
|
||||
integerBits = bytesRequired(transitionValue) * 8;
|
||||
}
|
||||
|
||||
while (value * 0x100 <= maxValue && value.denominator() != 1 && fractionalBits < 256 - integerBits)
|
||||
{
|
||||
value *= 0x100;
|
||||
fractionalBits += 8;
|
||||
}
|
||||
|
||||
if (value > maxValue)
|
||||
{
|
||||
cout << "value > max value " << endl;
|
||||
return shared_ptr<FixedPointType const>();
|
||||
}
|
||||
bigint v = value.denominator() / value.numerator();
|
||||
if (negative)
|
||||
v = -v;
|
||||
@ -834,12 +825,7 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
|
||||
//if (negative) // convert to positive number of same bit requirements
|
||||
// value = ((0 - value) - 1) << 1;
|
||||
if (value > u256(-1))
|
||||
{
|
||||
cout << "Too large of a number" << endl;
|
||||
return shared_ptr<FixedPointType const>();
|
||||
}
|
||||
|
||||
cout << "integer bits: " << integerBits << ", fractionalBits: " << fractionalBits << endl;
|
||||
//solAssert(integerBits >= fractionalBits, "Invalid bit requirement calculation.");
|
||||
//@todo special handling for integerBits == 0 && fractionalBits == 0?
|
||||
return make_shared<FixedPointType>(
|
||||
@ -848,31 +834,6 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
|
||||
);
|
||||
}
|
||||
|
||||
//todo: change name of function
|
||||
tuple<bigint, unsigned> RationalNumberType::findFractionNumberAndBits(unsigned const restrictedBits) const
|
||||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
StringLiteralType::StringLiteralType(Literal const& _literal):
|
||||
m_value(_literal.value())
|
||||
{
|
||||
|
@ -363,9 +363,8 @@ public:
|
||||
virtual Category category() const override { return Category::RationalNumber; }
|
||||
|
||||
/// @returns true if the literal is a valid integer.
|
||||
static bool isValidLiteral(Literal const& _literal);
|
||||
|
||||
explicit RationalNumberType(Literal const& _literal);
|
||||
static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
|
||||
|
||||
explicit RationalNumberType(rational _value):
|
||||
m_value(_value)
|
||||
{}
|
||||
@ -389,9 +388,8 @@ public:
|
||||
/// If the integer part does not fit, returns an empty pointer.
|
||||
std::shared_ptr<FixedPointType const> fixedPointType() const;
|
||||
|
||||
std::tuple<bigint, unsigned> findFractionNumberAndBits(unsigned const restrictedBits = 0) const;
|
||||
bigint denominator() const { return m_value.denominator(); }
|
||||
bigint wholeNumbers() const { return m_value.numerator() / m_value.denominator(); }
|
||||
bigint integerPart() const { return m_value.numerator() / m_value.denominator(); }
|
||||
|
||||
private:
|
||||
rational m_value;
|
||||
|
@ -158,7 +158,7 @@ tuple<Token::Value, unsigned int, unsigned int> Token::fromIdentifierOrKeyword(s
|
||||
int n = parseSize(positionX + 1, _literal.end());
|
||||
if (
|
||||
0 <= m && m <= 256 &&
|
||||
0 <= n && n <= 256 &&
|
||||
8 <= n && n <= 256 &&
|
||||
m + n > 0 &&
|
||||
m + n <= 256 &&
|
||||
m % 8 == 0 &&
|
||||
|
@ -3454,11 +3454,10 @@ BOOST_AUTO_TEST_CASE(inline_array_fixed_rationals)
|
||||
BOOST_CHECK(success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(zero_and_eight_variants_fixed)
|
||||
BOOST_AUTO_TEST_CASE(zero_and_eight_variant_fixed)
|
||||
{
|
||||
char const* text = R"(
|
||||
contract A {
|
||||
ufixed8x0 someInt = 4;
|
||||
ufixed0x8 half = 0.5;
|
||||
}
|
||||
)";
|
||||
@ -3471,7 +3470,7 @@ BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types)
|
||||
contract test {
|
||||
function f() {
|
||||
ufixed0x256 a = 0.12345678;
|
||||
ufixed24x0 b = 12345678.0;
|
||||
ufixed24x8 b = 12345678.5;
|
||||
ufixed0x256 c = 0.00000009;
|
||||
}
|
||||
}
|
||||
@ -3532,7 +3531,7 @@ BOOST_AUTO_TEST_CASE(rational_to_bytes_implicit_conversion)
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
BOOST_CHECK(!success(text));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(fixed_to_bytes_implicit_conversion)
|
||||
|
Loading…
Reference in New Issue
Block a user