From b6bad63d44224f2a4cc4aa3f656703dff7c13db3 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 6 Jan 2015 18:55:31 +0100 Subject: [PATCH 1/4] Use shared_from_this instead of manually supplying a shared_ptr to this. --- AST.cpp | 6 ++--- Types.cpp | 8 +++---- Types.h | 69 +++++++++++++++---------------------------------------- 3 files changed, 26 insertions(+), 57 deletions(-) diff --git a/AST.cpp b/AST.cpp index 047711067..97af6a1a6 100644 --- a/AST.cpp +++ b/AST.cpp @@ -192,8 +192,8 @@ void Assignment::checkTypeRequirements() { // compound assignment m_rightHandSide->checkTypeRequirements(); - TypePointer resultType = Type::binaryOperatorResult(Token::AssignmentToBinaryOp(m_assigmentOperator), - m_type, m_rightHandSide->getType()); + TypePointer resultType = m_type->binaryOperatorResult(Token::AssignmentToBinaryOp(m_assigmentOperator), + m_rightHandSide->getType()); if (!resultType || *resultType != *m_type) BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); } @@ -236,7 +236,7 @@ void BinaryOperation::checkTypeRequirements() { m_left->checkTypeRequirements(); m_right->checkTypeRequirements(); - m_commonType = Type::binaryOperatorResult(m_operator, m_left->getType(), m_right->getType()); + m_commonType = m_left->getType()->binaryOperatorResult(m_operator, m_right->getType()); if (!m_commonType) BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) + " not compatible with types " + diff --git a/Types.cpp b/Types.cpp index 7a81b65f6..21c95f829 100644 --- a/Types.cpp +++ b/Types.cpp @@ -192,11 +192,11 @@ u256 IntegerType::literalValue(Literal const& _literal) const return u256(value); } -TypePointer IntegerType::binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const +TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { if (getCategory() != _other->getCategory()) return TypePointer(); - auto commonType = dynamic_pointer_cast(Type::commonType(_this, _other)); + auto commonType = dynamic_pointer_cast(Type::commonType(shared_from_this(), _other)); if (!commonType) return TypePointer(); @@ -288,12 +288,12 @@ u256 BoolType::literalValue(Literal const& _literal) const BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); } -TypePointer BoolType::binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const +TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { if (getCategory() != _other->getCategory()) return TypePointer(); if (Token::isCompareOp(_operator) || _operator == Token::AND || _operator == Token::OR) - return _this; + return _other; else return TypePointer(); } diff --git a/Types.h b/Types.h index a91a6c24e..880f20ace 100644 --- a/Types.h +++ b/Types.h @@ -70,7 +70,7 @@ private: /** * Abstract base class that forms the root of the type hierarchy. */ -class Type: private boost::noncopyable +class Type: private boost::noncopyable, public std::enable_shared_from_this { public: enum class Category @@ -92,12 +92,6 @@ public: static TypePointer forLiteral(Literal const& _literal); /// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise static TypePointer commonType(TypePointer const& _a, TypePointer const& _b); - /// @returns the resulting type of applying the given operator or an empty pointer if this is not possible. - /// The default implementation allows comparison operators if a common type exists - static TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _a, TypePointer const& _b) - { - return _a->binaryOperatorResultImpl(_operator, _a, _b); - } virtual Category getCategory() const = 0; virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; } @@ -106,6 +100,13 @@ public: return isImplicitlyConvertibleTo(_convertTo); } virtual bool acceptsUnaryOperator(Token::Value) const { return false; } + /// @returns the resulting type of applying the given binary operator or an empty pointer if + /// this is not possible. + /// The default implementation allows comparison operators if a common type exists + virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const + { + return Token::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer(); + } virtual bool operator==(Type const& _other) const { return getCategory() == _other.getCategory(); } virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); } @@ -138,11 +139,6 @@ public: } protected: - virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _a, TypePointer const& _b) const - { - return Token::isCompareOp(_operator) ? commonType(_a, _b) : TypePointer(); - } - /// Convenience object used when returning an empty member list. static const MemberList EmptyMemberList; }; @@ -168,6 +164,7 @@ public: virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool acceptsUnaryOperator(Token::Value _operator) const override; + virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; virtual bool operator==(Type const& _other) const override; @@ -184,9 +181,6 @@ public: bool isAddress() const { return m_modifier == Modifier::ADDRESS; } int isSigned() const { return m_modifier == Modifier::SIGNED; } -protected: - virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override; - private: int m_bits; Modifier m_modifier; @@ -235,15 +229,13 @@ public: { return _operator == Token::NOT || _operator == Token::DELETE; } + virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; virtual unsigned getCalldataEncodedSize() const { return 1; } virtual bool isValueType() const override { return true; } virtual std::string toString() const override { return "bool"; } virtual u256 literalValue(Literal const& _literal) const override; - -protected: - virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override; }; /** @@ -285,10 +277,7 @@ class StructType: public Type public: virtual Category getCategory() const override { return Category::STRUCT; } StructType(StructDefinition const& _struct): m_struct(_struct) {} - virtual bool acceptsUnaryOperator(Token::Value _operator) const override - { - return _operator == Token::DELETE; - } + virtual bool acceptsUnaryOperator(Token::Value _operator) const override { return _operator == Token::DELETE; } virtual bool operator==(Type const& _other) const override; virtual u256 getStorageSize() const override; @@ -378,20 +367,12 @@ public: virtual Category getCategory() const override { return Category::VOID; } VoidType() {} + virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } virtual std::string toString() const override { return "void"; } virtual bool canBeStored() const override { return false; } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable void type requested.")); } virtual bool canLiveOutsideStorage() const override { return false; } virtual unsigned getSizeOnStack() const override { return 0; } - -protected: - virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override - { - (void)_operator; - (void)_this; - (void)_other; - return TypePointer(); - } }; /** @@ -403,24 +384,15 @@ class TypeType: public Type public: virtual Category getCategory() const override { return Category::TYPE; } TypeType(TypePointer const& _actualType): m_actualType(_actualType) {} - TypePointer const& getActualType() const { return m_actualType; } + virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); } virtual bool operator==(Type const& _other) const override; virtual bool canBeStored() const override { return false; } virtual u256 getStorageSize() const override { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Storage size of non-storable type type requested.")); } virtual bool canLiveOutsideStorage() const override { return false; } virtual std::string toString() const override { return "type(" + m_actualType->toString() + ")"; } -protected: - virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override - { - (void)_operator; - (void)_this; - (void)_other; - return TypePointer(); - } - private: TypePointer m_actualType; }; @@ -437,6 +409,12 @@ public: virtual Category getCategory() const override { return Category::MAGIC; } MagicType(Kind _kind); + + virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override + { + return TypePointer(); + } + virtual bool operator==(Type const& _other) const; virtual bool canBeStored() const override { return false; } virtual bool canLiveOutsideStorage() const override { return true; } @@ -445,15 +423,6 @@ public: virtual std::string toString() const override; -protected: - virtual TypePointer binaryOperatorResultImpl(Token::Value _operator, TypePointer const& _this, TypePointer const& _other) const override - { - (void)_operator; - (void)_this; - (void)_other; - return TypePointer(); - } - private: Kind m_kind; From d35842d65e4f81aa22114a312cd84b5835bc2533 Mon Sep 17 00:00:00 2001 From: Christian Date: Tue, 6 Jan 2015 19:08:24 +0100 Subject: [PATCH 2/4] Possibility for unary operators to change type. --- AST.cpp | 4 ++-- Types.cpp | 28 ++++++++++++++++++---------- Types.h | 16 +++++++++++----- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/AST.cpp b/AST.cpp index 97af6a1a6..107482d03 100644 --- a/AST.cpp +++ b/AST.cpp @@ -227,8 +227,8 @@ void UnaryOperation::checkTypeRequirements() m_subExpression->checkTypeRequirements(); if (m_operator == Token::Value::INC || m_operator == Token::Value::DEC || m_operator == Token::Value::DELETE) m_subExpression->requireLValue(); - m_type = m_subExpression->getType(); - if (!m_type->acceptsUnaryOperator(m_operator)) + m_type = m_subExpression->getType()->unaryOperatorResult(m_operator); + if (!m_type) BOOST_THROW_EXCEPTION(createTypeError("Unary operator not compatible with type.")); } diff --git a/Types.cpp b/Types.cpp index 21c95f829..1e6936e61 100644 --- a/Types.cpp +++ b/Types.cpp @@ -156,18 +156,26 @@ bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::CONTRACT; } -bool IntegerType::acceptsUnaryOperator(Token::Value _operator) const +TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const { + // "delete" is ok for all integer types if (_operator == Token::DELETE) - return true; - if (isAddress()) - return false; - if (_operator == Token::BIT_NOT) - return true; - if (isHash()) - return false; - return _operator == Token::ADD || _operator == Token::SUB || - _operator == Token::INC || _operator == Token::DEC; + return shared_from_this(); + // no further unary operators for addresses + else if (isAddress()) + return TypePointer(); + // "~" is ok for all other types + else if (_operator == Token::BIT_NOT) + return shared_from_this(); + // nothing else for hashes + else if (isHash()) + return TypePointer(); + // for non-hash integers, we allow +, -, ++ and -- + else if (_operator == Token::ADD || _operator == Token::SUB || + _operator == Token::INC || _operator == Token::DEC) + return shared_from_this(); + else + return TypePointer(); } bool IntegerType::operator==(Type const& _other) const diff --git a/Types.h b/Types.h index 880f20ace..35987be08 100644 --- a/Types.h +++ b/Types.h @@ -99,7 +99,10 @@ public: { return isImplicitlyConvertibleTo(_convertTo); } - virtual bool acceptsUnaryOperator(Token::Value) const { return false; } + /// @returns the resulting type of applying the given unary operator or an empty pointer if + /// this is not possible. + /// The default implementation does not allow any unary operator. + virtual TypePointer unaryOperatorResult(Token::Value) const { return TypePointer(); } /// @returns the resulting type of applying the given binary operator or an empty pointer if /// this is not possible. /// The default implementation allows comparison operators if a common type exists @@ -163,7 +166,7 @@ public: virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - virtual bool acceptsUnaryOperator(Token::Value _operator) const override; + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; virtual bool operator==(Type const& _other) const override; @@ -225,9 +228,9 @@ public: BoolType() {} virtual Category getCategory() const { return Category::BOOL; } virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; - virtual bool acceptsUnaryOperator(Token::Value _operator) const override + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override { - return _operator == Token::NOT || _operator == Token::DELETE; + return (_operator == Token::NOT || _operator == Token::DELETE) ? shared_from_this() : TypePointer(); } virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; @@ -277,7 +280,10 @@ class StructType: public Type public: virtual Category getCategory() const override { return Category::STRUCT; } StructType(StructDefinition const& _struct): m_struct(_struct) {} - virtual bool acceptsUnaryOperator(Token::Value _operator) const override { return _operator == Token::DELETE; } + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override + { + return _operator == Token::DELETE ? shared_from_this() : TypePointer(); + } virtual bool operator==(Type const& _other) const override; virtual u256 getStorageSize() const override; From 400d68b81d97db506550dcd93e50dcd0aa1c37ac Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 19 Dec 2014 11:31:17 +0100 Subject: [PATCH 3/4] Arbitrary precision integer constants. --- AST.cpp | 20 ++++- ExpressionCompiler.cpp | 42 +++++++--- ExpressionCompiler.h | 2 +- Scanner.cpp | 7 +- Types.cpp | 172 ++++++++++++++++++++++++++++++++++------- Types.h | 47 ++++++++--- 6 files changed, 233 insertions(+), 57 deletions(-) diff --git a/AST.cpp b/AST.cpp index 107482d03..d14cbf5c6 100644 --- a/AST.cpp +++ b/AST.cpp @@ -173,7 +173,15 @@ void VariableDefinition::checkTypeRequirements() { // no type declared and no previous assignment, infer the type m_value->checkTypeRequirements(); - m_variable->setType(m_value->getType()); + TypePointer type = m_value->getType(); + if (type->getCategory() == Type::Category::INTEGER_CONSTANT) + { + auto intType = dynamic_pointer_cast(type)->getIntegerType(); + if (!intType) + BOOST_THROW_EXCEPTION(m_value->createTypeError("Invalid integer constant " + type->toString())); + type = intType; + } + m_variable->setType(type); } } } @@ -195,13 +203,19 @@ void Assignment::checkTypeRequirements() TypePointer resultType = m_type->binaryOperatorResult(Token::AssignmentToBinaryOp(m_assigmentOperator), m_rightHandSide->getType()); if (!resultType || *resultType != *m_type) - BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_assigmentOperator)) + + " not compatible with types " + + m_type->toString() + " and " + + m_rightHandSide->getType()->toString())); } } void ExpressionStatement::checkTypeRequirements() { m_expression->checkTypeRequirements(); + if (m_expression->getType()->getCategory() == Type::Category::INTEGER_CONSTANT) + if (!dynamic_pointer_cast(m_expression->getType())->getIntegerType()) + BOOST_THROW_EXCEPTION(m_expression->createTypeError("Invalid integer constant.")); } void Expression::expectType(Type const& _expectedType) @@ -387,7 +401,7 @@ void Literal::checkTypeRequirements() { m_type = Type::forLiteral(*this); if (!m_type) - BOOST_THROW_EXCEPTION(createTypeError("Literal value too large.")); + BOOST_THROW_EXCEPTION(createTypeError("Invalid literal value.")); } } diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index aa7406132..9ea4c28a3 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -71,12 +71,20 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) return false; } -void ExpressionCompiler::endVisit(UnaryOperation const& _unaryOperation) +bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation) { //@todo type checking and creating code for an operator should be in the same place: // the operator should know how to convert itself and to which types it applies, so // put this code together with "Type::acceptsBinary/UnaryOperator" into a class that // represents the operator + if (_unaryOperation.getType()->getCategory() == Type::Category::INTEGER_CONSTANT) + { + m_context << _unaryOperation.getType()->literalValue(nullptr); + return false; + } + + _unaryOperation.getSubExpression().accept(*this); + switch (_unaryOperation.getOperator()) { case Token::NOT: // ! @@ -128,6 +136,7 @@ void ExpressionCompiler::endVisit(UnaryOperation const& _unaryOperation) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid unary operator: " + string(Token::toString(_unaryOperation.getOperator())))); } + return false; } bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) @@ -139,17 +148,19 @@ bool ExpressionCompiler::visit(BinaryOperation const& _binaryOperation) if (op == Token::AND || op == Token::OR) // special case: short-circuiting appendAndOrOperatorCode(_binaryOperation); + else if (commonType.getCategory() == Type::Category::INTEGER_CONSTANT) + m_context << commonType.literalValue(nullptr); else { - bool cleanupNeeded = false; - if (commonType.getCategory() == Type::Category::INTEGER) - if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) - cleanupNeeded = true; + bool cleanupNeeded = commonType.getCategory() == Type::Category::INTEGER && + (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD); // for commutative operators, push the literal as late as possible to allow improved optimization - //@todo this has to be extended for literal expressions - bool swap = (m_optimize && Token::isCommutativeOp(op) && dynamic_cast(&rightExpression) - && !dynamic_cast(&leftExpression)); + auto isLiteral = [](Expression const& _e) + { + return dynamic_cast(&_e) || _e.getType()->getCategory() == Type::Category::INTEGER_CONSTANT; + }; + bool swap = m_optimize && Token::isCommutativeOp(op) && isLiteral(rightExpression) && !isLiteral(leftExpression); if (swap) { leftExpression.accept(*this); @@ -423,10 +434,10 @@ void ExpressionCompiler::endVisit(Literal const& _literal) { switch (_literal.getType()->getCategory()) { - case Type::Category::INTEGER: + case Type::Category::INTEGER_CONSTANT: case Type::Category::BOOL: case Type::Category::STRING: - m_context << _literal.getType()->literalValue(_literal); + m_context << _literal.getType()->literalValue(&_literal); break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now.")); @@ -562,9 +573,16 @@ void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type con if (_typeOnStack == _targetType && !_cleanupNeeded) return; - if (_typeOnStack.getCategory() == Type::Category::INTEGER) + Type::Category stackTypeCategory = _typeOnStack.getCategory(); + Type::Category targetTypeCategory = _targetType.getCategory(); + if (stackTypeCategory == Type::Category::INTEGER) + { + solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, ""); appendHighBitsCleanup(dynamic_cast(_typeOnStack)); - else if (_typeOnStack.getCategory() == Type::Category::STRING) + } + else if (stackTypeCategory == Type::Category::INTEGER_CONSTANT) + solAssert(targetTypeCategory == Type::Category::INTEGER || targetTypeCategory == Type::Category::CONTRACT, ""); + else if (stackTypeCategory == Type::Category::STRING) { // nothing to do, strings are high-order-bit-aligned //@todo clear lower-order bytes if we allow explicit conversion to shorter strings diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index c0ee4ab48..c021aaff4 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -57,7 +57,7 @@ private: m_optimize(_optimize), m_context(_compilerContext), m_currentLValue(m_context) {} virtual bool visit(Assignment const& _assignment) override; - virtual void endVisit(UnaryOperation const& _unaryOperation) override; + virtual bool visit(UnaryOperation const& _unaryOperation) override; virtual bool visit(BinaryOperation const& _binaryOperation) override; virtual bool visit(FunctionCall const& _functionCall) override; virtual bool visit(NewExpression const& _newExpression) override; diff --git a/Scanner.cpp b/Scanner.cpp index 6433b5262..6e3d04bc5 100644 --- a/Scanner.cpp +++ b/Scanner.cpp @@ -455,7 +455,7 @@ void Scanner::scanToken() token = Token::ADD; break; case '-': - // - -- -= Number + // - -- -= advance(); if (m_char == '-') { @@ -464,8 +464,6 @@ void Scanner::scanToken() } else if (m_char == '=') token = selectToken(Token::ASSIGN_SUB); - else if (m_char == '.' || isDecimalDigit(m_char)) - token = scanNumber('-'); else token = Token::SUB; break; @@ -650,8 +648,7 @@ Token::Value Scanner::scanNumber(char _charSeen) } else { - if (_charSeen == '-') - addLiteralChar('-'); + solAssert(_charSeen == 0, ""); // if the first character is '0' we must check for octals and hex if (m_char == '0') { diff --git a/Types.cpp b/Types.cpp index 1e6936e61..c29b98753 100644 --- a/Types.cpp +++ b/Types.cpp @@ -91,7 +91,7 @@ shared_ptr Type::forLiteral(Literal const& _literal) case Token::FALSE_LITERAL: return make_shared(); case Token::NUMBER: - return IntegerType::smallestTypeForLiteral(_literal.getValue()); + return IntegerConstantType::fromLiteral(_literal.getValue()); case Token::STRING_LITERAL: //@todo put larger strings into dynamic strings return StaticStringType::smallestTypeForLiteral(_literal.getValue()); @@ -112,19 +112,6 @@ TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b) const MemberList Type::EmptyMemberList = MemberList(); -shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) -{ - bigint value(_literal); - bool isSigned = value < 0 || (!_literal.empty() && _literal.front() == '-'); - if (isSigned) - // convert to positive number of same bit requirements - value = ((-value) - 1) << 1; - unsigned bytes = max(bytesRequired(value), 1u); - if (bytes > 32) - return shared_ptr(); - return make_shared(bytes * 8, isSigned ? Modifier::SIGNED : Modifier::UNSIGNED); -} - IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier): m_bits(_bits), m_modifier(_modifier) { @@ -194,15 +181,9 @@ string IntegerType::toString() const return prefix + dev::toString(m_bits); } -u256 IntegerType::literalValue(Literal const& _literal) const -{ - bigint value(_literal.getValue()); - return u256(value); -} - TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const { - if (getCategory() != _other->getCategory()) + if (_other->getCategory() != Category::INTEGER_CONSTANT && _other->getCategory() != getCategory()) return TypePointer(); auto commonType = dynamic_pointer_cast(Type::commonType(shared_from_this(), _other)); @@ -236,6 +217,141 @@ const MemberList IntegerType::AddressMemberList = make_shared(TypePointers({make_shared(256)}), TypePointers(), FunctionType::Location::SEND)}}); +shared_ptr IntegerConstantType::fromLiteral(string const& _literal) +{ + return make_shared(bigint(_literal)); +} + +bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) const +{ + TypePointer integerType = getIntegerType(); + return integerType && integerType->isImplicitlyConvertibleTo(_convertTo); +} + +bool IntegerConstantType::isExplicitlyConvertibleTo(Type const& _convertTo) const +{ + TypePointer integerType = getIntegerType(); + return integerType && integerType->isExplicitlyConvertibleTo(_convertTo); +} + +TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) const +{ + bigint value; + switch (_operator) + { + case Token::BIT_NOT: + value = ~m_value; + break; + case Token::ADD: + value = m_value; + break; + case Token::SUB: + value = -m_value; + break; + default: + return TypePointer(); + } + return make_shared(value); +} + +TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const +{ + if (_other->getCategory() == Category::INTEGER) + { + shared_ptr integerType = getIntegerType(); + if (!integerType) + return TypePointer(); + return integerType->binaryOperatorResult(_operator, _other); + } + else if (_other->getCategory() != getCategory()) + return TypePointer(); + + IntegerConstantType const& other = dynamic_cast(*_other); + if (Token::isCompareOp(_operator)) + { + shared_ptr thisIntegerType = getIntegerType(); + shared_ptr otherIntegerType = other.getIntegerType(); + if (!thisIntegerType || !otherIntegerType) + return TypePointer(); + return thisIntegerType->binaryOperatorResult(_operator, otherIntegerType); + } + else + { + bigint value; + switch (_operator) + { + case Token::BIT_OR: + value = m_value | other.m_value; + break; + case Token::BIT_XOR: + value = m_value ^ other.m_value; + break; + case Token::BIT_AND: + value = m_value & other.m_value; + break; + case Token::ADD: + value = m_value + other.m_value; + break; + case Token::SUB: + value = m_value - other.m_value; + break; + case Token::MUL: + value = m_value * other.m_value; + break; + case Token::DIV: + if (other.m_value == 0) + return TypePointer(); + value = m_value / other.m_value; + break; + case Token::MOD: + if (other.m_value == 0) + return TypePointer(); + value = m_value % other.m_value; + break; + default: + return TypePointer(); + } + return make_shared(value); + } +} + +bool IntegerConstantType::operator==(Type const& _other) const +{ + if (_other.getCategory() != getCategory()) + return false; + return m_value == dynamic_cast(_other).m_value; +} + +string IntegerConstantType::toString() const +{ + return "int_const " + m_value.str(); +} + +u256 IntegerConstantType::literalValue(Literal const*) const +{ + // we ignore the literal and hope that the type was correctly determined + solAssert(m_value <= u256(-1), "Integer constant too large."); + solAssert(m_value >= -(bigint(1) << 255), "Integer constant too small."); + if (m_value >= 0) + return u256(m_value); + else + return s2u(s256(m_value)); +} + +shared_ptr IntegerConstantType::getIntegerType() const +{ + bigint value = m_value; + bool negative = (value < 0); + if (negative) // convert to positive number of same bit requirements + value = ((-value) - 1) << 1; + if (value > u256(-1)) + return shared_ptr(); + else + return make_shared(max(bytesRequired(value), 1u) * 8, + negative ? IntegerType::Modifier::SIGNED + : IntegerType::Modifier::UNSIGNED); +} + shared_ptr StaticStringType::smallestTypeForLiteral(string const& _literal) { if (_literal.length() <= 32) @@ -265,12 +381,13 @@ bool StaticStringType::operator==(Type const& _other) const return other.m_bytes == m_bytes; } -u256 StaticStringType::literalValue(const Literal& _literal) const +u256 StaticStringType::literalValue(const Literal* _literal) const { + solAssert(_literal, ""); u256 value = 0; - for (char c: _literal.getValue()) + for (char c: _literal->getValue()) value = (value << 8) | byte(c); - return value << ((32 - _literal.getValue().length()) * 8); + return value << ((32 - _literal->getValue().length()) * 8); } bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const @@ -286,11 +403,12 @@ bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const return isImplicitlyConvertibleTo(_convertTo); } -u256 BoolType::literalValue(Literal const& _literal) const +u256 BoolType::literalValue(Literal const* _literal) const { - if (_literal.getToken() == Token::TRUE_LITERAL) + solAssert(_literal, ""); + if (_literal->getToken() == Token::TRUE_LITERAL) return u256(1); - else if (_literal.getToken() == Token::FALSE_LITERAL) + else if (_literal->getToken() == Token::FALSE_LITERAL) return u256(0); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal.")); diff --git a/Types.h b/Types.h index 35987be08..918a915cc 100644 --- a/Types.h +++ b/Types.h @@ -75,7 +75,7 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this smallestTypeForLiteral(std::string const& _literal); - explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED); virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; @@ -177,7 +173,6 @@ public: virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; } virtual std::string toString() const override; - virtual u256 literalValue(Literal const& _literal) const override; int getNumBits() const { return m_bits; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } @@ -190,6 +185,40 @@ private: static const MemberList AddressMemberList; }; +/** + * Integer constants either literals or computed. Example expressions: 2, 2+10, ~10. + * There is one distinct type per value. + */ +class IntegerConstantType: public Type +{ +public: + virtual Category getCategory() const override { return Category::INTEGER_CONSTANT; } + + static std::shared_ptr fromLiteral(std::string const& _literal); + + explicit IntegerConstantType(bigint _value): m_value(_value) {} + + virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override; + virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override; + virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; + virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override; + + virtual bool operator==(Type const& _other) const override; + + virtual bool canBeStored() const override { return false; } + virtual bool canLiveOutsideStorage() const override { return false; } + virtual unsigned getSizeOnStack() const override { return 1; } + + virtual std::string toString() const override; + virtual u256 literalValue(Literal const* _literal) const override; + + /// @returns the smallest integer type that can hold the value or an empty pointer if not possible. + std::shared_ptr getIntegerType() const; + +private: + bigint m_value; +}; + /** * String type with fixed length, up to 32 bytes. */ @@ -211,7 +240,7 @@ public: virtual bool isValueType() const override { return true; } virtual std::string toString() const override { return "string" + 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; } @@ -238,7 +267,7 @@ public: virtual bool isValueType() const override { return true; } virtual std::string toString() const override { return "bool"; } - virtual u256 literalValue(Literal const& _literal) const override; + virtual u256 literalValue(Literal const* _literal) const override; }; /** From 852267e60f7a1d2b19b0dbddb3c0cf173f989526 Mon Sep 17 00:00:00 2001 From: Christian Date: Wed, 7 Jan 2015 21:35:35 +0100 Subject: [PATCH 4/4] Remove const from make_shared to allow enable_shared_from_this to work on MacOS. --- AST.cpp | 10 ++++---- Types.cpp | 74 +++++++++++++++++++++++++++---------------------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/AST.cpp b/AST.cpp index d14cbf5c6..79ac314cd 100644 --- a/AST.cpp +++ b/AST.cpp @@ -314,7 +314,7 @@ void NewExpression::checkTypeRequirements() m_contract = dynamic_cast(m_contractName->getReferencedDeclaration()); if (!m_contract) BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract.")); - shared_ptr type = make_shared(*m_contract); + shared_ptr type = make_shared(*m_contract); m_type = type; TypePointers const& parameterTypes = type->getConstructorType()->getParameterTypes(); if (parameterTypes.size() != m_arguments.size()) @@ -365,7 +365,7 @@ void Identifier::checkTypeRequirements() if (structDef) { // note that we do not have a struct type here - m_type = make_shared(make_shared(*structDef)); + m_type = make_shared(make_shared(*structDef)); return; } FunctionDefinition const* functionDef = dynamic_cast(m_referencedDeclaration); @@ -374,13 +374,13 @@ void Identifier::checkTypeRequirements() // a function reference is not a TypeType, because calling a TypeType converts to the type. // Calling a function (e.g. function(12), otherContract.function(34)) does not do a type // conversion. - m_type = make_shared(*functionDef); + m_type = make_shared(*functionDef); return; } ContractDefinition const* contractDef = dynamic_cast(m_referencedDeclaration); if (contractDef) { - m_type = make_shared(make_shared(*contractDef)); + m_type = make_shared(make_shared(*contractDef)); return; } MagicVariableDeclaration const* magicVariable = dynamic_cast(m_referencedDeclaration); @@ -394,7 +394,7 @@ void Identifier::checkTypeRequirements() void ElementaryTypeNameExpression::checkTypeRequirements() { - m_type = make_shared(Type::fromElementaryTypeName(m_typeToken)); + m_type = make_shared(Type::fromElementaryTypeName(m_typeToken)); } void Literal::checkTypeRequirements() diff --git a/Types.cpp b/Types.cpp index c29b98753..dcfc704a4 100644 --- a/Types.cpp +++ b/Types.cpp @@ -44,17 +44,17 @@ shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) if (bytes == 0) bytes = 32; int modifier = offset / 33; - return make_shared(bytes * 8, + return make_shared(bytes * 8, modifier == 0 ? IntegerType::Modifier::SIGNED : modifier == 1 ? IntegerType::Modifier::UNSIGNED : IntegerType::Modifier::HASH); } else if (_typeToken == Token::ADDRESS) - return make_shared(0, IntegerType::Modifier::ADDRESS); + return make_shared(0, IntegerType::Modifier::ADDRESS); else if (_typeToken == Token::BOOL) - return make_shared(); + return make_shared(); else if (Token::STRING0 <= _typeToken && _typeToken <= Token::STRING32) - return make_shared(int(_typeToken) - int(Token::STRING0)); + return make_shared(int(_typeToken) - int(Token::STRING0)); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); @@ -64,11 +64,11 @@ shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& { Declaration const* declaration = _typeName.getReferencedDeclaration(); if (StructDefinition const* structDef = dynamic_cast(declaration)) - return make_shared(*structDef); + return make_shared(*structDef); else if (FunctionDefinition const* function = dynamic_cast(declaration)) - return make_shared(*function); + return make_shared(*function); else if (ContractDefinition const* contract = dynamic_cast(declaration)) - return make_shared(*contract); + return make_shared(*contract); return shared_ptr(); } @@ -80,7 +80,7 @@ shared_ptr Type::fromMapping(Mapping const& _typeName) shared_ptr valueType = _typeName.getValueType().toType(); if (!valueType) BOOST_THROW_EXCEPTION(_typeName.getValueType().createTypeError("Invalid type name")); - return make_shared(keyType, valueType); + return make_shared(keyType, valueType); } shared_ptr Type::forLiteral(Literal const& _literal) @@ -89,14 +89,14 @@ shared_ptr Type::forLiteral(Literal const& _literal) { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: - return make_shared(); + return make_shared(); case Token::NUMBER: return IntegerConstantType::fromLiteral(_literal.getValue()); case Token::STRING_LITERAL: //@todo put larger strings into dynamic strings return StaticStringType::smallestTypeForLiteral(_literal.getValue()); default: - return shared_ptr(); + return shared_ptr(); } } @@ -205,21 +205,21 @@ TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointe const MemberList IntegerType::AddressMemberList = MemberList({{"balance", - make_shared(256)}, + make_shared(256)}, {"callstring32", - make_shared(TypePointers({make_shared(32)}), - TypePointers(), FunctionType::Location::BARE)}, + make_shared(TypePointers({make_shared(32)}), + TypePointers(), FunctionType::Location::BARE)}, {"callstring32string32", - make_shared(TypePointers({make_shared(32), - make_shared(32)}), - TypePointers(), FunctionType::Location::BARE)}, + make_shared(TypePointers({make_shared(32), + make_shared(32)}), + TypePointers(), FunctionType::Location::BARE)}, {"send", - make_shared(TypePointers({make_shared(256)}), - TypePointers(), FunctionType::Location::SEND)}}); + make_shared(TypePointers({make_shared(256)}), + TypePointers(), FunctionType::Location::SEND)}}); shared_ptr IntegerConstantType::fromLiteral(string const& _literal) { - return make_shared(bigint(_literal)); + return make_shared(bigint(_literal)); } bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) const @@ -251,7 +251,7 @@ TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) con default: return TypePointer(); } - return make_shared(value); + return make_shared(value); } TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const @@ -311,7 +311,7 @@ TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, Ty default: return TypePointer(); } - return make_shared(value); + return make_shared(value); } } @@ -347,9 +347,9 @@ shared_ptr IntegerConstantType::getIntegerType() const if (value > u256(-1)) return shared_ptr(); else - return make_shared(max(bytesRequired(value), 1u) * 8, - negative ? IntegerType::Modifier::SIGNED - : IntegerType::Modifier::UNSIGNED); + return make_shared(max(bytesRequired(value), 1u) * 8, + negative ? IntegerType::Modifier::SIGNED + : IntegerType::Modifier::UNSIGNED); } shared_ptr StaticStringType::smallestTypeForLiteral(string const& _literal) @@ -473,9 +473,9 @@ shared_ptr const& ContractType::getConstructorType() const { FunctionDefinition const* constructor = m_contract.getConstructor(); if (constructor) - m_constructorType = make_shared(*constructor); + m_constructorType = make_shared(*constructor); else - m_constructorType = make_shared(TypePointers(), TypePointers()); + m_constructorType = make_shared(TypePointers(), TypePointers()); } return m_constructorType; } @@ -647,21 +647,21 @@ MagicType::MagicType(MagicType::Kind _kind): switch (m_kind) { case Kind::BLOCK: - m_members = MemberList({{"coinbase", make_shared(0, IntegerType::Modifier::ADDRESS)}, - {"timestamp", make_shared(256)}, - {"prevhash", make_shared(256, IntegerType::Modifier::HASH)}, - {"difficulty", make_shared(256)}, - {"number", make_shared(256)}, - {"gaslimit", make_shared(256)}}); + m_members = MemberList({{"coinbase", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"timestamp", make_shared(256)}, + {"prevhash", make_shared(256, IntegerType::Modifier::HASH)}, + {"difficulty", make_shared(256)}, + {"number", make_shared(256)}, + {"gaslimit", make_shared(256)}}); break; case Kind::MSG: - m_members = MemberList({{"sender", make_shared(0, IntegerType::Modifier::ADDRESS)}, - {"gas", make_shared(256)}, - {"value", make_shared(256)}}); + m_members = MemberList({{"sender", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"gas", make_shared(256)}, + {"value", make_shared(256)}}); break; case Kind::TX: - m_members = MemberList({{"origin", make_shared(0, IntegerType::Modifier::ADDRESS)}, - {"gasprice", make_shared(256)}}); + m_members = MemberList({{"origin", make_shared(0, IntegerType::Modifier::ADDRESS)}, + {"gasprice", make_shared(256)}}); break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));