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:
VoR0220 2016-04-12 12:36:34 -05:00
parent 5bddb2d6ff
commit bfc238c8d1
6 changed files with 105 additions and 146 deletions

View File

@ -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));
}

View File

@ -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,

View File

@ -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())
{

View File

@ -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;

View File

@ -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 &&

View File

@ -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)