diff --git a/CMakeLists.txt b/CMakeLists.txt index b4aa2352f..d8c517fef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,7 @@ include(EthDependenciesDeprecated) createBuildInfo() add_subdirectory(libdevcore) -add_subdirectory(libevmface) +add_subdirectory(libevmcore) add_subdirectory(liblll) add_subdirectory(libserpent) add_subdirectory(libsolidity) diff --git a/alethzero/CMakeLists.txt b/alethzero/CMakeLists.txt index 0da0acb4f..01dfb88dc 100644 --- a/alethzero/CMakeLists.txt +++ b/alethzero/CMakeLists.txt @@ -53,7 +53,7 @@ else () endif () qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) -target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmface devcore web3jsonrpc jsqrc) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore devcrypto secp256k1 gmp ${CRYPTOPP_LS} serpent lll solidity evmcore devcore web3jsonrpc jsqrc) if (APPLE) # First have qt5 install plugins and frameworks diff --git a/eth/main.cpp b/eth/main.cpp index 759dd40d0..408654018 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -32,7 +32,7 @@ #include #endif #include -#include +#include #include #include #include diff --git a/iethxi/MainWin.cpp b/iethxi/MainWin.cpp index 276ff7630..2d5b57094 100644 --- a/iethxi/MainWin.cpp +++ b/iethxi/MainWin.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "BuildInfo.h" diff --git a/libethereum/Executive.h b/libethereum/Executive.h index cdfe23966..930c2859b 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include "Transaction.h" diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c2bccad42..35e00f588 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include "BlockChain.h" diff --git a/libevm/CMakeLists.txt b/libevm/CMakeLists.txt index 0c31a9fc3..b4aa1eef2 100644 --- a/libevm/CMakeLists.txt +++ b/libevm/CMakeLists.txt @@ -17,7 +17,7 @@ include_directories(..) target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} devcrypto) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} secp256k1) target_link_libraries(${EXECUTABLE} gmp) diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 62132a462..666e7e9e8 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/libevm/VM.h b/libevm/VM.h index aa58bdbb1..d8f71dfc9 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include "FeeStructure.h" diff --git a/liblll/Assembly.cpp b/libevmcore/Assembly.cpp similarity index 100% rename from liblll/Assembly.cpp rename to libevmcore/Assembly.cpp diff --git a/liblll/Assembly.h b/libevmcore/Assembly.h similarity index 99% rename from liblll/Assembly.h rename to libevmcore/Assembly.h index e39f1899b..ef5294a54 100644 --- a/liblll/Assembly.h +++ b/libevmcore/Assembly.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "Exceptions.h" namespace dev diff --git a/libevmface/CMakeLists.txt b/libevmcore/CMakeLists.txt similarity index 95% rename from libevmface/CMakeLists.txt rename to libevmcore/CMakeLists.txt index f82d2b96b..738303271 100644 --- a/libevmface/CMakeLists.txt +++ b/libevmcore/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) -set(EXECUTABLE evmface) +set(EXECUTABLE evmcore) file(GLOB HEADERS "*.h") if(ETH_STATIC) diff --git a/libevmcore/Exceptions.h b/libevmcore/Exceptions.h new file mode 100644 index 000000000..57e1ac9c6 --- /dev/null +++ b/libevmcore/Exceptions.h @@ -0,0 +1,36 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file Exceptions.h + * @author Christian + * @date 2014 + */ + +#pragma once + +#include + +namespace dev +{ +namespace eth +{ + +struct AssemblyException: virtual Exception {}; +struct InvalidDeposit: virtual AssemblyException {}; +struct InvalidOpcode: virtual AssemblyException {}; + +} +} diff --git a/libevmface/Instruction.cpp b/libevmcore/Instruction.cpp similarity index 100% rename from libevmface/Instruction.cpp rename to libevmcore/Instruction.cpp diff --git a/libevmface/Instruction.h b/libevmcore/Instruction.h similarity index 98% rename from libevmface/Instruction.h rename to libevmcore/Instruction.h index fadb5ab14..0892c50dc 100644 --- a/libevmface/Instruction.h +++ b/libevmcore/Instruction.h @@ -22,18 +22,13 @@ #pragma once #include -#include - -namespace boost { namespace spirit { class utree; } } -namespace sp = boost::spirit; +#include namespace dev { namespace eth { -struct InvalidOpcode: virtual Exception {}; - /// Virtual machine bytecode instruction. enum class Instruction: uint8_t { diff --git a/liblll/All.h b/liblll/All.h index ec6989e66..7c4192f62 100644 --- a/liblll/All.h +++ b/liblll/All.h @@ -1,6 +1,5 @@ #pragma once -#include "Assembly.h" #include "CodeFragment.h" #include "Compiler.h" #include "CompilerState.h" diff --git a/liblll/CMakeLists.txt b/liblll/CMakeLists.txt index cb50cc36e..8b1581785 100644 --- a/liblll/CMakeLists.txt +++ b/liblll/CMakeLists.txt @@ -15,7 +15,7 @@ endif() include_directories(..) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 47df8f3b9..2c200caa5 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "CompilerState.h" #include "Parser.h" using namespace std; diff --git a/liblll/CodeFragment.h b/liblll/CodeFragment.h index d6ca86bbe..b24b474da 100644 --- a/liblll/CodeFragment.h +++ b/liblll/CodeFragment.h @@ -22,8 +22,8 @@ #pragma once #include -#include -#include "Assembly.h" +#include +#include #include "Exceptions.h" namespace boost { namespace spirit { class utree; } } diff --git a/liblll/Exceptions.h b/liblll/Exceptions.h index c45215f1a..1e9671b36 100644 --- a/liblll/Exceptions.h +++ b/liblll/Exceptions.h @@ -32,16 +32,13 @@ namespace eth class CompilerException: public dev::Exception {}; class InvalidOperation: public CompilerException {}; class IntegerOutOfRange: public CompilerException {}; -class StringTooLong: public CompilerException {}; class EmptyList: public CompilerException {}; class DataNotExecutable: public CompilerException {}; class IncorrectParameterCount: public CompilerException {}; -class InvalidDeposit: public CompilerException {}; class InvalidName: public CompilerException {}; class InvalidMacroArgs: public CompilerException {}; class InvalidLiteral: public CompilerException {}; class BareSymbol: public CompilerException {}; -class ExpectedLiteral: public CompilerException {}; } } diff --git a/libpyserpent/CMakeLists.txt b/libpyserpent/CMakeLists.txt index 5108000f4..e6f32ec81 100644 --- a/libpyserpent/CMakeLists.txt +++ b/libpyserpent/CMakeLists.txt @@ -13,7 +13,7 @@ include_directories(..) target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ${PYTHON_LS}) diff --git a/libqethereum/QmlEthereum.cpp b/libqethereum/QmlEthereum.cpp index a7ed3df4d..b1b926f42 100644 --- a/libqethereum/QmlEthereum.cpp +++ b/libqethereum/QmlEthereum.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libserpent/CMakeLists.txt b/libserpent/CMakeLists.txt index 0090b5dc3..c2fe89cc0 100644 --- a/libserpent/CMakeLists.txt +++ b/libserpent/CMakeLists.txt @@ -16,7 +16,7 @@ endif() include_directories(..) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 44cf39291..565560adc 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -337,9 +337,11 @@ void ExpressionStatement::checkTypeRequirements() void Expression::expectType(Type const& _expectedType) { checkTypeRequirements(); - if (!getType()->isImplicitlyConvertibleTo(_expectedType)) - BOOST_THROW_EXCEPTION(createTypeError("Type not implicitly convertible to expected type.")); - //@todo provide more information to the exception + Type const& type = *getType(); + if (!type.isImplicitlyConvertibleTo(_expectedType)) + BOOST_THROW_EXCEPTION(createTypeError("Type " + type.toString() + + " not implicitly convertible to expected type " + + _expectedType.toString() + ".")); } void UnaryOperation::checkTypeRequirements() @@ -363,14 +365,18 @@ void BinaryOperation::checkTypeRequirements() else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation.")); + BOOST_THROW_EXCEPTION(createTypeError("No common type found in binary operation: " + + m_left->getType()->toString() + " vs. " + + m_right->getType()->toString())); if (Token::isCompareOp(m_operator)) m_type = make_shared(); else { m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(m_operator)) - BOOST_THROW_EXCEPTION(createTypeError("Operator not compatible with type.")); + BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_operator)) + + " not compatible with type " + + m_commonType->toString())); } } @@ -479,6 +485,8 @@ void ElementaryTypeNameExpression::checkTypeRequirements() void Literal::checkTypeRequirements() { m_type = Type::forLiteral(*this); + if (!m_type) + BOOST_THROW_EXCEPTION(createTypeError("Literal value too large.")); } } diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 793ce863f..ce9190ea4 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -565,12 +565,15 @@ public: Expression& getLeftExpression() const { return *m_left; } Expression& getRightExpression() const { return *m_right; } Token::Value getOperator() const { return m_operator; } + Type const& getCommonType() const { return *m_commonType; } private: ASTPointer m_left; Token::Value m_operator; ASTPointer m_right; + /// The common type that is used for the operation, not necessarily the result type (e.g. for + /// comparisons, this is always bool). std::shared_ptr m_commonType; }; diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt index f425bba48..f335dd754 100644 --- a/libsolidity/CMakeLists.txt +++ b/libsolidity/CMakeLists.txt @@ -16,8 +16,7 @@ file(GLOB HEADERS "*.h") include_directories(..) -# @todo we only depend on Assembly, not on all of lll -target_link_libraries(${EXECUTABLE} evmface devcore lll) +target_link_libraries(${EXECUTABLE} evmcore devcore) install( TARGETS ${EXECUTABLE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index d05552b9e..8afd52b27 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -271,7 +271,7 @@ bool Compiler::visit(Return& _return) { ExpressionCompiler::compileExpression(m_context, *expression); VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front(); - ExpressionCompiler::cleanHigherOrderBitsIfNeeded(*expression->getType(), *firstVariable.getType()); + ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType()); int stackPosition = m_context.getStackPositionOfVariable(firstVariable); m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; } @@ -284,8 +284,9 @@ bool Compiler::visit(VariableDefinition& _variableDefinition) if (Expression* expression = _variableDefinition.getExpression()) { ExpressionCompiler::compileExpression(m_context, *expression); - ExpressionCompiler::cleanHigherOrderBitsIfNeeded(*expression->getType(), - *_variableDefinition.getDeclaration().getType()); + ExpressionCompiler::appendTypeConversion(m_context, + *expression->getType(), + *_variableDefinition.getDeclaration().getType()); int stackPosition = m_context.getStackPositionOfVariable(_variableDefinition.getDeclaration()); m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP; } diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 46c4c72ab..088ef43bc 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -23,8 +23,8 @@ #pragma once #include -#include -#include +#include +#include #include namespace dev { diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index d23579b11..6efb8b20c 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -37,6 +37,13 @@ void ExpressionCompiler::compileExpression(CompilerContext& _context, Expression _expression.accept(compiler); } +void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, + Type const& _typeOnStack, Type const& _targetType) +{ + ExpressionCompiler compiler(_context); + compiler.appendTypeConversion(_typeOnStack, _targetType); +} + bool ExpressionCompiler::visit(Assignment& _assignment) { m_currentLValue = nullptr; @@ -44,7 +51,7 @@ bool ExpressionCompiler::visit(Assignment& _assignment) Expression& rightHandSide = _assignment.getRightHandSide(); rightHandSide.accept(*this); Type const& resultType = *_assignment.getType(); - cleanHigherOrderBitsIfNeeded(*rightHandSide.getType(), resultType); + appendTypeConversion(*rightHandSide.getType(), resultType); _assignment.getLeftHandSide().accept(*this); Token::Value op = _assignment.getAssignmentOperator(); @@ -113,7 +120,7 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) { Expression& leftExpression = _binaryOperation.getLeftExpression(); Expression& rightExpression = _binaryOperation.getRightExpression(); - Type const& resultType = *_binaryOperation.getType(); + Type const& commonType = _binaryOperation.getCommonType(); Token::Value const op = _binaryOperation.getOperator(); if (op == Token::AND || op == Token::OR) @@ -121,23 +128,21 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) // special case: short-circuiting appendAndOrOperatorCode(_binaryOperation); } - else if (Token::isCompareOp(op)) - { - leftExpression.accept(*this); - rightExpression.accept(*this); - - // the types to compare have to be the same, but the resulting type is always bool - if (asserts(*leftExpression.getType() == *rightExpression.getType())) - BOOST_THROW_EXCEPTION(InternalCompilerError()); - appendCompareOperatorCode(op, *leftExpression.getType()); - } else { + bool cleanupNeeded = false; + if (commonType.getCategory() == Type::Category::INTEGER) + if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) + cleanupNeeded = true; + leftExpression.accept(*this); - cleanHigherOrderBitsIfNeeded(*leftExpression.getType(), resultType); + appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded); rightExpression.accept(*this); - cleanHigherOrderBitsIfNeeded(*rightExpression.getType(), resultType); - appendOrdinaryBinaryOperatorCode(op, resultType); + appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); + if (Token::isCompareOp(op)) + appendCompareOperatorCode(op, commonType); + else + appendOrdinaryBinaryOperatorCode(op, commonType); } // do not visit the child nodes, we already did that explicitly @@ -153,7 +158,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) BOOST_THROW_EXCEPTION(InternalCompilerError()); Expression& firstArgument = *_functionCall.getArguments().front(); firstArgument.accept(*this); - cleanHigherOrderBitsIfNeeded(*firstArgument.getType(), *_functionCall.getType()); + appendTypeConversion(*firstArgument.getType(), *_functionCall.getType()); } else { @@ -170,7 +175,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) for (unsigned i = 0; i < arguments.size(); ++i) { arguments[i]->accept(*this); - cleanHigherOrderBitsIfNeeded(*arguments[i]->getType(), + appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType()); } @@ -233,28 +238,6 @@ void ExpressionCompiler::endVisit(Literal& _literal) } } -void ExpressionCompiler::cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType) -{ - // If the type of one of the operands is extended, we need to remove all - // higher-order bits that we might have ignored in previous operations. - // @todo: store in the AST whether the operand might have "dirty" higher - // order bits - - if (_typeOnStack == _targetType) - return; - if (_typeOnStack.getCategory() == Type::Category::INTEGER && - _targetType.getCategory() == Type::Category::INTEGER) - { - //@todo - } - else - { - // If we get here, there is either an implementation missing to clean higher oder bits - // for non-integer types that are explicitly convertible or we got here in error. - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); - } -} - void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation& _binaryOperation) { Token::Value const op = _binaryOperation.getOperator(); @@ -379,6 +362,32 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator) } } +void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) +{ + // If the type of one of the operands is extended, we need to remove all + // higher-order bits that we might have ignored in previous operations. + // @todo: store in the AST whether the operand might have "dirty" higher + // order bits + + if (_typeOnStack == _targetType && !_cleanupNeeded) + return; + if (_typeOnStack.getCategory() == Type::Category::INTEGER) + appendHighBitsCleanup(dynamic_cast(_typeOnStack)); + else if (_typeOnStack != _targetType) + // All other types should not be convertible to non-equal types. + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid type conversion requested.")); +} + +void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) +{ + if (_typeOnStack.getNumBits() == 256) + return; + else if (_typeOnStack.isSigned()) + m_context << u256(_typeOnStack.getNumBits() / 8 - 1) << eth::Instruction::SIGNEXTEND; + else + m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; +} + void ExpressionCompiler::storeInLValue(Expression const& _expression) { moveToLValue(_expression); diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index a930723cc..d67814be0 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -26,6 +26,8 @@ namespace dev { namespace solidity { class CompilerContext; // forward +class Type; // forward +class IntegerType; // forward /// Compiler for expressions, i.e. converts an AST tree whose root is an Expression into a stream /// of EVM instructions. It needs a compiler context that is the same for the whole compilation @@ -37,7 +39,7 @@ public: static void compileExpression(CompilerContext& _context, Expression& _expression); /// Appends code to remove dirty higher order bits in case of an implicit promotion to a wider type. - static void cleanHigherOrderBitsIfNeeded(Type const& _typeOnStack, Type const& _targetType); + static void appendTypeConversion(CompilerContext& _context, Type const& _typeOnStack, Type const& _targetType); private: ExpressionCompiler(CompilerContext& _compilerContext): m_currentLValue(nullptr), m_context(_compilerContext) {} @@ -62,6 +64,14 @@ private: void appendShiftOperatorCode(Token::Value _operator); /// @} + /// Appends an implicit or explicit type conversion. For now this comprises only erasing + /// higher-order bits (@see appendHighBitCleanup) when widening integer types. + /// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be + /// necessary. + void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false); + //// Appends code that cleans higher-order bits for integer types. + void appendHighBitsCleanup(IntegerType const& _typeOnStack); + /// Stores the value on top of the stack in the current lvalue and copies that value to the /// top of the stack again void storeInLValue(Expression const& _expression); diff --git a/libsolidity/Scanner.cpp b/libsolidity/Scanner.cpp index c36820317..b13e52d7e 100644 --- a/libsolidity/Scanner.cpp +++ b/libsolidity/Scanner.cpp @@ -271,7 +271,7 @@ void Scanner::scanToken() token = Token::ADD; break; case '-': - // - -- -= + // - -- -= Number advance(); if (m_char == '-') { @@ -280,6 +280,8 @@ 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; @@ -331,7 +333,7 @@ void Scanner::scanToken() // . Number advance(); if (IsDecimalDigit(m_char)) - token = scanNumber(true); + token = scanNumber('.'); else token = Token::PERIOD; break; @@ -372,7 +374,7 @@ void Scanner::scanToken() if (IsIdentifierStart(m_char)) token = scanIdentifierOrKeyword(); else if (IsDecimalDigit(m_char)) - token = scanNumber(false); + token = scanNumber(); else if (skipWhitespace()) token = Token::WHITESPACE; else if (isSourcePastEndOfInput()) @@ -461,14 +463,11 @@ void Scanner::scanDecimalDigits() } -Token::Value Scanner::scanNumber(bool _periodSeen) +Token::Value Scanner::scanNumber(char _charSeen) { - // the first digit of the number or the fraction - if (asserts(IsDecimalDigit(m_char))) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Number does not start with decimal digit.")); - enum { DECIMAL, HEX, OCTAL, IMPLICIT_OCTAL, BINARY } kind = DECIMAL; + enum { DECIMAL, HEX, BINARY } kind = DECIMAL; LiteralScope literal(this); - if (_periodSeen) + if (_charSeen == '.') { // we have already seen a decimal point of the float addLiteralChar('.'); @@ -476,12 +475,13 @@ Token::Value Scanner::scanNumber(bool _periodSeen) } else { + if (_charSeen == '-') + addLiteralChar('-'); // if the first character is '0' we must check for octals and hex if (m_char == '0') { addLiteralCharAndAdvance(); - // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or - // an octal number. + // either 0, 0exxx, 0Exxx, 0.xxx or a hex number if (m_char == 'x' || m_char == 'X') { // hex number @@ -556,17 +556,73 @@ Token::Value Scanner::scanNumber(bool _periodSeen) KEYWORD("function", Token::FUNCTION) \ KEYWORD_GROUP('h') \ KEYWORD("hash", Token::HASH) \ + KEYWORD("hash8", Token::HASH8) \ + KEYWORD("hash16", Token::HASH16) \ + KEYWORD("hash24", Token::HASH24) \ KEYWORD("hash32", Token::HASH32) \ + KEYWORD("hash40", Token::HASH40) \ + KEYWORD("hash48", Token::HASH48) \ + KEYWORD("hash56", Token::HASH56) \ KEYWORD("hash64", Token::HASH64) \ + KEYWORD("hash72", Token::HASH72) \ + KEYWORD("hash80", Token::HASH80) \ + KEYWORD("hash88", Token::HASH88) \ + KEYWORD("hash96", Token::HASH96) \ + KEYWORD("hash104", Token::HASH104) \ + KEYWORD("hash112", Token::HASH112) \ + KEYWORD("hash120", Token::HASH120) \ KEYWORD("hash128", Token::HASH128) \ + KEYWORD("hash136", Token::HASH136) \ + KEYWORD("hash144", Token::HASH144) \ + KEYWORD("hash152", Token::HASH152) \ + KEYWORD("hash160", Token::HASH160) \ + KEYWORD("hash168", Token::HASH168) \ + KEYWORD("hash178", Token::HASH176) \ + KEYWORD("hash184", Token::HASH184) \ + KEYWORD("hash192", Token::HASH192) \ + KEYWORD("hash200", Token::HASH200) \ + KEYWORD("hash208", Token::HASH208) \ + KEYWORD("hash216", Token::HASH216) \ + KEYWORD("hash224", Token::HASH224) \ + KEYWORD("hash232", Token::HASH232) \ + KEYWORD("hash240", Token::HASH240) \ + KEYWORD("hash248", Token::HASH248) \ KEYWORD("hash256", Token::HASH256) \ KEYWORD_GROUP('i') \ KEYWORD("if", Token::IF) \ KEYWORD("in", Token::IN) \ KEYWORD("int", Token::INT) \ + KEYWORD("int8", Token::INT8) \ + KEYWORD("int16", Token::INT16) \ + KEYWORD("int24", Token::INT24) \ KEYWORD("int32", Token::INT32) \ + KEYWORD("int40", Token::INT40) \ + KEYWORD("int48", Token::INT48) \ + KEYWORD("int56", Token::INT56) \ KEYWORD("int64", Token::INT64) \ + KEYWORD("int72", Token::INT72) \ + KEYWORD("int80", Token::INT80) \ + KEYWORD("int88", Token::INT88) \ + KEYWORD("int96", Token::INT96) \ + KEYWORD("int104", Token::INT104) \ + KEYWORD("int112", Token::INT112) \ + KEYWORD("int120", Token::INT120) \ KEYWORD("int128", Token::INT128) \ + KEYWORD("int136", Token::INT136) \ + KEYWORD("int144", Token::INT144) \ + KEYWORD("int152", Token::INT152) \ + KEYWORD("int160", Token::INT160) \ + KEYWORD("int168", Token::INT168) \ + KEYWORD("int178", Token::INT176) \ + KEYWORD("int184", Token::INT184) \ + KEYWORD("int192", Token::INT192) \ + KEYWORD("int200", Token::INT200) \ + KEYWORD("int208", Token::INT208) \ + KEYWORD("int216", Token::INT216) \ + KEYWORD("int224", Token::INT224) \ + KEYWORD("int232", Token::INT232) \ + KEYWORD("int240", Token::INT240) \ + KEYWORD("int248", Token::INT248) \ KEYWORD("int256", Token::INT256) \ KEYWORD_GROUP('l') \ KEYWORD_GROUP('m') \ @@ -591,9 +647,37 @@ Token::Value Scanner::scanNumber(bool _periodSeen) KEYWORD("true", Token::TRUE_LITERAL) \ KEYWORD_GROUP('u') \ KEYWORD("uint", Token::UINT) \ + KEYWORD("uint8", Token::UINT8) \ + KEYWORD("uint16", Token::UINT16) \ + KEYWORD("uint24", Token::UINT24) \ KEYWORD("uint32", Token::UINT32) \ + KEYWORD("uint40", Token::UINT40) \ + KEYWORD("uint48", Token::UINT48) \ + KEYWORD("uint56", Token::UINT56) \ KEYWORD("uint64", Token::UINT64) \ + KEYWORD("uint72", Token::UINT72) \ + KEYWORD("uint80", Token::UINT80) \ + KEYWORD("uint88", Token::UINT88) \ + KEYWORD("uint96", Token::UINT96) \ + KEYWORD("uint104", Token::UINT104) \ + KEYWORD("uint112", Token::UINT112) \ + KEYWORD("uint120", Token::UINT120) \ KEYWORD("uint128", Token::UINT128) \ + KEYWORD("uint136", Token::UINT136) \ + KEYWORD("uint144", Token::UINT144) \ + KEYWORD("uint152", Token::UINT152) \ + KEYWORD("uint160", Token::UINT160) \ + KEYWORD("uint168", Token::UINT168) \ + KEYWORD("uint178", Token::UINT176) \ + KEYWORD("uint184", Token::UINT184) \ + KEYWORD("uint192", Token::UINT192) \ + KEYWORD("uint200", Token::UINT200) \ + KEYWORD("uint208", Token::UINT208) \ + KEYWORD("uint216", Token::UINT216) \ + KEYWORD("uint224", Token::UINT224) \ + KEYWORD("uint232", Token::UINT232) \ + KEYWORD("uint240", Token::UINT240) \ + KEYWORD("uint248", Token::UINT248) \ KEYWORD("uint256", Token::UINT256) \ KEYWORD("ureal", Token::UREAL) \ KEYWORD_GROUP('v') \ diff --git a/libsolidity/Scanner.h b/libsolidity/Scanner.h index 537c2434e..997365f3c 100644 --- a/libsolidity/Scanner.h +++ b/libsolidity/Scanner.h @@ -180,7 +180,7 @@ private: Token::Value skipMultiLineComment(); void scanDecimalDigits(); - Token::Value scanNumber(bool _periodSeen); + Token::Value scanNumber(char _charSeen = 0); Token::Value scanIdentifierOrKeyword(); Token::Value scanString(); diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 0fb9b670f..67971c3d0 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -169,19 +169,103 @@ namespace solidity * the implementation in Types.cpp has to be synced to this here * TODO more to be added */ \ K(INT, "int", 0) \ + K(INT8, "int8", 0) \ + K(INT16, "int16", 0) \ + K(INT24, "int24", 0) \ K(INT32, "int32", 0) \ + K(INT40, "int40", 0) \ + K(INT48, "int48", 0) \ + K(INT56, "int56", 0) \ K(INT64, "int64", 0) \ + K(INT72, "int72", 0) \ + K(INT80, "int80", 0) \ + K(INT88, "int88", 0) \ + K(INT96, "int96", 0) \ + K(INT104, "int104", 0) \ + K(INT112, "int112", 0) \ + K(INT120, "int120", 0) \ K(INT128, "int128", 0) \ + K(INT136, "int136", 0) \ + K(INT144, "int144", 0) \ + K(INT152, "int152", 0) \ + K(INT160, "int160", 0) \ + K(INT168, "int168", 0) \ + K(INT176, "int178", 0) \ + K(INT184, "int184", 0) \ + K(INT192, "int192", 0) \ + K(INT200, "int200", 0) \ + K(INT208, "int208", 0) \ + K(INT216, "int216", 0) \ + K(INT224, "int224", 0) \ + K(INT232, "int232", 0) \ + K(INT240, "int240", 0) \ + K(INT248, "int248", 0) \ K(INT256, "int256", 0) \ K(UINT, "uint", 0) \ + K(UINT8, "uint8", 0) \ + K(UINT16, "uint16", 0) \ + K(UINT24, "uint24", 0) \ K(UINT32, "uint32", 0) \ + K(UINT40, "uint40", 0) \ + K(UINT48, "uint48", 0) \ + K(UINT56, "uint56", 0) \ K(UINT64, "uint64", 0) \ + K(UINT72, "uint72", 0) \ + K(UINT80, "uint80", 0) \ + K(UINT88, "uint88", 0) \ + K(UINT96, "uint96", 0) \ + K(UINT104, "uint104", 0) \ + K(UINT112, "uint112", 0) \ + K(UINT120, "uint120", 0) \ K(UINT128, "uint128", 0) \ + K(UINT136, "uint136", 0) \ + K(UINT144, "uint144", 0) \ + K(UINT152, "uint152", 0) \ + K(UINT160, "uint160", 0) \ + K(UINT168, "uint168", 0) \ + K(UINT176, "uint178", 0) \ + K(UINT184, "uint184", 0) \ + K(UINT192, "uint192", 0) \ + K(UINT200, "uint200", 0) \ + K(UINT208, "uint208", 0) \ + K(UINT216, "uint216", 0) \ + K(UINT224, "uint224", 0) \ + K(UINT232, "uint232", 0) \ + K(UINT240, "uint240", 0) \ + K(UINT248, "uint248", 0) \ K(UINT256, "uint256", 0) \ K(HASH, "hash", 0) \ + K(HASH8, "hash8", 0) \ + K(HASH16, "hash16", 0) \ + K(HASH24, "hash24", 0) \ K(HASH32, "hash32", 0) \ + K(HASH40, "hash40", 0) \ + K(HASH48, "hash48", 0) \ + K(HASH56, "hash56", 0) \ K(HASH64, "hash64", 0) \ + K(HASH72, "hash72", 0) \ + K(HASH80, "hash80", 0) \ + K(HASH88, "hash88", 0) \ + K(HASH96, "hash96", 0) \ + K(HASH104, "hash104", 0) \ + K(HASH112, "hash112", 0) \ + K(HASH120, "hash120", 0) \ K(HASH128, "hash128", 0) \ + K(HASH136, "hash136", 0) \ + K(HASH144, "hash144", 0) \ + K(HASH152, "hash152", 0) \ + K(HASH160, "hash160", 0) \ + K(HASH168, "hash168", 0) \ + K(HASH176, "hash178", 0) \ + K(HASH184, "hash184", 0) \ + K(HASH192, "hash192", 0) \ + K(HASH200, "hash200", 0) \ + K(HASH208, "hash208", 0) \ + K(HASH216, "hash216", 0) \ + K(HASH224, "hash224", 0) \ + K(HASH232, "hash232", 0) \ + K(HASH240, "hash240", 0) \ + K(HASH248, "hash248", 0) \ K(HASH256, "hash256", 0) \ K(ADDRESS, "address", 0) \ K(BOOL, "bool", 0) \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index a4d70e3a0..7354255e1 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -25,12 +25,14 @@ #include #include +using namespace std; + namespace dev { namespace solidity { -std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) +shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) { if (asserts(Token::isElementaryTypeName(_typeToken))) BOOST_THROW_EXCEPTION(InternalCompilerError()); @@ -38,58 +40,63 @@ std::shared_ptr Type::fromElementaryTypeName(Token::Value _typeToken) if (Token::INT <= _typeToken && _typeToken <= Token::HASH256) { int offset = _typeToken - Token::INT; - int bits = offset % 5; - if (bits == 0) - bits = 256; - else - bits = (1 << (bits - 1)) * 32; - int modifier = offset / 5; - return std::make_shared(bits, - modifier == 0 ? IntegerType::Modifier::SIGNED : - modifier == 1 ? IntegerType::Modifier::UNSIGNED : - IntegerType::Modifier::HASH); + int bytes = offset % 33; + if (bytes == 0) + bytes = 32; + int modifier = offset / 33; + return make_shared(bytes * 8, + modifier == 0 ? IntegerType::Modifier::SIGNED : + modifier == 1 ? IntegerType::Modifier::UNSIGNED : + IntegerType::Modifier::HASH); } else if (_typeToken == Token::ADDRESS) - return std::make_shared(0, IntegerType::Modifier::ADDRESS); + return make_shared(0, IntegerType::Modifier::ADDRESS); else if (_typeToken == Token::BOOL) - return std::make_shared(); + return make_shared(); else BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type.")); - return std::shared_ptr(); + return shared_ptr(); } -std::shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) +shared_ptr Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName) { - return std::make_shared(*_typeName.getReferencedStruct()); + return make_shared(*_typeName.getReferencedStruct()); } -std::shared_ptr Type::fromMapping(Mapping const&) +shared_ptr Type::fromMapping(Mapping const&) { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Mapping types not yet implemented.")); - return std::shared_ptr(); + return shared_ptr(); } -std::shared_ptr Type::forLiteral(Literal const& _literal) +shared_ptr Type::forLiteral(Literal const& _literal) { switch (_literal.getToken()) { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: - return std::make_shared(); + return make_shared(); case Token::NUMBER: return IntegerType::smallestTypeForLiteral(_literal.getValue()); case Token::STRING_LITERAL: - return std::shared_ptr(); // @todo + return shared_ptr(); // @todo default: - return std::shared_ptr(); + return shared_ptr(); } } -std::shared_ptr IntegerType::smallestTypeForLiteral(std::string const&) +shared_ptr IntegerType::smallestTypeForLiteral(string const& _literal) { - //@todo - return std::make_shared(256, Modifier::UNSIGNED); + 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): @@ -155,19 +162,17 @@ bool IntegerType::operator==(Type const& _other) const return other.m_bits == m_bits && other.m_modifier == m_modifier; } -std::string IntegerType::toString() const +string IntegerType::toString() const { if (isAddress()) return "address"; - std::string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint"); + string prefix = isHash() ? "hash" : (isSigned() ? "int" : "uint"); return prefix + dev::toString(m_bits); } u256 IntegerType::literalValue(Literal const& _literal) const { bigint value(_literal.getValue()); - //@todo check that the number is not too large - //@todo does this work for signed numbers? return u256(value); } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 4493b8037..8c88ca79f 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -56,7 +56,8 @@ public: static std::shared_ptr fromMapping(Mapping const& _typeName); /// @} - /// Auto-detect the proper type for a literal + /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does + /// not fit any type. static std::shared_ptr forLiteral(Literal const& _literal); virtual Category getCategory() const = 0; @@ -95,6 +96,8 @@ public: }; virtual Category getCategory() const override { return Category::INTEGER; } + /// @returns the smallest integer type for the given literal or an empty pointer + /// if no type fits. static std::shared_ptr smallestTypeForLiteral(std::string const& _literal); explicit IntegerType(int _bits, Modifier _modifier = Modifier::UNSIGNED); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 7e5d29080..40ec744bd 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -22,7 +22,7 @@ */ #include "WebThreeStubServer.h" -#include +#include #include #include #include diff --git a/lllc/CMakeLists.txt b/lllc/CMakeLists.txt index 9d5e8c5ff..a9b53c74c 100644 --- a/lllc/CMakeLists.txt +++ b/lllc/CMakeLists.txt @@ -9,7 +9,7 @@ set(EXECUTABLE lllc) add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/lllc/main.cpp b/lllc/main.cpp index a4c9df78c..1a44ee950 100644 --- a/lllc/main.cpp +++ b/lllc/main.cpp @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include "BuildInfo.h" using namespace std; using namespace dev; diff --git a/neth/main.cpp b/neth/main.cpp index 06e22f963..6be555fbb 100644 --- a/neth/main.cpp +++ b/neth/main.cpp @@ -30,7 +30,7 @@ #include #endif #include -#include +#include #include #if ETH_JSONRPC #include diff --git a/sc/CMakeLists.txt b/sc/CMakeLists.txt index 3cacf78e6..9aa23b03b 100644 --- a/sc/CMakeLists.txt +++ b/sc/CMakeLists.txt @@ -10,7 +10,7 @@ add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} serpent) target_link_libraries(${EXECUTABLE} lll) -target_link_libraries(${EXECUTABLE} evmface) +target_link_libraries(${EXECUTABLE} evmcore) target_link_libraries(${EXECUTABLE} devcore) if ("${TARGET_PLATFORM}" STREQUAL "w64") diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index 28e4342d7..321e515d6 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "vm.h" using namespace std; diff --git a/test/solidityCompiler.cpp b/test/solidityCompiler.cpp index 69d331339..192fd61a4 100644 --- a/test/solidityCompiler.cpp +++ b/test/solidityCompiler.cpp @@ -119,10 +119,10 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers) byte(Instruction::JUMPDEST), // beginning of g byte(Instruction::PUSH1), 0x0, byte(Instruction::DUP1), // initialized e and h - byte(Instruction::PUSH1), byte(0x20 + shift), // ret address - byte(Instruction::PUSH1), 0x1, - byte(Instruction::PUSH1), 0x2, - byte(Instruction::PUSH1), 0x3, + byte(Instruction::PUSH1), 0x29 + shift, // ret address + byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), + byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), + byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND), byte(Instruction::PUSH1), byte(0x1 + shift), // stack here: ret e h 0x20 1 2 3 0x1 byte(Instruction::JUMP), diff --git a/test/solidityEndToEndTest.cpp b/test/solidityEndToEndTest.cpp index 116310aed..35c2a3b02 100644 --- a/test/solidityEndToEndTest.cpp +++ b/test/solidityEndToEndTest.cpp @@ -41,31 +41,31 @@ class ExecutionFramework public: ExecutionFramework() { g_logVerbosity = 0; } - bytes compileAndRun(std::string const& _sourceCode) + bytes const& compileAndRun(std::string const& _sourceCode) { bytes code = dev::solidity::CompilerStack::compile(_sourceCode); sendMessage(code, true); + BOOST_REQUIRE(!m_output.empty()); return m_output; } - bytes callFunction(byte _index, bytes const& _data) + bytes const& callFunction(byte _index, bytes const& _data) { sendMessage(bytes(1, _index) + _data, false); return m_output; } - bytes callFunction(byte _index, u256 const& _argument1) + bytes const& callFunction(byte _index, u256 const& _argument1) { - callFunction(_index, toBigEndian(_argument1)); - return m_output; + return callFunction(_index, toBigEndian(_argument1)); } private: void sendMessage(bytes const& _data, bool _isCreation) { eth::Executive executive(m_state); - eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data) - : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data); + eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) + : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec()); bytes transactionRLP = t.rlp(); try { @@ -77,13 +77,14 @@ private: { BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address())); m_contractAddress = executive.newAddress(); + BOOST_REQUIRE(m_contractAddress); BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress)); } else BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address())); BOOST_REQUIRE(executive.go()); executive.finalize(); - m_output = executive.out().toBytes(); + m_output = executive.out().toVector(); } Address m_contractAddress; @@ -93,27 +94,24 @@ private: bytes m_output; }; -BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest) +BOOST_FIXTURE_TEST_SUITE(SolidityCompilerEndToEndTest, ExecutionFramework) BOOST_AUTO_TEST_CASE(smoke_test) { char const* sourceCode = "contract test {\n" " function f(uint a) returns(uint d) { return a * 7; }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); + compileAndRun(sourceCode); u256 a = 0x200030004; - bytes result = framework.callFunction(0, a); - BOOST_CHECK(result == toBigEndian(a * 7)); + BOOST_CHECK(callFunction(0, a) == toBigEndian(a * 7)); } BOOST_AUTO_TEST_CASE(empty_contract) { char const* sourceCode = "contract test {\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, bytes()).empty()); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()).empty()); } BOOST_AUTO_TEST_CASE(recursive_calls) @@ -124,13 +122,12 @@ BOOST_AUTO_TEST_CASE(recursive_calls) " else return n * f(n - 1);\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2))); - BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6))); - BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2))); + BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6))); + BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24))); } BOOST_AUTO_TEST_CASE(while_loop) @@ -142,13 +139,12 @@ BOOST_AUTO_TEST_CASE(while_loop) " while (i <= n) nfac *= i++;\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2))); - BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6))); - BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2))); + BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6))); + BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24))); } BOOST_AUTO_TEST_CASE(break_outside_loop) @@ -217,13 +213,12 @@ BOOST_AUTO_TEST_CASE(calling_other_functions) " return 3 * x + 1;\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(2, u256(0)) == toBigEndian(u256(0))); - BOOST_CHECK(framework.callFunction(2, u256(1)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(2, u256(2)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(2, u256(8)) == toBigEndian(u256(1))); - BOOST_CHECK(framework.callFunction(2, u256(127)) == toBigEndian(u256(1))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(2, u256(0)) == toBigEndian(u256(0))); + BOOST_CHECK(callFunction(2, u256(1)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(2, u256(2)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(2, u256(8)) == toBigEndian(u256(1))); + BOOST_CHECK(callFunction(2, u256(127)) == toBigEndian(u256(1))); } BOOST_AUTO_TEST_CASE(many_local_variables) @@ -235,12 +230,25 @@ BOOST_AUTO_TEST_CASE(many_local_variables) " y += b + x2;\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000))) + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000))) == toBigEndian(u256(0x121121))); } +BOOST_AUTO_TEST_CASE(packing_unpacking_types) +{ + char const* sourceCode = "contract test {\n" + " function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n" + " if (a) y = 1;\n" + " y = y * 0x100000000 | ~b;\n" + " y = y * 0x10000000000000000 | ~c;\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0")) + == fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f")); +} + BOOST_AUTO_TEST_CASE(multiple_return_values) { char const* sourceCode = "contract test {\n" @@ -248,9 +256,8 @@ BOOST_AUTO_TEST_CASE(multiple_return_values) " y1 = x2; y2 = x1;\n" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd))) == toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0))); } @@ -262,13 +269,59 @@ BOOST_AUTO_TEST_CASE(short_circuiting) " return x;" " }\n" "}\n"; - ExecutionFramework framework; - framework.compileAndRun(sourceCode); - BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0))); - BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8))); + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(0))); + BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(8))); } -//@todo test smaller types +BOOST_AUTO_TEST_CASE(high_bits_cleaning) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " uint32 x = uint32(0xffffffff) + 10;\n" + " if (x >= 0xffffffff) return 0;\n" + " return x;" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(9))); +} + +BOOST_AUTO_TEST_CASE(sign_extension) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " int64 x = -int32(0xff);\n" + " if (x >= 0xff) return 0;\n" + " return -uint256(x);" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xff))); +} + +BOOST_AUTO_TEST_CASE(small_unsigned_types) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(uint256 y) {\n" + " uint32 x = uint32(0xffffff) * 0xffffff;\n" + " return x / 0x100;" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xfe0000))); +} + +BOOST_AUTO_TEST_CASE(small_signed_types) +{ + char const* sourceCode = "contract test {\n" + " function run() returns(int256 y) {\n" + " return -int32(10) * -int64(20);\n" + " }\n" + "}\n"; + compileAndRun(sourceCode); + BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(200))); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/solidityExpressionCompiler.cpp b/test/solidityExpressionCompiler.cpp index 561cc3bda..8fc4a1a22 100644 --- a/test/solidityExpressionCompiler.cpp +++ b/test/solidityExpressionCompiler.cpp @@ -154,8 +154,8 @@ BOOST_AUTO_TEST_CASE(comparison) "}\n"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, - byte(eth::Instruction::PUSH2), 0x11, 0xaa, + bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::GT), byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::EQ), @@ -172,16 +172,16 @@ BOOST_AUTO_TEST_CASE(short_circuiting) bytes expectation({byte(eth::Instruction::PUSH1), 0xa, byte(eth::Instruction::PUSH1), 0x8, - byte(eth::Instruction::ADD), - byte(eth::Instruction::PUSH1), 0x4, + byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::GT), byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4 byte(eth::Instruction::DUP1), - byte(eth::Instruction::PUSH1), 0x14, + byte(eth::Instruction::PUSH1), 0x20, byte(eth::Instruction::JUMPI), // short-circuit if it is true byte(eth::Instruction::POP), - byte(eth::Instruction::PUSH1), 0x2, - byte(eth::Instruction::PUSH1), 0x9, + byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::EQ), byte(eth::Instruction::ISZERO), // after this we have 2 != 9 byte(eth::Instruction::JUMPDEST), @@ -197,10 +197,11 @@ BOOST_AUTO_TEST_CASE(arithmetics) " function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }" "}\n"; bytes code = compileFirstExpression(sourceCode); - bytes expectation({byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0x3, + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0x5, byte(eth::Instruction::PUSH1), 0x6, @@ -213,8 +214,10 @@ BOOST_AUTO_TEST_CASE(arithmetics) byte(eth::Instruction::SWAP1), byte(eth::Instruction::SUB), byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::SWAP1), byte(eth::Instruction::MOD), + byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::SWAP1), byte(eth::Instruction::DIV), byte(eth::Instruction::MUL)}); @@ -224,15 +227,15 @@ BOOST_AUTO_TEST_CASE(arithmetics) BOOST_AUTO_TEST_CASE(unary_operators) { char const* sourceCode = "contract test {\n" - " function f() { var x = !(~+-1 == 2); }" + " function f() { var x = !(~+- 1 == 2); }" "}\n"; bytes code = compileFirstExpression(sourceCode); bytes expectation({byte(eth::Instruction::PUSH1), 0x1, byte(eth::Instruction::PUSH1), 0x0, byte(eth::Instruction::SUB), - byte(eth::Instruction::NOT), - byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), + byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::EQ), byte(eth::Instruction::ISZERO)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); @@ -305,7 +308,7 @@ BOOST_AUTO_TEST_CASE(assignment) byte(eth::Instruction::POP), byte(eth::Instruction::DUP2), // Stack here: a+b b a+b - byte(eth::Instruction::PUSH1), 0x2, + byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::MUL)}); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } @@ -320,17 +323,17 @@ BOOST_AUTO_TEST_CASE(function_call) {{"test", "f", "a"}, {"test", "f", "b"}}); // Stack: a, b - bytes expectation({byte(eth::Instruction::PUSH1), 0x0a, + bytes expectation({byte(eth::Instruction::PUSH1), 0x0d, byte(eth::Instruction::DUP3), - byte(eth::Instruction::PUSH1), 0x01, + byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::ADD), // Stack here: a b (a+1) byte(eth::Instruction::DUP3), - byte(eth::Instruction::PUSH1), 0x14, + byte(eth::Instruction::PUSH1), 0x1a, byte(eth::Instruction::JUMP), byte(eth::Instruction::JUMPDEST), // Stack here: a b g(a+1, b) - byte(eth::Instruction::PUSH1), 0x02, + byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND), byte(eth::Instruction::MUL), // Stack here: a b g(a+1, b)*2 byte(eth::Instruction::DUP3), @@ -344,6 +347,45 @@ BOOST_AUTO_TEST_CASE(function_call) BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } +BOOST_AUTO_TEST_CASE(negative_literals_8bits) +{ + // these all fit in 8 bits + char const* sourceCode = "contract test {\n" + " function f() { int8 x = -0 + -1 + -0x01 + -127 + -128; }\n" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation(bytes({byte(eth::Instruction::PUSH1), 0x00, + byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x81) + + bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x80) + + bytes({byte(eth::Instruction::ADD)})); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + +BOOST_AUTO_TEST_CASE(negative_literals_16bits) +{ + // -1 should need 8 bits, -129 should need 16 bits, how many bits are used is visible + // from the SIGNEXTEND opcodes + char const* sourceCode = "contract test {\n" + " function f() { int64 x = int64(-1 + -129); }\n" + "}\n"; + bytes code = compileFirstExpression(sourceCode); + + bytes expectation(bytes({byte(eth::Instruction::PUSH32)}) + bytes(32, 0xff) + + bytes({byte(eth::Instruction::PUSH1), 0x00, + byte(eth::Instruction::SIGNEXTEND), + byte(eth::Instruction::PUSH32)}) + bytes(31, 0xff) + bytes(1, 0x7f) + + bytes({byte(eth::Instruction::ADD), + byte(eth::Instruction::PUSH1), 0x01, + byte(eth::Instruction::SIGNEXTEND)})); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/solidityNameAndTypeResolution.cpp b/test/solidityNameAndTypeResolution.cpp index 9e34e6d0e..f46ad6733 100644 --- a/test/solidityNameAndTypeResolution.cpp +++ b/test/solidityNameAndTypeResolution.cpp @@ -162,6 +162,22 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(type_conversion_for_comparison) +{ + char const* text = "contract test {\n" + " function f() { uint32(2) == int64(2); }" + "}\n"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(type_conversion_for_comparison_invalid) +{ + char const* text = "contract test {\n" + " function f() { int32(2) == uint64(2); }" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_CASE(type_inference_explicit_conversion) { char const* text = "contract test {\n" diff --git a/test/solidityScanner.cpp b/test/solidityScanner.cpp index d2a960cfb..d714699a0 100644 --- a/test/solidityScanner.cpp +++ b/test/solidityScanner.cpp @@ -97,6 +97,27 @@ BOOST_AUTO_TEST_CASE(hex_numbers) BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); } +BOOST_AUTO_TEST_CASE(negative_numbers) +{ + Scanner scanner(CharStream("var x = -.2 + -0x78 + -7.3 + 8.9;")); + BOOST_CHECK_EQUAL(scanner.getCurrentToken(), Token::VAR); + BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); + BOOST_CHECK_EQUAL(scanner.next(), Token::ASSIGN); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-.2"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-0x78"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "-7.3"); + BOOST_CHECK_EQUAL(scanner.next(), Token::ADD); + BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); + BOOST_CHECK_EQUAL(scanner.getCurrentLiteral(), "8.9"); + BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); + BOOST_CHECK_EQUAL(scanner.next(), Token::EOS); +} + BOOST_AUTO_TEST_CASE(locations) { Scanner scanner(CharStream("function_identifier has ; -0x743/*comment*/\n ident //comment")); @@ -109,11 +130,8 @@ BOOST_AUTO_TEST_CASE(locations) BOOST_CHECK_EQUAL(scanner.next(), Token::SEMICOLON); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 24); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 25); - BOOST_CHECK_EQUAL(scanner.next(), Token::SUB); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 27); BOOST_CHECK_EQUAL(scanner.next(), Token::NUMBER); - BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 27); + BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 26); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().end, 32); BOOST_CHECK_EQUAL(scanner.next(), Token::IDENTIFIER); BOOST_CHECK_EQUAL(scanner.getCurrentLocation().start, 45); diff --git a/test/vm.h b/test/vm.h index 1ed33e5fa..a52a02e31 100644 --- a/test/vm.h +++ b/test/vm.h @@ -29,7 +29,7 @@ along with cpp-ethereum. If not, see . #include "JsonSpiritHeaders.h" #include #include -#include +#include #include #include #include diff --git a/third/CMakeLists.txt b/third/CMakeLists.txt index 6edea7456..d5371b666 100644 --- a/third/CMakeLists.txt +++ b/third/CMakeLists.txt @@ -53,7 +53,7 @@ else () endif () qt5_use_modules(${EXECUTEABLE} Core)# Gui Widgets Network WebKit WebKitWidgets) -target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmface devcore web3jsonrpc jsqrc) +target_link_libraries(${EXECUTEABLE} webthree qethereum ethereum evm ethcore secp256k1 gmp ${CRYPTOPP_LS} serpent lll evmcore devcore web3jsonrpc jsqrc) if (APPLE) # First have qt5 install plugins and frameworks diff --git a/walleth/MainWin.cpp b/walleth/MainWin.cpp index 3fa5a9388..f56cad65d 100644 --- a/walleth/MainWin.cpp +++ b/walleth/MainWin.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include "BuildInfo.h" diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index c308f05e7..30deea983 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -125,7 +125,7 @@ - + true true @@ -341,7 +341,7 @@ - + true true @@ -367,7 +367,7 @@ true - + @@ -567,4 +567,4 @@ - \ No newline at end of file + diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index 137440619..514320472 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -37,8 +37,8 @@ libevm - - libevmface + + libevmcore liblll @@ -243,14 +243,14 @@ libevm - - libevmface + + libevmcore liblll - - liblll + + libevmcore liblll @@ -449,7 +449,7 @@ {37c37803-1515-47c1-b7e6-3879f4429ab3} - + {ed9ad1b3-700c-47f9-8548-a90b5ef179ac} @@ -471,4 +471,4 @@ {d838fece-fc20-42f6-bff5-97c236159b80} - \ No newline at end of file +