aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CompilerUtils.cpp7
-rw-r--r--ExpressionCompiler.cpp26
-rw-r--r--Types.cpp84
-rw-r--r--Types.h27
4 files changed, 84 insertions, 60 deletions
diff --git a/CompilerUtils.cpp b/CompilerUtils.cpp
index 8a26b5d1..e11b6b4f 100644
--- a/CompilerUtils.cpp
+++ b/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
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index 91a59b2d..51e1fd0a 100644
--- a/ExpressionCompiler.cpp
+++ b/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:
diff --git a/Types.cpp b/Types.cpp
index daf7c03e..aadd884b 100644
--- a/Types.cpp
+++ b/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;
+ return TypePointer();
}
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)}});
diff --git a/Types.h b/Types.h
index 3d67720c..6517cf07 100644
--- a/Types.h
+++ b/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; }