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) if (!length->annotation().type)
ConstantEvaluator e(*length); ConstantEvaluator e(*length);
auto const* lengthType = dynamic_cast<RationalNumberType const*>(length->annotation().type.get()); auto const* lengthType = dynamic_cast<RationalNumberType const*>(length->annotation().type.get());
if (!lengthType) if (!lengthType || lengthType->denominator() != 1)
fatalTypeError(length->location(), "Invalid array length."); fatalTypeError(length->location(), "Invalid array length, expected integer literal.");
else if (lengthType->denominator() != 1)
fatalTypeError(length->location(), "Invalid input for array length, expected integer.");
else else
_typeName.annotation().type = make_shared<ArrayType>(DataLocation::Storage, baseType, lengthType->literalValue(nullptr)); _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(), ""); solAssert(!var.typeName(), "");
if ( if (
valueComponentType->category() == Type::Category::RationalNumber && 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.annotation().type = valueComponentType->mobileType();
var.accept(*this); var.accept(*this);
} }
@ -800,8 +801,11 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
void TypeChecker::endVisit(ExpressionStatement const& _statement) void TypeChecker::endVisit(ExpressionStatement const& _statement)
{ {
if (type(_statement.expression())->category() == Type::Category::RationalNumber) if (type(_statement.expression())->category() == Type::Category::RationalNumber)
if (!dynamic_pointer_cast<RationalNumberType const>(type(_statement.expression()))->integerType()) if (
typeError(_statement.expression().location(), "Invalid integer constant."); !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) bool TypeChecker::visit(Conditional const& _conditional)
@ -1107,8 +1111,8 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
if (functionType->takesArbitraryParameters()) if (functionType->takesArbitraryParameters())
{ {
if (auto t = dynamic_cast<RationalNumberType const*>(argType.get())) if (auto t = dynamic_cast<RationalNumberType const*>(argType.get()))
if (!t->integerType()) if (!t->integerType() && !t->fixedPointType())
typeError(arguments[i]->location(), "Integer constant too large."); typeError(arguments[i]->location(), "Rational number too large.");
} }
else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i])) else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
typeError( typeError(
@ -1343,8 +1347,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
expectType(*index, IntegerType(256)); expectType(*index, IntegerType(256));
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get())) if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
{ {
if (numberType->denominator() != 1) solAssert(!numberType->denominator() != 1 ,"Invalid type for array access.");
typeError(_access.location(), "Invalid type for array access.");
if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr)) if (!actualType.isDynamicallySized() && actualType.length() <= numberType->literalValue(nullptr))
typeError(_access.location(), "Out of bounds array access."); 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())); resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
else else
{ {
index->accept(*this); expectType(*index, IntegerType(256));
if (auto length = dynamic_cast<RationalNumberType const*>(type(*index).get())) if (auto length = dynamic_cast<RationalNumberType const*>(type(*index).get()))
resultType = make_shared<TypeType>(make_shared<ArrayType>( resultType = make_shared<TypeType>(make_shared<ArrayType>(
DataLocation::Memory, DataLocation::Memory,

View File

@ -181,10 +181,13 @@ TypePointer Type::forLiteral(Literal const& _literal)
case Token::FalseLiteral: case Token::FalseLiteral:
return make_shared<BoolType>(); return make_shared<BoolType>();
case Token::Number: 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 else
return TypePointer(); return TypePointer();
}
case Token::StringLiteral: case Token::StringLiteral:
return make_shared<StringLiteralType>(_literal); return make_shared<StringLiteralType>(_literal);
default: default:
@ -272,7 +275,7 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
else if (_convertTo.category() == Category::FixedPoint) else if (_convertTo.category() == Category::FixedPoint)
{ {
FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo); FixedPointType const& convertTo = dynamic_cast<FixedPointType const&>(_convertTo);
if (convertTo.integerBits() < m_bits) if (convertTo.integerBits() < m_bits || isAddress())
return false; return false;
else if (isSigned()) else if (isSigned())
return convertTo.isSigned(); return convertTo.isSigned();
@ -440,7 +443,8 @@ string FixedPointType::toString(bool) const
TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) 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()
&& _other->category() != Category::Integer && _other->category() != Category::Integer
) )
@ -453,22 +457,29 @@ TypePointer FixedPointType::binaryOperatorResult(Token::Value _operator, TypePoi
// All fixed types can be compared // All fixed types can be compared
if (Token::isCompareOp(_operator)) if (Token::isCompareOp(_operator))
return commonType; return commonType;
if (Token::isBooleanOp(_operator)) if (Token::isBitOp(_operator) || Token::isBooleanOp(_operator))
return TypePointer(); return TypePointer();
return commonType; return commonType;
} }
bool RationalNumberType::isValidLiteral(Literal const& _literal) tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal)
{ {
rational x;
try try
{ {
rational numerator; rational numerator;
rational denominator(1); rational denominator(1);
auto radixPoint = find(_literal.value().begin(), _literal.value().end(), '.'); auto radixPoint = find(_literal.value().begin(), _literal.value().end(), '.');
if (radixPoint != _literal.value().end()) if (radixPoint != _literal.value().end())
{ {
//problem here. If the first digit is a 0 in the string, it won't if (
//turn it into a integer...Using find if not to count the leading 0s. !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( auto leadingZeroes = find_if_not(
radixPoint + 1, radixPoint + 1,
_literal.value().end(), _literal.value().end(),
@ -476,81 +487,55 @@ bool RationalNumberType::isValidLiteral(Literal const& _literal)
); );
auto fractionalBegin = leadingZeroes != _literal.value().end() ? auto fractionalBegin = leadingZeroes != _literal.value().end() ?
leadingZeroes : radixPoint + 1; leadingZeroes : radixPoint + 1;
denominator = bigint(string(fractionalBegin, _literal.value().end())); denominator = bigint(string(fractionalBegin, _literal.value().end()));
denominator /= boost::multiprecision::pow( denominator /= boost::multiprecision::pow(
bigint(10), bigint(10),
distance(radixPoint + 1, _literal.value().end()) distance(radixPoint + 1, _literal.value().end())
); );
numerator = bigint(string(_literal.value().begin(), radixPoint)); numerator = bigint(string(_literal.value().begin(), radixPoint));
rational x = numerator + denominator; x = numerator + denominator;
} }
else 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 (...) catch (...)
{ {
return false; return make_tuple(false, rational(0));
}
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(true, x);
} }
bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const 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); auto targetType = dynamic_cast<IntegerType const*>(&_convertTo);
if (m_value == 0) if (m_value == 0)
return true; return true;
if (m_value.denominator() != 1)
return false;
int forSignBit = (targetType->isSigned() ? 1 : 0); int forSignBit = (targetType->isSigned() ? 1 : 0);
if (m_value > 0) if (m_value > 0)
{ {
if (m_value <= (u256(-1) >> (256 - targetType->numBits() + forSignBit))) if (integerPart() <= (u256(-1) >> (256 - targetType->numBits() + forSignBit)))
return true; 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 true;
return false; return false;
} }
else if (_convertTo.category() == Category::FixedPoint) else if (_convertTo.category() == Category::FixedPoint)
{ {
cout << "hit here?" << endl;
if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo)) if (fixedPointType() && fixedPointType()->isImplicitlyConvertibleTo(_convertTo))
return true; return true;
return false; return false;
@ -583,7 +569,7 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const
if (m_value.denominator() == 1) if (m_value.denominator() == 1)
return fixedBytes.numBytes() * 8 >= integerType()->numBits(); return fixedBytes.numBytes() * 8 >= integerType()->numBits();
else else
return fixedBytes.numBytes() * 8 >= fixedPointType()->numBits(); return false;
} }
return false; return false;
} }
@ -692,7 +678,7 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
break; break;
case Token::Mul: case Token::Mul:
value = m_value * other.m_value; value = m_value * other.m_value;
break; break;
case Token::Div: case Token::Div:
if (other.m_value == 0) if (other.m_value == 0)
return TypePointer(); return TypePointer();
@ -758,9 +744,7 @@ string RationalNumberType::toString(bool) const
u256 RationalNumberType::literalValue(Literal const*) const u256 RationalNumberType::literalValue(Literal const*) const
{ {
u256 value; u256 value;
unsigned uselessBits = 0; bigint shiftedValue = integerPart();
bigint shiftedValue;
tie(shiftedValue, uselessBits) = findFractionNumberAndBits();
// we ignore the literal and hope that the type was correctly determined // we ignore the literal and hope that the type was correctly determined
solAssert(shiftedValue <= u256(-1), "Integer constant too large."); solAssert(shiftedValue <= u256(-1), "Integer constant too large.");
solAssert(shiftedValue >= -(bigint(1) << 255), "Number constant too small."); solAssert(shiftedValue >= -(bigint(1) << 255), "Number constant too small.");
@ -768,8 +752,7 @@ u256 RationalNumberType::literalValue(Literal const*) const
if (m_value >= 0) if (m_value >= 0)
value = u256(shiftedValue); value = u256(shiftedValue);
else else
value = s2u(s256(0 - shiftedValue)); value = s2u(s256(shiftedValue));
return value; return value;
} }
@ -789,7 +772,7 @@ TypePointer RationalNumberType::mobileType() const
//TODO: combine integerType() and fixedPointType() into one function //TODO: combine integerType() and fixedPointType() into one function
shared_ptr<IntegerType const> RationalNumberType::integerType() const shared_ptr<IntegerType const> RationalNumberType::integerType() const
{ {
bigint value = wholeNumbers(); bigint value = integerPart();
bool negative = (value < 0); bool negative = (value < 0);
if (negative) // convert to positive number of same bit requirements if (negative) // convert to positive number of same bit requirements
value = ((0 - value) - 1) << 1; value = ((0 - value) - 1) << 1;
@ -806,26 +789,34 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
{ {
bool negative = (m_value < 0); bool negative = (m_value < 0);
unsigned fractionalBits = 0; unsigned fractionalBits = 0;
unsigned integerBits = bytesRequired(wholeNumbers()) * 8; unsigned integerBits = 0;
rational value = m_value; rational value = m_value;
bigint l = bigint(1) << 256; bigint transitionValue = bigint(1) << 256;
rational maxValue = rational(l); rational maxValue = rational(transitionValue);
if (!negative) 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; value *= 0x100;
fractionalBits += 8; fractionalBits += 8;
} }
if (value > maxValue) if (value > maxValue)
{
cout << "value > max value " << endl;
return shared_ptr<FixedPointType const>(); return shared_ptr<FixedPointType const>();
}
bigint v = value.denominator() / value.numerator(); bigint v = value.denominator() / value.numerator();
if (negative) if (negative)
v = -v; v = -v;
@ -834,12 +825,7 @@ shared_ptr<FixedPointType const> RationalNumberType::fixedPointType() const
//if (negative) // convert to positive number of same bit requirements //if (negative) // convert to positive number of same bit requirements
// value = ((0 - value) - 1) << 1; // value = ((0 - value) - 1) << 1;
if (value > u256(-1)) if (value > u256(-1))
{
cout << "Too large of a number" << endl;
return shared_ptr<FixedPointType const>(); return shared_ptr<FixedPointType const>();
}
cout << "integer bits: " << integerBits << ", fractionalBits: " << fractionalBits << endl;
//solAssert(integerBits >= fractionalBits, "Invalid bit requirement calculation."); //solAssert(integerBits >= fractionalBits, "Invalid bit requirement calculation.");
//@todo special handling for integerBits == 0 && fractionalBits == 0? //@todo special handling for integerBits == 0 && fractionalBits == 0?
return make_shared<FixedPointType>( 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): StringLiteralType::StringLiteralType(Literal const& _literal):
m_value(_literal.value()) m_value(_literal.value())
{ {

View File

@ -363,9 +363,8 @@ public:
virtual Category category() const override { return Category::RationalNumber; } virtual Category category() const override { return Category::RationalNumber; }
/// @returns true if the literal is a valid integer. /// @returns true if the literal is a valid integer.
static bool isValidLiteral(Literal const& _literal); static std::tuple<bool, rational> isValidLiteral(Literal const& _literal);
explicit RationalNumberType(Literal const& _literal);
explicit RationalNumberType(rational _value): explicit RationalNumberType(rational _value):
m_value(_value) m_value(_value)
{} {}
@ -389,9 +388,8 @@ public:
/// If the integer part does not fit, returns an empty pointer. /// If the integer part does not fit, returns an empty pointer.
std::shared_ptr<FixedPointType const> fixedPointType() const; 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 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: private:
rational m_value; 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()); int n = parseSize(positionX + 1, _literal.end());
if ( if (
0 <= m && m <= 256 && 0 <= m && m <= 256 &&
0 <= n && n <= 256 && 8 <= n && n <= 256 &&
m + n > 0 && m + n > 0 &&
m + n <= 256 && m + n <= 256 &&
m % 8 == 0 && m % 8 == 0 &&

View File

@ -3454,11 +3454,10 @@ BOOST_AUTO_TEST_CASE(inline_array_fixed_rationals)
BOOST_CHECK(success(text)); 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"( char const* text = R"(
contract A { contract A {
ufixed8x0 someInt = 4;
ufixed0x8 half = 0.5; ufixed0x8 half = 0.5;
} }
)"; )";
@ -3471,7 +3470,7 @@ BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types)
contract test { contract test {
function f() { function f() {
ufixed0x256 a = 0.12345678; ufixed0x256 a = 0.12345678;
ufixed24x0 b = 12345678.0; ufixed24x8 b = 12345678.5;
ufixed0x256 c = 0.00000009; 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) BOOST_AUTO_TEST_CASE(fixed_to_bytes_implicit_conversion)