Browse Source

Replacing StaticStringType with FixedBytesType

cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
72f2397ebe
  1. 7
      libsolidity/CompilerUtils.cpp
  2. 26
      libsolidity/ExpressionCompiler.cpp
  3. 82
      libsolidity/Types.cpp
  4. 27
      libsolidity/Types.h

7
libsolidity/CompilerUtils.cpp

@ -177,8 +177,9 @@ void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundari
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
bool leftAligned = _type.getCategory() == Type::Category::String;
unsigned _encodedSize = _type.getCalldataEncodedSize();
unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
bool leftAligned = _type.getCategory() == Type::Category::FixedBytes;
if (numBytes == 0)
m_context << eth::Instruction::POP << u256(0);
else
@ -202,7 +203,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
{
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
bool leftAligned = _type.getCategory() == Type::Category::String;
bool leftAligned = _type.getCategory() == Type::Category::FixedBytes;
if (numBytes == 0)
m_context << eth::Instruction::POP;
else

26
libsolidity/ExpressionCompiler.cpp

@ -123,23 +123,23 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
Type::Category stackTypeCategory = _typeOnStack.getCategory();
Type::Category targetTypeCategory = _targetType.getCategory();
if (stackTypeCategory == Type::Category::String)
if (stackTypeCategory == Type::Category::FixedBytes)
{
StaticStringType const& typeOnStack = dynamic_cast<StaticStringType const&>(_typeOnStack);
FixedBytesType const& typeOnStack = dynamic_cast<FixedBytesType const&>(_typeOnStack);
if (targetTypeCategory == Type::Category::Integer)
{
// conversion from string to hash. no need to clean the high bit
// conversion from string to bytes. no need to clean the high bit
// only to shift right because of opposite alignment
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
solAssert(targetIntegerType.isBytes(), "Only conversion between String and Bytes is allowed.");
solAssert(targetIntegerType.isAddress(), "Only conversion between Address and FixedBytes is allowed.");
solAssert(targetIntegerType.getNumBits() == typeOnStack.getNumBytes() * 8, "The size should be the same.");
m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
}
else
{
// clear lower-order bytes for conversion to shorter strings - we always clean
solAssert(targetTypeCategory == Type::Category::String, "Invalid type conversion requested.");
StaticStringType const& targetType = dynamic_cast<StaticStringType const&>(_targetType);
// clear lower-order bytes for conversion to shorter bytes - we always clean
solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
if (targetType.getNumBytes() < typeOnStack.getNumBytes())
{
if (targetType.getNumBytes() == 0)
@ -158,14 +158,14 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con
stackTypeCategory == Type::Category::Contract ||
stackTypeCategory == Type::Category::IntegerConstant)
{
if (targetTypeCategory == Type::Category::String && stackTypeCategory == Type::Category::Integer)
if (targetTypeCategory == Type::Category::FixedBytes && stackTypeCategory == Type::Category::Integer)
{
// conversion from hash to string. no need to clean the high bit
// conversion from bytes to string. no need to clean the high bit
// only to shift left because of opposite alignment
StaticStringType const& targetStringType = dynamic_cast<StaticStringType const&>(_targetType);
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
IntegerType const& typeOnStack = dynamic_cast<IntegerType const&>(_typeOnStack);
solAssert(typeOnStack.isBytes(), "Only conversion between String and Bytes is allowed.");
solAssert(typeOnStack.getNumBits() == targetStringType.getNumBytes() * 8, "The size should be the same.");
solAssert(typeOnStack.isAddress(), "Only conversion between Address and Bytes is allowed.");
solAssert(typeOnStack.getNumBits() == targetBytesType.getNumBytes() * 8, "The size should be the same.");
m_context << (u256(1) << (256 - typeOnStack.getNumBits())) << eth::Instruction::MUL;
}
else if (targetTypeCategory == Type::Category::Enum)
@ -870,7 +870,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
{
case Type::Category::IntegerConstant:
case Type::Category::Bool:
case Type::Category::String:
case Type::Category::FixedBytes:
m_context << _literal.getType()->literalValue(&_literal);
break;
default:

82
libsolidity/Types.cpp

@ -46,10 +46,18 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken)
if (bytes == 0)
bytes = 32;
int modifier = offset / 33;
return make_shared<IntegerType>(bytes * 8,
modifier == 0 ? IntegerType::Modifier::Signed :
modifier == 1 ? IntegerType::Modifier::Unsigned :
IntegerType::Modifier::Bytes);
switch(modifier)
{
case 0:
return make_shared<IntegerType>(bytes * 8, IntegerType::Modifier::Signed);
case 1:
return make_shared<IntegerType>(bytes * 8, IntegerType::Modifier::Unsigned);
case 2:
return make_shared<FixedBytesType>(bytes);
default:
solAssert(false, "Unexpected modifier value. Should never happen");
return TypePointer();
}
}
else if (_typeToken == Token::Address)
return make_shared<IntegerType>(0, IntegerType::Modifier::Address);
@ -121,7 +129,7 @@ TypePointer Type::forLiteral(Literal const& _literal)
return make_shared<IntegerConstantType>(_literal);
case Token::StringLiteral:
//@todo put larger strings into dynamic strings
return StaticStringType::smallestTypeForLiteral(_literal.getValue());
return FixedBytesType::smallestTypeForLiteral(_literal.getValue());
default:
return shared_ptr<Type>();
}
@ -157,8 +165,6 @@ bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false;
if (isAddress())
return convertTo.isAddress();
else if (isBytes())
return convertTo.isBytes();
else if (isSigned())
return convertTo.isSigned();
else
@ -183,10 +189,7 @@ TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
// "~" is ok for all other types
else if (_operator == Token::BitNot)
return shared_from_this();
// nothing else for bytes
else if (isBytes())
return TypePointer();
// for non-hash integers, we allow +, -, ++ and --
// for non-address integers, we allow +, -, ++ and --
else if (_operator == Token::Add || _operator == Token::Sub ||
_operator == Token::Inc || _operator == Token::Dec ||
_operator == Token::After)
@ -207,7 +210,7 @@ string IntegerType::toString() const
{
if (isAddress())
return "address";
string prefix = isBytes() ? "bytes" : (isSigned() ? "int" : "uint");
string prefix = isSigned() ? "int" : "uint";
return prefix + dev::toString(m_bits);
}
@ -224,13 +227,7 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe
if (Token::isCompareOp(_operator))
return commonType;
// Nothing else can be done with addresses, but bytes can receive bit operators
if (commonType->isAddress())
return TypePointer();
else if (commonType->isBytes() && !Token::isBitOp(_operator))
return TypePointer();
else
return commonType;
}
const MemberList IntegerType::AddressMemberList =
@ -426,50 +423,75 @@ shared_ptr<IntegerType const> IntegerConstantType::getIntegerType() const
: IntegerType::Modifier::Unsigned);
}
shared_ptr<StaticStringType> StaticStringType::smallestTypeForLiteral(string const& _literal)
shared_ptr<FixedBytesType> FixedBytesType::smallestTypeForLiteral(string const& _literal)
{
if (_literal.length() <= 32)
return make_shared<StaticStringType>(_literal.length());
return shared_ptr<StaticStringType>();
return make_shared<FixedBytesType>(_literal.length());
return shared_ptr<FixedBytesType>();
}
StaticStringType::StaticStringType(int _bytes): m_bytes(_bytes)
FixedBytesType::FixedBytesType(int _bytes): m_bytes(_bytes)
{
solAssert(m_bytes >= 0 && m_bytes <= 32,
"Invalid byte number for static string type: " + dev::toString(m_bytes));
}
bool StaticStringType::isImplicitlyConvertibleTo(Type const& _convertTo) const
bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.getCategory() != getCategory())
return false;
StaticStringType const& convertTo = dynamic_cast<StaticStringType const&>(_convertTo);
FixedBytesType const& convertTo = dynamic_cast<FixedBytesType const&>(_convertTo);
return convertTo.m_bytes >= m_bytes;
}
bool StaticStringType::isExplicitlyConvertibleTo(Type const& _convertTo) const
bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (_convertTo.getCategory() == getCategory())
return true;
if (_convertTo.getCategory() == Category::Integer)
{
IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
if (convertTo.isBytes() && (m_bytes * 8 == convertTo.getNumBits()))
if (m_bytes * 8 == convertTo.getNumBits())
return true;
}
return false;
}
bool StaticStringType::operator==(Type const& _other) const
TypePointer FixedBytesType::unaryOperatorResult(Token::Value _operator) const
{
// "delete" and "~" is okay for FixedBytesType
if (_operator == Token::Delete)
return make_shared<VoidType>();
else if (_operator == Token::BitNot)
return shared_from_this();
return TypePointer();
}
TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
{
auto commonType = dynamic_pointer_cast<FixedBytesType const>(Type::commonType(shared_from_this(), _other));
if (!commonType)
return TypePointer();
// FixedBytes can be compared and have bitwise operators applied to them
if (Token::isCompareOp(_operator) || Token::isBitOp(_operator))
return commonType;
return TypePointer();
}
bool FixedBytesType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())
return false;
StaticStringType const& other = dynamic_cast<StaticStringType const&>(_other);
FixedBytesType const& other = dynamic_cast<FixedBytesType const&>(_other);
return other.m_bytes == m_bytes;
}
u256 StaticStringType::literalValue(const Literal* _literal) const
u256 FixedBytesType::literalValue(const Literal* _literal) const
{
solAssert(_literal, "");
u256 value = 0;
@ -1117,7 +1139,7 @@ MagicType::MagicType(MagicType::Kind _kind):
case Kind::Block:
m_members = MemberList({{"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
{"timestamp", make_shared<IntegerType>(256)},
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"hash"}, FunctionType::Location::BlockHash)},
{"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes"}, FunctionType::Location::BlockHash)},
{"difficulty", make_shared<IntegerType>(256)},
{"number", make_shared<IntegerType>(256)},
{"gaslimit", make_shared<IntegerType>(256)}});

