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. 23
      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 CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
{ {
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries); unsigned _encodedSize = _type.getCalldataEncodedSize();
bool leftAligned = _type.getCategory() == Type::Category::String; unsigned numBytes = _padToWordBoundaries ? getPaddedSize(_encodedSize) : _encodedSize;
bool leftAligned = _type.getCategory() == Type::Category::FixedBytes;
if (numBytes == 0) if (numBytes == 0)
m_context << eth::Instruction::POP << u256(0); m_context << eth::Instruction::POP << u256(0);
else else
@ -202,7 +203,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWordBoundaries) const
{ {
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries); unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
bool leftAligned = _type.getCategory() == Type::Category::String; bool leftAligned = _type.getCategory() == Type::Category::FixedBytes;
if (numBytes == 0) if (numBytes == 0)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
else else

26
libsolidity/ExpressionCompiler.cpp

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

82
libsolidity/Types.cpp

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

23
libsolidity/Types.h

@ -77,7 +77,7 @@ public:
enum class Category enum class Category
{ {
Integer, IntegerConstant, Bool, Real, Array, Integer, IntegerConstant, Bool, Real, Array,
String, Contract, Struct, Function, Enum, FixedBytes, Contract, Struct, Function, Enum,
Mapping, Void, TypeType, Modifier, Magic Mapping, Void, TypeType, Modifier, Magic
}; };
@ -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 class IntegerType: public Type
{ {
public: public:
enum class Modifier enum class Modifier
{ {
Unsigned, Signed, Bytes, Address Unsigned, Signed, Address
}; };
virtual Category getCategory() const override { return Category::Integer; } virtual Category getCategory() const override { return Category::Integer; }
@ -186,7 +186,6 @@ public:
virtual std::string toString() const override; virtual std::string toString() const override;
int getNumBits() const { return m_bits; } 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 isAddress() const { return m_modifier == Modifier::Address; }
bool isSigned() const { return m_modifier == Modifier::Signed; } 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: 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. /// 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 isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool operator==(Type const& _other) 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 unsigned getCalldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
virtual bool isValueType() const override { return true; } 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; virtual u256 literalValue(Literal const* _literal) const override;
int getNumBytes() const { return m_bytes; } int getNumBytes() const { return m_bytes; }

Loading…
Cancel
Save