From bc71f71035e0a35ca9ea2ed7a5e10e17b7f66b4c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 24 Feb 2015 17:08:27 +0100 Subject: [PATCH] Simple Assembly Locations test - Also adding some helper functions to SourceLocation --- libdevcore/SourceLocation.h | 7 ++ libevmcore/Assembly.h | 6 +- libsolidity/Compiler.h | 2 + libsolidity/CompilerContext.cpp | 8 +- test/Assembly.cpp | 128 ++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 test/Assembly.cpp diff --git a/libdevcore/SourceLocation.h b/libdevcore/SourceLocation.h index 75919061b..7b92ddc92 100644 --- a/libdevcore/SourceLocation.h +++ b/libdevcore/SourceLocation.h @@ -39,6 +39,13 @@ struct SourceLocation start(_start), end(_end), sourceName(_sourceName) { } SourceLocation(): start(-1), end(-1) { } + SourceLocation(SourceLocation const& other): + start(other.start), end(other.end), sourceName(other.sourceName) {} + SourceLocation& operator=(SourceLocation const& other) { start = other.start; end = other.end; sourceName = other.sourceName; return *this;} + + bool operator==(SourceLocation const& other) const { return start == other.start && end == other.end;} + bool operator!=(SourceLocation const& other) const { return !(*this == other); } + bool isEmpty() const { return start == -1 && end == -1; } int start; diff --git a/libevmcore/Assembly.h b/libevmcore/Assembly.h index 68235777f..cb247d161 100644 --- a/libevmcore/Assembly.h +++ b/libevmcore/Assembly.h @@ -59,6 +59,7 @@ public: bool match(AssemblyItem const& _i) const { return _i.m_type == UndefinedItem || (m_type == _i.m_type && (m_type != Operation || m_data == _i.m_data)); } void setLocation(dev::SourceLocation const& _location) { m_location = _location;} + dev::SourceLocation const& getLocation() const { return m_location; } private: AssemblyItemType m_type; @@ -88,8 +89,8 @@ public: void append(Assembly const& _a); void append(Assembly const& _a, int _deposit); AssemblyItem const& append(AssemblyItem const& _i, SourceLocation const& _location = SourceLocation()); - AssemblyItem const& append(std::string const& _data) { return append(newPushString(_data)); } - AssemblyItem const& append(bytes const& _data) { return append(newData(_data)); } + AssemblyItem const& append(std::string const& _data, SourceLocation const& _location = SourceLocation()) { return append(newPushString(_data), _location); } + AssemblyItem const& append(bytes const& _data, SourceLocation const& _location = SourceLocation()) { return append(newData(_data), _location); } AssemblyItem appendSubSize(Assembly const& _a) { auto ret = newSub(_a); append(newPushSubSize(ret.data())); return ret; } /// Pushes the final size of the current assembly itself. Use this when the code is modified /// after compilation and CODESIZE is not an option. @@ -102,6 +103,7 @@ public: template Assembly& operator<<(T const& _d) { append(_d); return *this; } + AssemblyItems const& getItems() const { return m_items; } AssemblyItem const& back() const { return m_items.back(); } std::string backString() const { return m_items.size() && m_items.back().m_type == PushString ? m_strings.at((h256)m_items.back().m_data) : std::string(); } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 28ab34adb..a35a18e1d 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -41,6 +41,8 @@ public: bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); } bytes getRuntimeBytecode() { return m_runtimeContext.getAssembledBytecode(m_optimize);} void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); } + CompilerContext const& getContext() const { return m_context; } + CompilerContext const& getRuntimeContext() const { return m_runtimeContext; } private: /// Registers the non-function objects inside the contract with the context. diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index 67a367240..5fd91e435 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -176,28 +176,28 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node) CompilerContext& CompilerContext::operator<<(eth::AssemblyItem _item) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); - m_asm.append(_item); + m_asm.append(_item, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(eth::Instruction _instruction) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); - m_asm.append(_instruction); + m_asm.append(_instruction, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(u256 const& _value) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); - m_asm.append(_value); + m_asm.append(_value, m_visitedNodes.top()->getLocation()); return *this; } CompilerContext& CompilerContext::operator<<(bytes const& _data) { solAssert(m_visitedNodes.size() > 0, "No node on the visited stack"); - m_asm.append(_data); + m_asm.append(_data, m_visitedNodes.top()->getLocation()); return *this; } diff --git a/test/Assembly.cpp b/test/Assembly.cpp new file mode 100644 index 000000000..0ccc174cb --- /dev/null +++ b/test/Assembly.cpp @@ -0,0 +1,128 @@ +/* + 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 . +*/ +/** + * @author Lefteris Karapetsas + * @date 2015 + * Unit tests for Assembly Items from evmcore/Assembly.h + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace dev::eth; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +namespace +{ + +eth::AssemblyItems compileContract(const string& _sourceCode) +{ + Parser parser; + ASTPointer sourceUnit; + BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared(CharStream(_sourceCode)))); + NameAndTypeResolver resolver({}); + resolver.registerDeclarations(*sourceUnit); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); + } + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract)); + } + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + Compiler compiler; + compiler.compileContract(*contract, map{}); + + return compiler.getRuntimeContext().getAssembly().getItems(); + } + BOOST_FAIL("No contract found in source."); + return AssemblyItems(); +} + +void checkAssemblyLocations(AssemblyItems const& _items, std::vector _locations) +{ + size_t i = 0; + BOOST_CHECK_EQUAL(_items.size(), _locations.size()); + for (auto const& it: _items) + { + BOOST_CHECK_MESSAGE(it.getLocation() == _locations[i], std::string("Location mismatch for item" + i)); + ++ i; + } + +} + +} // end anonymous namespace + +BOOST_AUTO_TEST_SUITE(Assembly) + +BOOST_AUTO_TEST_CASE(location_test) +{ + char const* sourceCode = "contract test {\n" + " function f() returns (uint256 a)\n" + " {\n" + " return 16;\n" + " }\n" + "}\n"; + std::shared_ptr n = make_shared("source"); + AssemblyItems items = compileContract(sourceCode); + std::vector locations { + SourceLocation(0, 77, n), SourceLocation(0, 77, n), + SourceLocation(0, 77, n), SourceLocation(0, 77, n), + SourceLocation(0, 77, n), SourceLocation(0, 77, n), + SourceLocation(0, 77, n), SourceLocation(0, 77, n), + SourceLocation(), SourceLocation(), + SourceLocation(0, 77, n), SourceLocation(0, 77, n), + SourceLocation(), SourceLocation(), SourceLocation(), + SourceLocation(0, 77, n), SourceLocation(0, 77, n), + SourceLocation(0, 77, n), SourceLocation(0, 77, n), + SourceLocation(0, 77, n), SourceLocation(0, 77, n), + SourceLocation(0, 77, n), + SourceLocation(18, 75, n), SourceLocation(18, 75, n), + SourceLocation(61, 70, n), SourceLocation(61, 70, n), SourceLocation(61, 70, n), + SourceLocation(), SourceLocation(), + SourceLocation(61, 70, n), SourceLocation(61, 70, n), SourceLocation(61, 70, n) + }; + checkAssemblyLocations(items, locations); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces +