diff options
36 files changed, 332 insertions, 61 deletions
diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index ba66d79f..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "deps"] - path = deps - url = https://github.com/ethereum/cpp-dependencies diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a65071d..89d627dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" # Let's find our dependencies include(EthDependencies) -include(deps/jsoncpp.cmake) +include(jsoncpp) find_package(Threads) diff --git a/Changelog.md b/Changelog.md index c4918013..458a9543 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Features: * Support ``pragma experimental "v0.5.0";`` to turn on upcoming breaking changes. + * Assembly Parser: Support multiple assignment (``x, y := f()``). * Code Generator: Added ``.selector`` member on external function types to retrieve their signature. * Code Generator: Keep a single copy of encoding functions when using the experimental "ABIEncoderV2". * Optimizer: Add new optimization step to remove unused ``JUMPDEST``s. diff --git a/cmake/jsoncpp.cmake b/cmake/jsoncpp.cmake new file mode 100644 index 00000000..6ddf4c74 --- /dev/null +++ b/cmake/jsoncpp.cmake @@ -0,0 +1,51 @@ +include(ExternalProject) + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten") + set(JSONCPP_CMAKE_COMMAND emcmake cmake) +else() + set(JSONCPP_CMAKE_COMMAND ${CMAKE_COMMAND}) +endif() + +# Disable implicit fallthrough warning in jsoncpp for gcc >= 7 until the upstream handles it properly +if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0) + set(JSONCCP_EXTRA_FLAGS -Wno-implicit-fallthrough) +else() + set(JSONCCP_EXTRA_FLAGS "") +endif() + +set(prefix "${CMAKE_BINARY_DIR}/deps") +set(JSONCPP_LIBRARY "${prefix}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}jsoncpp${CMAKE_STATIC_LIBRARY_SUFFIX}") +set(JSONCPP_INCLUDE_DIR "${prefix}/include") + +set(byproducts "") +if(CMAKE_VERSION VERSION_GREATER 3.1) + set(byproducts BUILD_BYPRODUCTS "${JSONCPP_LIBRARY}") +endif() + +ExternalProject_Add(jsoncpp-project + PREFIX "${prefix}" + DOWNLOAD_DIR "${CMAKE_SOURCE_DIR}/deps/downloads" + DOWNLOAD_NAME jsoncpp-1.7.7.tar.gz + URL https://github.com/open-source-parsers/jsoncpp/archive/1.7.7.tar.gz + URL_HASH SHA256=087640ebcf7fbcfe8e2717a0b9528fff89c52fcf69fa2a18cc2b538008098f97 + CMAKE_COMMAND ${JSONCPP_CMAKE_COMMAND} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + # Build static lib but suitable to be included in a shared lib. + -DCMAKE_POSITION_INDEPENDENT_CODE=${BUILD_SHARED_LIBS} + -DJSONCPP_WITH_TESTS=OFF + -DJSONCPP_WITH_PKGCONFIG_SUPPORT=OFF + -DCMAKE_CXX_FLAGS=${JSONCCP_EXTRA_FLAGS} + # Overwrite build and install commands to force Release build on MSVC. + BUILD_COMMAND cmake --build <BINARY_DIR> --config Release + INSTALL_COMMAND cmake --build <BINARY_DIR> --config Release --target install + ${byproducts} +) + +# Create jsoncpp imported library +add_library(jsoncpp STATIC IMPORTED) +file(MAKE_DIRECTORY ${JSONCPP_INCLUDE_DIR}) # Must exist. +set_property(TARGET jsoncpp PROPERTY IMPORTED_LOCATION ${JSONCPP_LIBRARY}) +set_property(TARGET jsoncpp PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${JSONCPP_INCLUDE_DIR}) +add_dependencies(jsoncpp jsoncpp-project) diff --git a/deps b/deps deleted file mode 160000 -Subproject e5c8316db8d3daa0abc3b5af8545ce330057608 diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 97320c7f..29d98645 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -42,7 +42,7 @@ The following elementary types exist: - ``address``: equivalent to ``uint160``, except for the assumed interpretation and language typing. -- ``uint``, ``int``: synonyms for ``uint256``, ``int256`` respectively (not to be used for computing the function selector). +- ``uint``, ``int``: synonyms for ``uint256``, ``int256`` respectively (this shorthand not to be used for computing the function selector). - ``bool``: equivalent to ``uint8`` restricted to the values 0 and 1 @@ -50,7 +50,7 @@ The following elementary types exist: - ``ufixed<M>x<N>``: unsigned variant of ``fixed<M>x<N>``. -- ``fixed``, ``ufixed``: synonyms for ``fixed128x19``, ``ufixed128x19`` respectively (not to be used for computing the function selector). +- ``fixed``, ``ufixed``: synonyms for ``fixed128x19``, ``ufixed128x19`` respectively (this shorthand not to be used for computing the function selector). - ``bytes<M>``: binary type of ``M`` bytes, ``0 < M <= 32``. @@ -58,7 +58,7 @@ The following elementary types exist: The following (fixed-size) array type exists: -- ``<type>[M]``: a fixed-length array of the given fixed-length type. +- ``<type>[M]``: a fixed-length array of ``M`` elements, ``M > 0``, of the given type. The following non-fixed-size types exist: @@ -66,7 +66,7 @@ The following non-fixed-size types exist: - ``string``: dynamic sized unicode string assumed to be UTF-8 encoded. -- ``<type>[]``: a variable-length array of the given fixed-length type. +- ``<type>[]``: a variable-length array of elements of the given type. Types can be combined to a tuple by enclosing a finite non-negative number of them inside parentheses, separated by commas: diff --git a/libdevcore/SHA3.cpp b/libdevcore/SHA3.cpp index 4d82ec85..b0e40ccb 100644 --- a/libdevcore/SHA3.cpp +++ b/libdevcore/SHA3.cpp @@ -97,10 +97,9 @@ static const uint64_t RC[24] = \ static inline void keccakf(void* state) { uint64_t* a = (uint64_t*)state; uint64_t b[5] = {0}; - uint64_t t = 0; - uint8_t x, y; for (int i = 0; i < 24; i++) { + uint8_t x, y; // Theta FOR5(x, 1, b[x] = 0; @@ -110,7 +109,7 @@ static inline void keccakf(void* state) { FOR5(y, 5, a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) // Rho and pi - t = a[1]; + uint64_t t = a[1]; x = 0; REPEAT24(b[0] = a[pi[x]]; a[pi[x]] = rol(t, rho[x]); diff --git a/libdevcore/SwarmHash.h b/libdevcore/SwarmHash.h index a5da96f5..a06f7bda 100644 --- a/libdevcore/SwarmHash.h +++ b/libdevcore/SwarmHash.h @@ -26,7 +26,7 @@ namespace dev { -/// Compute the "swarm hash" of @a _data -h256 swarmHash(std::string const& _data); +/// Compute the "swarm hash" of @a _input +h256 swarmHash(std::string const& _input); } diff --git a/libevmasm/ConstantOptimiser.h b/libevmasm/ConstantOptimiser.h index 82982e25..c450b0b4 100644 --- a/libevmasm/ConstantOptimiser.h +++ b/libevmasm/ConstantOptimiser.h @@ -91,7 +91,7 @@ protected: } /// Replaces all constants i by the code given in @a _replacement[i]. - static void replaceConstants(AssemblyItems& _items, std::map<u256, AssemblyItems> const& _replacement); + static void replaceConstants(AssemblyItems& _items, std::map<u256, AssemblyItems> const& _replacements); Params m_params; u256 const& m_value; diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 6a7c80e0..dad952bc 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -189,9 +189,9 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ return gas; } -GasMeter::GasConsumption GasMeter::wordGas(u256 const& _multiplier, ExpressionClasses::Id _position) +GasMeter::GasConsumption GasMeter::wordGas(u256 const& _multiplier, ExpressionClasses::Id _value) { - u256 const* value = m_state->expressionClasses().knownConstant(_position); + u256 const* value = m_state->expressionClasses().knownConstant(_value); if (!value) return GasConsumption::infinite(); return GasConsumption(_multiplier * ((*value + 31) / 32)); diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp index e0b11cf3..66f593e8 100644 --- a/libjulia/backends/evm/EVMCodeTransform.cpp +++ b/libjulia/backends/evm/EVMCodeTransform.cpp @@ -60,9 +60,12 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) void CodeTransform::operator()(Assignment const& _assignment) { - visitExpression(*_assignment.value); + int height = m_assembly.stackHeight(); + boost::apply_visitor(*this, *_assignment.value); + expectDeposit(_assignment.variableNames.size(), height); + m_assembly.setSourceLocation(_assignment.location); - generateAssignment(_assignment.variableName); + generateMultiAssignment(_assignment.variableNames); checkStackHeight(&_assignment); } @@ -469,6 +472,13 @@ void CodeTransform::finalizeBlock(Block const& _block, int blockStartStackHeight checkStackHeight(&_block); } +void CodeTransform::generateMultiAssignment(vector<Identifier> const& _variableNames) +{ + solAssert(m_scope, ""); + for (auto const& variableName: _variableNames | boost::adaptors::reversed) + generateAssignment(variableName); +} + void CodeTransform::generateAssignment(Identifier const& _variableName) { solAssert(m_scope, ""); diff --git a/libjulia/backends/evm/EVMCodeTransform.h b/libjulia/backends/evm/EVMCodeTransform.h index 2c0fd10c..951c8a50 100644 --- a/libjulia/backends/evm/EVMCodeTransform.h +++ b/libjulia/backends/evm/EVMCodeTransform.h @@ -124,6 +124,7 @@ private: /// to @a _blackStartStackHeight. void finalizeBlock(solidity::assembly::Block const& _block, int _blockStartStackHeight); + void generateMultiAssignment(std::vector<solidity::assembly::Identifier> const& _variableNames); void generateAssignment(solidity::assembly::Identifier const& _variableName); /// Determines the stack height difference to the given variables. Throws diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index d08c4eb5..b3fb5258 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -38,30 +38,30 @@ bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit) return !m_errorOccured; } -bool DocStringAnalyser::visit(ContractDefinition const& _node) +bool DocStringAnalyser::visit(ContractDefinition const& _contract) { static const set<string> validTags = set<string>{"author", "title", "dev", "notice"}; - parseDocStrings(_node, _node.annotation(), validTags, "contracts"); + parseDocStrings(_contract, _contract.annotation(), validTags, "contracts"); return true; } -bool DocStringAnalyser::visit(FunctionDefinition const& _node) +bool DocStringAnalyser::visit(FunctionDefinition const& _function) { - handleCallable(_node, _node, _node.annotation()); + handleCallable(_function, _function, _function.annotation()); return true; } -bool DocStringAnalyser::visit(ModifierDefinition const& _node) +bool DocStringAnalyser::visit(ModifierDefinition const& _modifier) { - handleCallable(_node, _node, _node.annotation()); + handleCallable(_modifier, _modifier, _modifier.annotation()); return true; } -bool DocStringAnalyser::visit(EventDefinition const& _node) +bool DocStringAnalyser::visit(EventDefinition const& _event) { - handleCallable(_node, _node, _node.annotation()); + handleCallable(_event, _event, _event.annotation()); return true; } diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 59bd3b1f..d83697cd 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -148,7 +148,7 @@ public: private: bool visit(SourceUnit& _sourceUnit) override; void endVisit(SourceUnit& _sourceUnit) override; - bool visit(ImportDirective& _declaration) override; + bool visit(ImportDirective& _import) override; bool visit(ContractDefinition& _contract) override; void endVisit(ContractDefinition& _contract) override; bool visit(StructDefinition& _struct) override; diff --git a/libsolidity/analysis/PostTypeChecker.h b/libsolidity/analysis/PostTypeChecker.h index dbdf50e0..91d2b0b9 100644 --- a/libsolidity/analysis/PostTypeChecker.h +++ b/libsolidity/analysis/PostTypeChecker.h @@ -50,8 +50,8 @@ private: virtual bool visit(ContractDefinition const& _contract) override; virtual void endVisit(ContractDefinition const& _contract) override; - virtual bool visit(VariableDeclaration const& _declaration) override; - virtual void endVisit(VariableDeclaration const& _declaration) override; + virtual bool visit(VariableDeclaration const& _variable) override; + virtual void endVisit(VariableDeclaration const& _variable) override; virtual bool visit(Identifier const& _identifier) override; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 6811d3e4..51249f20 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -129,7 +129,7 @@ string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) return std::to_string(_location.start) + ":" + std::to_string(length) + ":" + std::to_string(sourceIndex); } -string ASTJsonConverter::namePathToString(std::vector<ASTString> const& _namePath) const +string ASTJsonConverter::namePathToString(std::vector<ASTString> const& _namePath) { return boost::algorithm::join(_namePath, "."); } @@ -171,7 +171,7 @@ void ASTJsonConverter::appendExpressionAttributes( _attributes += exprAttributes; } -Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<assembly::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) +Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<assembly::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const { Json::Value tuple(Json::objectValue); tuple["src"] = sourceLocationToString(_info.first->location); diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 60c660c1..9a886220 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -120,7 +120,7 @@ private: std::vector<std::pair<std::string, Json::Value>>&& _attributes ); std::string sourceLocationToString(SourceLocation const& _location) const; - std::string namePathToString(std::vector<ASTString> const& _namePath) const; + static std::string namePathToString(std::vector<ASTString> const& _namePath); static Json::Value idOrNull(ASTNode const* _pt) { return _pt ? Json::Value(nodeId(*_pt)) : Json::nullValue; @@ -129,13 +129,13 @@ private: { return _node ? toJson(*_node) : Json::nullValue; } - Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info); - std::string location(VariableDeclaration::Location _location); - std::string contractKind(ContractDefinition::ContractKind _kind); - std::string functionCallKind(FunctionCallKind _kind); - std::string literalTokenKind(Token::Value _token); - std::string type(Expression const& _expression); - std::string type(VariableDeclaration const& _varDecl); + Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const; + static std::string location(VariableDeclaration::Location _location); + static std::string contractKind(ContractDefinition::ContractKind _kind); + static std::string functionCallKind(FunctionCallKind _kind); + static std::string literalTokenKind(Token::Value _token); + static std::string type(Expression const& _expression); + static std::string type(VariableDeclaration const& _varDecl); static int nodeId(ASTNode const& _node) { return _node.id(); @@ -151,8 +151,8 @@ private: } return tmp; } - Json::Value typePointerToJson(TypePointer _tp); - Json::Value typePointerToJson(std::shared_ptr<std::vector<TypePointer>> _tps); + static Json::Value typePointerToJson(TypePointer _tp); + static Json::Value typePointerToJson(std::shared_ptr<std::vector<TypePointer>> _tps); void appendExpressionAttributes( std::vector<std::pair<std::string, Json::Value>> &_attributes, ExpressionAnnotation const& _annotation diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h index 38c1e045..7c5ee59f 100644 --- a/libsolidity/codegen/ContractCompiler.h +++ b/libsolidity/codegen/ContractCompiler.h @@ -96,8 +96,8 @@ private: virtual bool visit(IfStatement const& _ifStatement) override; virtual bool visit(WhileStatement const& _whileStatement) override; virtual bool visit(ForStatement const& _forStatement) override; - virtual bool visit(Continue const& _continue) override; - virtual bool visit(Break const& _break) override; + virtual bool visit(Continue const& _continueStatement) override; + virtual bool visit(Break const& _breakStatement) override; virtual bool visit(Return const& _return) override; virtual bool visit(Throw const& _throw) override; virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 631a25ff..c94baa10 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1819,7 +1819,7 @@ void ExpressionCompiler::setLValueToStorageItem(Expression const& _expression) setLValue<StorageItem>(_expression, *_expression.annotation().type); } -bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op) const +bool ExpressionCompiler::cleanupNeededForOp(Type::Category _type, Token::Value _op) { if (Token::isCompareOp(_op) || Token::isShiftOp(_op)) return true; diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index 5f6c3d64..cdfa096e 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -119,7 +119,7 @@ private: /// @returns true if the operator applied to the given type requires a cleanup prior to the /// operation. - bool cleanupNeededForOp(Type::Category _type, Token::Value _op) const; + static bool cleanupNeededForOp(Type::Category _type, Token::Value _op); /// @returns the CompilerUtils object containing the current context. CompilerUtils utils(); diff --git a/libsolidity/formal/SMTLib2Interface.h b/libsolidity/formal/SMTLib2Interface.h index b8dac366..63188acd 100644 --- a/libsolidity/formal/SMTLib2Interface.h +++ b/libsolidity/formal/SMTLib2Interface.h @@ -41,7 +41,7 @@ namespace smt class SMTLib2Interface: public SolverInterface, public boost::noncopyable { public: - SMTLib2Interface(ReadCallback::Callback const& _queryCallback); + explicit SMTLib2Interface(ReadCallback::Callback const& _queryCallback); void reset() override; diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 76b0bbd5..e5bdc90f 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -163,11 +163,25 @@ bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment) bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment) { + int const expectedItems = _assignment.variableNames.size(); + solAssert(expectedItems >= 1, ""); int const stackHeight = m_stackHeight; bool success = boost::apply_visitor(*this, *_assignment.value); - solAssert(m_stackHeight >= stackHeight, "Negative value size."); - if (!checkAssignment(_assignment.variableName, m_stackHeight - stackHeight)) - success = false; + if ((m_stackHeight - stackHeight) != expectedItems) + { + m_errorReporter.declarationError( + _assignment.location, + "Variable count does not match number of values (" + + to_string(expectedItems) + + " vs. " + + to_string(m_stackHeight - stackHeight) + + ")" + ); + return false; + } + for (auto const& variableName: _assignment.variableNames) + if (!checkAssignment(variableName, 1)) + success = false; m_info.stackHeightInfo[&_assignment] = m_stackHeight; return success; } diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index db5840bc..b0dd85ca 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -54,7 +54,11 @@ struct Label { SourceLocation location; std::string name; }; struct StackAssignment { SourceLocation location; Identifier variableName; }; /// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand /// side and requires x to occupy exactly one stack slot. -struct Assignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; }; +/// +/// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy +/// a single stack slot and expects a single expression on the right hand returning +/// the same amount of items as the number of variables. +struct Assignment { SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Statement> value; }; /// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))" struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; }; struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; }; diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index d84fe999..3087ad86 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -122,6 +122,34 @@ assembly::Statement Parser::parseStatement() { case Token::LParen: return parseCall(std::move(statement)); + case Token::Comma: + { + // if a comma follows, a multiple assignment is assumed + + if (statement.type() != typeid(assembly::Identifier)) + fatalParserError("Label name / variable name must precede \",\" (multiple assignment)."); + assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); + + Assignment assignment = createWithLocation<Assignment>(identifier.location); + assignment.variableNames.emplace_back(identifier); + + do + { + expectToken(Token::Comma); + statement = parseElementaryOperation(false); + if (statement.type() != typeid(assembly::Identifier)) + fatalParserError("Variable name expected in multiple assignemnt."); + assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(statement)); + } + while (currentToken() == Token::Comma); + + expectToken(Token::Colon); + expectToken(Token::Assign); + + assignment.value.reset(new Statement(parseExpression())); + assignment.location.end = locationOf(*assignment.value).end; + return assignment; + } case Token::Colon: { if (statement.type() != typeid(assembly::Identifier)) @@ -136,7 +164,7 @@ assembly::Statement Parser::parseStatement() if (!m_julia && instructions().count(identifier.name)) fatalParserError("Cannot use instruction names for identifier names."); advance(); - assignment.variableName = identifier; + assignment.variableNames.emplace_back(identifier); assignment.value.reset(new Statement(parseExpression())); assignment.location.end = locationOf(*assignment.value).end; return assignment; diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp index 47ede91d..a5272808 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libsolidity/inlineasm/AsmPrinter.cpp @@ -116,7 +116,11 @@ string AsmPrinter::operator()(assembly::StackAssignment const& _assignment) string AsmPrinter::operator()(assembly::Assignment const& _assignment) { - return (*this)(_assignment.variableName) + " := " + boost::apply_visitor(*this, *_assignment.value); + solAssert(_assignment.variableNames.size() >= 1, ""); + string variables = (*this)(_assignment.variableNames.front()); + for (size_t i = 1; i < _assignment.variableNames.size(); ++i) + variables += ", " + (*this)(_assignment.variableNames[i]); + return variables + " := " + boost::apply_visitor(*this, *_assignment.value); } string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration) diff --git a/libsolidity/interface/ErrorReporter.h b/libsolidity/interface/ErrorReporter.h index 6f7ef51d..a87db21d 100644 --- a/libsolidity/interface/ErrorReporter.h +++ b/libsolidity/interface/ErrorReporter.h @@ -86,7 +86,7 @@ public: void fatalTypeError(SourceLocation const& _location, std::string const& _description); - void docstringParsingError(std::string const& _location); + void docstringParsingError(std::string const& _description); ErrorList const& errors() const; diff --git a/libsolidity/parsing/ParserBase.cpp b/libsolidity/parsing/ParserBase.cpp index fe95b0fe..5b83c5bd 100644 --- a/libsolidity/parsing/ParserBase.cpp +++ b/libsolidity/parsing/ParserBase.cpp @@ -104,7 +104,7 @@ void ParserBase::expectToken(Token::Value _value) void ParserBase::increaseRecursionDepth() { m_recursionDepth++; - if (m_recursionDepth >= 3000) + if (m_recursionDepth >= 2560) fatalParserError("Maximum recursion depth reached during parsing."); } diff --git a/scripts/install_deps.bat b/scripts/install_deps.bat index 512a28df..d02005cc 100644 --- a/scripts/install_deps.bat +++ b/scripts/install_deps.bat @@ -58,4 +58,4 @@ REM REM Copyright (c) 2016 solidity contributors. REM --------------------------------------------------------------------------- -cmake -P deps\install_deps.cmake +cmake -P scripts\install_deps.cmake diff --git a/scripts/install_deps.cmake b/scripts/install_deps.cmake new file mode 100644 index 00000000..d1284b9e --- /dev/null +++ b/scripts/install_deps.cmake @@ -0,0 +1,99 @@ +get_filename_component(ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../deps" ABSOLUTE) + +set(CACHE_DIR "${ROOT_DIR}/cache") +set(PACKAGES_DIR "${ROOT_DIR}/packages") + +function(download URL DST_FILE STATUS) + set(TMP_FILE "${DST_FILE}.part") + + get_filename_component(FILE_NAME ${DST_FILE} NAME) + if (NOT EXISTS ${DST_FILE}) + message("Downloading ${FILE_NAME}") + file(DOWNLOAD ${URL} ${TMP_FILE} SHOW_PROGRESS STATUS DOWNLOAD_STATUS) + list(GET DOWNLOAD_STATUS 0 STATUS_CODE) + if (STATUS_CODE EQUAL 0) + file(RENAME ${TMP_FILE} ${DST_FILE}) + else() + file(REMOVE ${TMP_FILE}) + list(GET DOWNLOAD_STATUS 1 ERROR_MSG) + + message("ERROR! Downloading '${FILE_NAME}' failed.") + message(STATUS "URL: ${URL}") + message(STATUS "Error: ${STATUS_CODE} ${ERROR_MSG}") + set(STATUS FALSE PARENT_SCOPE) + return() + endif() + else() + message("Using cached ${FILE_NAME}") + endif() + set(STATUS TRUE PARENT_SCOPE) +endfunction(download) + +function(download_and_unpack PACKAGE_URL DST_DIR) + get_filename_component(FILE_NAME ${PACKAGE_URL} NAME) + + set(DST_FILE "${CACHE_DIR}/${FILE_NAME}") + set(TMP_FILE "${DST_FILE}.part") + + file(MAKE_DIRECTORY ${CACHE_DIR}) + file(MAKE_DIRECTORY ${DST_DIR}) + + download(${PACKAGE_URL} ${DST_FILE} STATUS) + + if (STATUS) + message("Unpacking ${FILE_NAME} to ${DST_DIR}") + execute_process(COMMAND ${CMAKE_COMMAND} -E tar -xf ${DST_FILE} + WORKING_DIRECTORY ${DST_DIR}) + endif() +endfunction(download_and_unpack) + +# Packs installed package binaries and headers into an archive. +function(create_package NAME DIR) + message("Creating package ${NAME}") + file(MAKE_DIRECTORY ${PACKAGES_DIR}) + + # To create an archive without addicional top level directory + # (like package-X.Y.Z) we need to know all top level files/dirs. + # Usually it is just "win64" dir. + file(GLOB TOP_FILES RELATIVE ${DIR} "${DIR}/*") + + set(PACKAGE_FILE "${PACKAGES_DIR}/${NAME}.tar.gz") + execute_process(COMMAND ${CMAKE_COMMAND} -E + tar -czf ${PACKAGE_FILE} ${TOP_FILES} + WORKING_DIRECTORY ${DIR}) +endfunction(create_package) + +# Downloads the source code of the package and unpacks it to dedicated 'src' +# dir. Also creates 'build' and 'install' dir to be used by a build script. +function(prepare_package_source NAME VERSION URL) + set(PACKAGE_NAME "${NAME}-${VERSION}") + + set(PACKAGE_DIR "${CACHE_DIR}/${PACKAGE_NAME}") + set(SOURCE_DIR "${PACKAGE_DIR}/src") + set(BUILD_DIR "${PACKAGE_DIR}/build") + set(INSTALL_DIR "${PACKAGE_DIR}/install") + + if (NOT EXISTS ${SOURCE_DIR}) + download_and_unpack(${URL} ${PACKAGE_DIR} STATUS) + file(GLOB ORIG_SOURCE_DIR_NAME "${PACKAGE_DIR}/*") + file(RENAME ${ORIG_SOURCE_DIR_NAME} ${SOURCE_DIR}) + endif() + + file(MAKE_DIRECTORY ${BUILD_DIR}) + file(MAKE_DIRECTORY ${INSTALL_DIR}) + + # Export names and dirs to be used by a package-specific build script. + set(PACKAGE_NAME ${PACKAGE_NAME} PARENT_SCOPE) + set(SOURCE_DIR ${SOURCE_DIR} PARENT_SCOPE) + set(BUILD_DIR ${BUILD_DIR} PARENT_SCOPE) + set(INSTALL_DIR ${INSTALL_DIR} PARENT_SCOPE) +endfunction() + +set(INSTALL_DIR "${ROOT_DIR}/install") +set(SERVER "https://github.com/ethereum/cpp-dependencies/releases/download/vc140/") + +function(download_and_install PACKAGE_NAME) + download_and_unpack("${SERVER}${PACKAGE_NAME}.tar.gz" ${INSTALL_DIR}) +endfunction(download_and_install) + +download_and_install("boost-1.61") diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index ba385dee..e8d8d111 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -262,7 +262,7 @@ protected: void sendMessage(bytes const& _data, bool _isCreation, u256 const& _value = 0); void sendEther(Address const& _to, u256 const& _value); size_t currentTimestamp(); - size_t blockTimestamp(u256 number); + size_t blockTimestamp(u256 _number); /// @returns the (potentially newly created) _ith address. Address account(size_t _i); diff --git a/test/RPCSession.h b/test/RPCSession.h index 558cb99f..eae6a09c 100644 --- a/test/RPCSession.h +++ b/test/RPCSession.h @@ -40,7 +40,7 @@ class IPCSocket : public boost::noncopyable { public: - IPCSocket(std::string const& _path); + explicit IPCSocket(std::string const& _path); std::string sendRequest(std::string const& _req); ~IPCSocket() { CloseHandle(m_socket); } @@ -55,7 +55,7 @@ private: class IPCSocket: public boost::noncopyable { public: - IPCSocket(std::string const& _path); + explicit IPCSocket(std::string const& _path); std::string sendRequest(std::string const& _req); ~IPCSocket() { close(m_socket); } @@ -107,7 +107,7 @@ public: Json::Value eth_getBlockByNumber(std::string const& _blockNumber, bool _fullObjects); std::string eth_call(TransactionData const& _td, std::string const& _blockNumber); TransactionReceipt eth_getTransactionReceipt(std::string const& _transactionHash); - std::string eth_sendTransaction(TransactionData const& _transactionData); + std::string eth_sendTransaction(TransactionData const& _td); std::string eth_sendTransaction(std::string const& _transaction); std::string eth_getBalance(std::string const& _address, std::string const& _blockNumber); std::string eth_getStorageRoot(std::string const& _address, std::string const& _blockNumber); diff --git a/test/libdevcore/MiniMoustache.cpp b/test/libdevcore/Whiskers.cpp index 84149173..84149173 100644 --- a/test/libdevcore/MiniMoustache.cpp +++ b/test/libdevcore/Whiskers.cpp diff --git a/test/libjulia/Parser.cpp b/test/libjulia/Parser.cpp index 51070370..f8c1aa4d 100644 --- a/test/libjulia/Parser.cpp +++ b/test/libjulia/Parser.cpp @@ -249,6 +249,26 @@ BOOST_AUTO_TEST_CASE(recursion_depth) CHECK_ERROR(input, ParserError, "recursion"); } +BOOST_AUTO_TEST_CASE(multiple_assignment) +{ + CHECK_ERROR("{ let x:u256 function f() -> a:u256, b:u256 {} 123:u256, x := f() }", ParserError, "Label name / variable name must precede \",\" (multiple assignment)."); + CHECK_ERROR("{ let x:u256 function f() -> a:u256, b:u256 {} x, 123:u256 := f() }", ParserError, "Variable name expected in multiple assignemnt."); + + /// NOTE: Travis hiccups if not having a variable + char const* text = R"( + { + function f(a:u256) -> r1:u256, r2:u256 { + r1 := a + r2 := 7:u256 + } + let x:u256 := 9:u256 + let y:u256 := 2:u256 + x, y := f(x) + } + )"; + BOOST_CHECK(successParse(text)); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/AnalysisFramework.h b/test/libsolidity/AnalysisFramework.h index f73f06c2..172ae01b 100644 --- a/test/libsolidity/AnalysisFramework.h +++ b/test/libsolidity/AnalysisFramework.h @@ -59,8 +59,8 @@ protected: void printErrors(); - ContractDefinition const* retrieveContractByName(SourceUnit const& _source, std::string const& _name); - FunctionTypePointer retrieveFunctionBySignature( + static ContractDefinition const* retrieveContractByName(SourceUnit const& _source, std::string const& _name); + static FunctionTypePointer retrieveFunctionBySignature( ContractDefinition const& _contract, std::string const& _signature ); diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 0debc66d..da3522b4 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -412,7 +412,25 @@ BOOST_AUTO_TEST_CASE(recursion_depth) CHECK_PARSE_ERROR(input, ParserError, "recursion"); } +BOOST_AUTO_TEST_CASE(multiple_assignment) +{ + CHECK_PARSE_ERROR("{ let x function f() -> a, b {} 123, x := f() }", ParserError, "Label name / variable name must precede \",\" (multiple assignment)."); + CHECK_PARSE_ERROR("{ let x function f() -> a, b {} x, 123 := f() }", ParserError, "Variable name expected in multiple assignemnt."); + /// NOTE: Travis hiccups if not having a variable + char const* text = R"( + { + function f(a) -> r1, r2 { + r1 := a + r2 := 7 + } + let x := 9 + let y := 2 + x, y := f(x) + } + )"; + BOOST_CHECK(successParse(text)); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index bdac8278..458b64f4 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -7867,6 +7867,31 @@ BOOST_AUTO_TEST_CASE(inline_assembly_function_call) BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7))); } +BOOST_AUTO_TEST_CASE(inline_assembly_function_call_assignment) +{ + char const* sourceCode = R"( + contract C { + function f() { + assembly { + let a1, b1, c1 + function asmfun(a, b, c) -> x, y, z { + x := a + y := b + z := 7 + } + a1, b1, c1 := asmfun(1, 2, 3) + mstore(0x00, a1) + mstore(0x20, b1) + mstore(0x40, c1) + return(0, 0x60) + } + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(1), u256(2), u256(7))); +} + BOOST_AUTO_TEST_CASE(inline_assembly_function_call2) { char const* sourceCode = R"( |