27
libsolidity/Types.h

@ -77,12 +77,12 @@ public:
enum class Category
{
Integer, IntegerConstant, Bool, Real, Array,
String, Contract, Struct, Function, Enum,
FixedBytes, Contract, Struct, Function, Enum,
Mapping, Void, TypeType, Modifier, Magic
};
///@{
///@name Factory functions
/// @{
/// @name Factory functions
/// Factory functions that convert an AST @ref TypeName to a Type.
static TypePointer fromElementaryTypeName(Token::Value _typeToken);
static TypePointer fromElementaryTypeName(std::string const& _name);
@ -158,14 +158,14 @@ protected:
};
/**
* Any kind of integer type including hash and address.
* Any kind of integer type including address.
*/
class IntegerType: public Type
{
public:
enum class Modifier
{
Unsigned, Signed, Bytes, Address
Unsigned, Signed, Address
};
virtual Category getCategory() const override { return Category::Integer; }
@ -186,7 +186,6 @@ public:
virtual std::string toString() const override;
int getNumBits() const { return m_bits; }
bool isBytes() const { return m_modifier == Modifier::Bytes || m_modifier == Modifier::Address; }
bool isAddress() const { return m_modifier == Modifier::Address; }
bool isSigned() const { return m_modifier == Modifier::Signed; }
@ -232,27 +231,29 @@ private:
};
/**
* String type with fixed length, up to 32 bytes.
* Bytes type with fixed length of up to 32 bytes
*/
class StaticStringType: public Type
class FixedBytesType: public Type
{
public:
virtual Category getCategory() const override { return Category::String; }
virtual Category getCategory() const override { return Category::FixedBytes; }
/// @returns the smallest string type for the given literal or an empty pointer
/// @returns the smallest bytes type for the given literal or an empty pointer
/// if no type fits.
static std::shared_ptr<StaticStringType> smallestTypeForLiteral(std::string const& _literal);
static std::shared_ptr<FixedBytesType> smallestTypeForLiteral(std::string const& _literal);
explicit StaticStringType(int _bytes);
explicit FixedBytesType(int _bytes);
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool operator==(Type const& _other) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
virtual bool isValueType() const override { return true; }
virtual std::string toString() const override { return "string" + dev::toString(m_bytes); }
virtual std::string toString() const override { return "bytes" + dev::toString(m_bytes); }
virtual u256 literalValue(Literal const* _literal) const override;
int getNumBytes() const { return m_bytes; }

Loading…
Cancel
Save