Browse Source

Simple Assembly Locations test

- Also adding some helper functions to SourceLocation
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
bc71f71035
  1. 7
      libdevcore/SourceLocation.h
  2. 6
      libevmcore/Assembly.h
  3. 2
      libsolidity/Compiler.h
  4. 8
      libsolidity/CompilerContext.cpp
  5. 128
      test/Assembly.cpp

7
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;

6
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 <class T> 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(); }

2
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.

8
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;
}

128
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 <http://www.gnu.org/licenses/>.
*/
/**
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
* Unit tests for Assembly Items from evmcore/Assembly.h
*/
#include <string>
#include <iostream>
#include <boost/test/unit_test.hpp>
#include <libdevcore/Log.h>
#include <libdevcore/SourceLocation.h>
#include <libsolidity/Scanner.h>
#include <libsolidity/Parser.h>
#include <libsolidity/NameAndTypeResolver.h>
#include <libsolidity/Compiler.h>
#include <libsolidity/AST.h>
#include <libevmcore/Assembly.h>
using namespace std;
using namespace dev::eth;
namespace dev
{
namespace solidity
{
namespace test
{
namespace
{
eth::AssemblyItems compileContract(const string& _sourceCode)
{
Parser parser;
ASTPointer<SourceUnit> sourceUnit;
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode))));
NameAndTypeResolver resolver({});
resolver.registerDeclarations(*sourceUnit);
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract));
}
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract));
}
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
Compiler compiler;
compiler.compileContract(*contract, map<ContractDefinition const*, bytes const*>{});
return compiler.getRuntimeContext().getAssembly().getItems();
}
BOOST_FAIL("No contract found in source.");
return AssemblyItems();
}
void checkAssemblyLocations(AssemblyItems const& _items, std::vector<SourceLocation> _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<std::string const> n = make_shared<std::string>("source");
AssemblyItems items = compileContract(sourceCode);
std::vector<SourceLocation> 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
Loading…
Cancel
Save