diff options
-rw-r--r-- | CompilerUtils.cpp | 7 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 26 | ||||
-rw-r--r-- | Types.cpp | 84 | ||||
-rw-r--r-- | Types.h | 27 |
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: @@ -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)}}); @@ -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; } |