Browse Source
Conflicts: libethereum/Executive.cpp libethereum/Executive.h libethereum/State.cpp libevm/VM.cpp libevm/VM.h libevm/VMFace.h test/createRandomTest.cpp test/vm.cpp windows/LibEthereum.vcxproj.filterscl-refactor
Paweł Bylica
10 years ago
91 changed files with 5254 additions and 1613 deletions
@ -1,28 +0,0 @@ |
|||||
#include <libevm/VM.h> |
|
||||
|
|
||||
#if ETH_EVMJIT |
|
||||
#include<evmjit/libevmjit-cpp/JitVM.h> |
|
||||
#endif |
|
||||
|
|
||||
#include "VMFactory.h" |
|
||||
|
|
||||
namespace dev |
|
||||
{ |
|
||||
namespace eth |
|
||||
{ |
|
||||
|
|
||||
std::unique_ptr<VMFace> VMFactory::create(VMFactory::Kind _kind, u256 _gas) |
|
||||
{ |
|
||||
#if ETH_EVMJIT |
|
||||
auto vm = _kind == Kind::JIT ? static_cast<VMFace*>(new JitVM) |
|
||||
: static_cast<VMFace*>(new VM); |
|
||||
#else |
|
||||
VMFace* vm = new VM; |
|
||||
#endif |
|
||||
|
|
||||
vm->reset(_gas); |
|
||||
return std::unique_ptr<VMFace>(vm); |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
} |
|
@ -1,28 +0,0 @@ |
|||||
#pragma once |
|
||||
|
|
||||
#include <libevm/VMFace.h> |
|
||||
|
|
||||
namespace dev |
|
||||
{ |
|
||||
namespace eth |
|
||||
{ |
|
||||
|
|
||||
/**
|
|
||||
*/ |
|
||||
|
|
||||
class VMFactory |
|
||||
{ |
|
||||
public: |
|
||||
enum Kind: bool { |
|
||||
Interpreter, |
|
||||
#if ETH_EVMJIT |
|
||||
JIT |
|
||||
#endif |
|
||||
}; |
|
||||
|
|
||||
static std::unique_ptr<VMFace> create(Kind, u256 _gas = 0); |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
} |
|
||||
} |
|
@ -0,0 +1,45 @@ |
|||||
|
/*
|
||||
|
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/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include "VMFactory.h" |
||||
|
#include "VM.h" |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace eth |
||||
|
{ |
||||
|
namespace |
||||
|
{ |
||||
|
VMKind g_kind = VMKind::Interpreter; |
||||
|
} |
||||
|
|
||||
|
void VMFactory::setKind(VMKind _kind) |
||||
|
{ |
||||
|
g_kind = _kind; |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<VMFace> VMFactory::create(u256 _gas) |
||||
|
{ |
||||
|
asserts(g_kind == VMKind::Interpreter && "Only interpreter supported for now"); |
||||
|
return std::unique_ptr<VMFace>(new VM(_gas)); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,187 @@ |
|||||
|
/*
|
||||
|
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/>.
|
||||
|
*/ |
||||
|
/** @file Network.cpp
|
||||
|
* @author Alex Leverington <nessence@gmail.com> |
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @author Eric Lombrozo <elombrozo@gmail.com> (Windows version of getInterfaceAddresses()) |
||||
|
* @date 2014 |
||||
|
*/ |
||||
|
|
||||
|
#include <sys/types.h> |
||||
|
#ifndef _WIN32 |
||||
|
#include <ifaddrs.h> |
||||
|
#endif |
||||
|
|
||||
|
#include <boost/algorithm/string.hpp> |
||||
|
#include <libdevcore/Common.h> |
||||
|
#include <libdevcore/CommonIO.h> |
||||
|
#include <libethcore/Exceptions.h> |
||||
|
#include "Common.h" |
||||
|
#include "UPnP.h" |
||||
|
#include "Network.h" |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace dev; |
||||
|
using namespace dev::p2p; |
||||
|
|
||||
|
std::vector<bi::address> Network::getInterfaceAddresses() |
||||
|
{ |
||||
|
std::vector<bi::address> addresses; |
||||
|
|
||||
|
#ifdef _WIN32 |
||||
|
WSAData wsaData; |
||||
|
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) |
||||
|
BOOST_THROW_EXCEPTION(NoNetworking()); |
||||
|
|
||||
|
char ac[80]; |
||||
|
if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) |
||||
|
{ |
||||
|
clog(NetWarn) << "Error " << WSAGetLastError() << " when getting local host name."; |
||||
|
WSACleanup(); |
||||
|
BOOST_THROW_EXCEPTION(NoNetworking()); |
||||
|
} |
||||
|
|
||||
|
struct hostent* phe = gethostbyname(ac); |
||||
|
if (phe == 0) |
||||
|
{ |
||||
|
clog(NetWarn) << "Bad host lookup."; |
||||
|
WSACleanup(); |
||||
|
BOOST_THROW_EXCEPTION(NoNetworking()); |
||||
|
} |
||||
|
|
||||
|
for (int i = 0; phe->h_addr_list[i] != 0; ++i) |
||||
|
{ |
||||
|
struct in_addr addr; |
||||
|
memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr)); |
||||
|
char *addrStr = inet_ntoa(addr); |
||||
|
bi::address address(bi::address::from_string(addrStr)); |
||||
|
if (!isLocalHostAddress(address)) |
||||
|
addresses.push_back(address.to_v4()); |
||||
|
} |
||||
|
|
||||
|
WSACleanup(); |
||||
|
#else |
||||
|
ifaddrs* ifaddr; |
||||
|
if (getifaddrs(&ifaddr) == -1) |
||||
|
BOOST_THROW_EXCEPTION(NoNetworking()); |
||||
|
|
||||
|
for (auto ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) |
||||
|
{ |
||||
|
if (!ifa->ifa_addr || string(ifa->ifa_name) == "lo0") |
||||
|
continue; |
||||
|
|
||||
|
if (ifa->ifa_addr->sa_family == AF_INET) |
||||
|
{ |
||||
|
in_addr addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; |
||||
|
boost::asio::ip::address_v4 address(boost::asio::detail::socket_ops::network_to_host_long(addr.s_addr)); |
||||
|
if (!isLocalHostAddress(address)) |
||||
|
addresses.push_back(address); |
||||
|
} |
||||
|
else if (ifa->ifa_addr->sa_family == AF_INET6) |
||||
|
{ |
||||
|
sockaddr_in6* sockaddr = ((struct sockaddr_in6 *)ifa->ifa_addr); |
||||
|
in6_addr addr = sockaddr->sin6_addr; |
||||
|
boost::asio::ip::address_v6::bytes_type bytes; |
||||
|
memcpy(&bytes[0], addr.s6_addr, 16); |
||||
|
boost::asio::ip::address_v6 address(bytes, sockaddr->sin6_scope_id); |
||||
|
if (!isLocalHostAddress(address)) |
||||
|
addresses.push_back(address); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (ifaddr!=NULL) |
||||
|
freeifaddrs(ifaddr); |
||||
|
|
||||
|
#endif |
||||
|
|
||||
|
return std::move(addresses); |
||||
|
} |
||||
|
|
||||
|
int Network::listen4(bi::tcp::acceptor& _acceptor, unsigned short _listenPort) |
||||
|
{ |
||||
|
int retport = -1; |
||||
|
for (unsigned i = 0; i < 2; ++i) |
||||
|
{ |
||||
|
// try to connect w/listenPort, else attempt net-allocated port
|
||||
|
bi::tcp::endpoint endpoint(bi::tcp::v4(), i ? 0 : _listenPort); |
||||
|
try |
||||
|
{ |
||||
|
_acceptor.open(endpoint.protocol()); |
||||
|
_acceptor.set_option(ba::socket_base::reuse_address(true)); |
||||
|
_acceptor.bind(endpoint); |
||||
|
_acceptor.listen(); |
||||
|
retport = _acceptor.local_endpoint().port(); |
||||
|
break; |
||||
|
} |
||||
|
catch (...) |
||||
|
{ |
||||
|
if (i) |
||||
|
{ |
||||
|
// both attempts failed
|
||||
|
cwarn << "Couldn't start accepting connections on host. Something very wrong with network?\n" << boost::current_exception_diagnostic_information(); |
||||
|
} |
||||
|
|
||||
|
// first attempt failed
|
||||
|
_acceptor.close(); |
||||
|
continue; |
||||
|
} |
||||
|
} |
||||
|
return retport; |
||||
|
} |
||||
|
|
||||
|
bi::tcp::endpoint Network::traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr) |
||||
|
{ |
||||
|
asserts(_listenPort != 0); |
||||
|
|
||||
|
UPnP* upnp = nullptr; |
||||
|
try |
||||
|
{ |
||||
|
upnp = new UPnP; |
||||
|
} |
||||
|
// let m_upnp continue as null - we handle it properly.
|
||||
|
catch (NoUPnPDevice) {} |
||||
|
|
||||
|
bi::tcp::endpoint upnpep; |
||||
|
if (upnp && upnp->isValid()) |
||||
|
{ |
||||
|
bi::address paddr; |
||||
|
int extPort = 0; |
||||
|
for (auto const& addr: _ifAddresses) |
||||
|
if (addr.is_v4() && isPrivateAddress(addr) && (extPort = upnp->addRedirect(addr.to_string().c_str(), _listenPort))) |
||||
|
{ |
||||
|
paddr = addr; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
auto eip = upnp->externalIP(); |
||||
|
bi::address eipaddr(bi::address::from_string(eip)); |
||||
|
if (extPort && eip != string("0.0.0.0") && !isPrivateAddress(eipaddr)) |
||||
|
{ |
||||
|
clog(NetNote) << "Punched through NAT and mapped local port" << _listenPort << "onto external port" << extPort << "."; |
||||
|
clog(NetNote) << "External addr:" << eip; |
||||
|
o_upnpifaddr = paddr; |
||||
|
upnpep = bi::tcp::endpoint(eipaddr, (unsigned short)extPort); |
||||
|
} |
||||
|
else |
||||
|
clog(NetWarn) << "Couldn't punch through NAT (or no NAT in place)."; |
||||
|
|
||||
|
if (upnp) |
||||
|
delete upnp; |
||||
|
} |
||||
|
|
||||
|
return upnpep; |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
/*
|
||||
|
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/>.
|
||||
|
*/ |
||||
|
/** @file Network.h
|
||||
|
* @author Alex Leverington <nessence@gmail.com> |
||||
|
* @author Gav Wood <i@gavwood.com> |
||||
|
* @date 2014 |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <vector> |
||||
|
namespace ba = boost::asio; |
||||
|
namespace bi = ba::ip; |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
|
||||
|
namespace p2p |
||||
|
{ |
||||
|
|
||||
|
struct NetworkPreferences |
||||
|
{ |
||||
|
NetworkPreferences(unsigned short p = 30303, std::string i = std::string(), bool u = true, bool l = false): listenPort(p), publicIP(i), upnp(u), localNetworking(l) {} |
||||
|
|
||||
|
unsigned short listenPort = 30303; |
||||
|
std::string publicIP; |
||||
|
bool upnp = true; |
||||
|
bool localNetworking = false; |
||||
|
}; |
||||
|
|
||||
|
/**
|
||||
|
* @brief Network Class |
||||
|
* Static network operations and interface(s). |
||||
|
*/ |
||||
|
class Network |
||||
|
{ |
||||
|
public: |
||||
|
/// @returns public and private interface addresses
|
||||
|
static std::vector<bi::address> getInterfaceAddresses(); |
||||
|
|
||||
|
/// Try to bind and listen on _listenPort, else attempt net-allocated port.
|
||||
|
static int listen4(bi::tcp::acceptor& _acceptor, unsigned short _listenPort); |
||||
|
|
||||
|
/// Return public endpoint of upnp interface. If successful o_upnpifaddr will be a private interface address and endpoint will contain public address and port.
|
||||
|
static bi::tcp::endpoint traverseNAT(std::vector<bi::address> const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr); |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,493 @@ |
|||||
|
/*
|
||||
|
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 Christian <c@ethdev.com> |
||||
|
* @date 2014 |
||||
|
* Implementation of the accept functions of AST nodes, included by AST.cpp to not clutter that |
||||
|
* file with these mechanical implementations. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <libsolidity/AST.h> |
||||
|
#include <libsolidity/ASTVisitor.h> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace solidity |
||||
|
{ |
||||
|
|
||||
|
void SourceUnit::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
listAccept(m_nodes, _visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void SourceUnit::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
listAccept(m_nodes, _visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ImportDirective::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ImportDirective::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ContractDefinition::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
listAccept(m_definedStructs, _visitor); |
||||
|
listAccept(m_stateVariables, _visitor); |
||||
|
listAccept(m_definedFunctions, _visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ContractDefinition::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
listAccept(m_definedStructs, _visitor); |
||||
|
listAccept(m_stateVariables, _visitor); |
||||
|
listAccept(m_definedFunctions, _visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void StructDefinition::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
listAccept(m_members, _visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void StructDefinition::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
listAccept(m_members, _visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void StructDefinition::checkValidityOfMembers() const |
||||
|
{ |
||||
|
checkMemberTypes(); |
||||
|
checkRecursion(); |
||||
|
} |
||||
|
|
||||
|
void ParameterList::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
listAccept(m_parameters, _visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ParameterList::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
listAccept(m_parameters, _visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void FunctionDefinition::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_parameters->accept(_visitor); |
||||
|
if (m_returnParameters) |
||||
|
m_returnParameters->accept(_visitor); |
||||
|
m_body->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void FunctionDefinition::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_parameters->accept(_visitor); |
||||
|
if (m_returnParameters) |
||||
|
m_returnParameters->accept(_visitor); |
||||
|
m_body->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void VariableDeclaration::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
if (m_typeName) |
||||
|
m_typeName->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void VariableDeclaration::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
if (m_typeName) |
||||
|
m_typeName->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void TypeName::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void TypeName::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ElementaryTypeName::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ElementaryTypeName::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void UserDefinedTypeName::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void UserDefinedTypeName::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Mapping::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_keyType->accept(_visitor); |
||||
|
m_valueType->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Mapping::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_keyType->accept(_visitor); |
||||
|
m_valueType->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Block::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
listAccept(m_statements, _visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Block::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
listAccept(m_statements, _visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void IfStatement::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_condition->accept(_visitor); |
||||
|
m_trueBody->accept(_visitor); |
||||
|
if (m_falseBody) |
||||
|
m_falseBody->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void IfStatement::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_condition->accept(_visitor); |
||||
|
m_trueBody->accept(_visitor); |
||||
|
if (m_falseBody) |
||||
|
m_falseBody->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void WhileStatement::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_condition->accept(_visitor); |
||||
|
m_body->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void WhileStatement::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_condition->accept(_visitor); |
||||
|
m_body->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Continue::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Continue::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Break::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Break::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Return::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
if (m_expression) |
||||
|
m_expression->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Return::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
if (m_expression) |
||||
|
m_expression->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ExpressionStatement::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
if (m_expression) |
||||
|
m_expression->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ExpressionStatement::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
if (m_expression) |
||||
|
m_expression->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void VariableDefinition::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_variable->accept(_visitor); |
||||
|
if (m_value) |
||||
|
m_value->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void VariableDefinition::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_variable->accept(_visitor); |
||||
|
if (m_value) |
||||
|
m_value->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Assignment::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_leftHandSide->accept(_visitor); |
||||
|
m_rightHandSide->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Assignment::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_leftHandSide->accept(_visitor); |
||||
|
m_rightHandSide->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void UnaryOperation::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
m_subExpression->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void UnaryOperation::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
m_subExpression->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void BinaryOperation::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_left->accept(_visitor); |
||||
|
m_right->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void BinaryOperation::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_left->accept(_visitor); |
||||
|
m_right->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void FunctionCall::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_expression->accept(_visitor); |
||||
|
listAccept(m_arguments, _visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void FunctionCall::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_expression->accept(_visitor); |
||||
|
listAccept(m_arguments, _visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void MemberAccess::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
m_expression->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void MemberAccess::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
m_expression->accept(_visitor); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void IndexAccess::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_base->accept(_visitor); |
||||
|
m_index->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void IndexAccess::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
if (_visitor.visit(*this)) |
||||
|
{ |
||||
|
m_base->accept(_visitor); |
||||
|
m_index->accept(_visitor); |
||||
|
} |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Identifier::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Identifier::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ElementaryTypeNameExpression::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void ElementaryTypeNameExpression::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Literal::accept(ASTVisitor& _visitor) |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
void Literal::accept(ASTConstVisitor& _visitor) const |
||||
|
{ |
||||
|
_visitor.visit(*this); |
||||
|
_visitor.endVisit(*this); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
/*
|
||||
|
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 Christian <c@ethdev.com> |
||||
|
* @date 2014 |
||||
|
* Routines used by both the compiler and the expression compiler. |
||||
|
*/ |
||||
|
|
||||
|
#include <libsolidity/CompilerUtils.h> |
||||
|
#include <libsolidity/AST.h> |
||||
|
#include <libevmcore/Instruction.h> |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace solidity |
||||
|
{ |
||||
|
|
||||
|
void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) |
||||
|
{ |
||||
|
unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(_variable)); |
||||
|
unsigned const size = _variable.getType()->getSizeOnStack(); |
||||
|
// move variable starting from its top end in the stack
|
||||
|
if (stackPosition - size + 1 > 16) |
||||
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_variable.getLocation()) |
||||
|
<< errinfo_comment("Stack too deep.")); |
||||
|
for (unsigned i = 0; i < size; ++i) |
||||
|
m_context << eth::swapInstruction(stackPosition - size + 1) << eth::Instruction::POP; |
||||
|
} |
||||
|
|
||||
|
void CompilerUtils::copyToStackTop(unsigned _stackDepth, Type const& _type) |
||||
|
{ |
||||
|
if (_stackDepth > 16) |
||||
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Stack too deep.")); |
||||
|
unsigned const size = _type.getSizeOnStack(); |
||||
|
for (unsigned i = 0; i < size; ++i) |
||||
|
m_context << eth::dupInstruction(_stackDepth); |
||||
|
} |
||||
|
|
||||
|
void CompilerUtils::popStackElement(Type const& _type) |
||||
|
{ |
||||
|
unsigned const size = _type.getSizeOnStack(); |
||||
|
for (unsigned i = 0; i < size; ++i) |
||||
|
m_context << eth::Instruction::POP; |
||||
|
} |
||||
|
|
||||
|
unsigned CompilerUtils::getSizeOnStack(vector<shared_ptr<Type const>> const& _variableTypes) |
||||
|
{ |
||||
|
unsigned size = 0; |
||||
|
for (shared_ptr<Type const> const& type: _variableTypes) |
||||
|
size += type->getSizeOnStack(); |
||||
|
return size; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
/*
|
||||
|
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 Christian <c@ethdev.com> |
||||
|
* @date 2014 |
||||
|
* Routines used by both the compiler and the expression compiler. |
||||
|
*/ |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <libsolidity/CompilerContext.h> |
||||
|
#include <libsolidity/ASTForward.h> |
||||
|
|
||||
|
namespace dev { |
||||
|
namespace solidity { |
||||
|
|
||||
|
class Type; // forward
|
||||
|
|
||||
|
class CompilerUtils |
||||
|
{ |
||||
|
public: |
||||
|
CompilerUtils(CompilerContext& _context): m_context(_context) {} |
||||
|
|
||||
|
/// Moves the value that is at the top of the stack to a stack variable.
|
||||
|
void moveToStackVariable(VariableDeclaration const& _variable); |
||||
|
/// Copies a variable of type @a _type from a stack depth of @a _stackDepth to the top of the stack.
|
||||
|
void copyToStackTop(unsigned _stackDepth, Type const& _type); |
||||
|
/// Removes the current value from the top of the stack.
|
||||
|
void popStackElement(Type const& _type); |
||||
|
|
||||
|
template <class T> |
||||
|
static unsigned getSizeOnStack(std::vector<T> const& _variables); |
||||
|
static unsigned getSizeOnStack(std::vector<std::shared_ptr<Type const>> const& _variableTypes); |
||||
|
|
||||
|
private: |
||||
|
CompilerContext& m_context; |
||||
|
}; |
||||
|
|
||||
|
template <class T> |
||||
|
unsigned CompilerUtils::getSizeOnStack(std::vector<T> const& _variables) |
||||
|
{ |
||||
|
unsigned size = 0; |
||||
|
for (T const& variable: _variables) |
||||
|
size += variable->getType()->getSizeOnStack(); |
||||
|
return size; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,368 @@ |
|||||
|
/*
|
||||
|
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 <lefteris@ethdev.com> |
||||
|
* @date 2014 |
||||
|
* Solidity command line interface. |
||||
|
*/ |
||||
|
#include "CommandLineInterface.h" |
||||
|
|
||||
|
#include <string> |
||||
|
#include <iostream> |
||||
|
#include <fstream> |
||||
|
|
||||
|
#include <boost/filesystem.hpp> |
||||
|
|
||||
|
#include "BuildInfo.h" |
||||
|
#include <libdevcore/Common.h> |
||||
|
#include <libdevcore/CommonData.h> |
||||
|
#include <libdevcore/CommonIO.h> |
||||
|
#include <libevmcore/Instruction.h> |
||||
|
#include <libsolidity/Scanner.h> |
||||
|
#include <libsolidity/Parser.h> |
||||
|
#include <libsolidity/ASTPrinter.h> |
||||
|
#include <libsolidity/NameAndTypeResolver.h> |
||||
|
#include <libsolidity/Exceptions.h> |
||||
|
#include <libsolidity/CompilerStack.h> |
||||
|
#include <libsolidity/SourceReferenceFormatter.h> |
||||
|
|
||||
|
using namespace std; |
||||
|
namespace po = boost::program_options; |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace solidity |
||||
|
{ |
||||
|
|
||||
|
static void version() |
||||
|
{ |
||||
|
cout << "solc, the solidity complier commandline interface " << dev::Version << endl |
||||
|
<< " by Christian <c@ethdev.com> and Lefteris <lefteris@ethdev.com>, (c) 2014." << endl |
||||
|
<< "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; |
||||
|
exit(0); |
||||
|
} |
||||
|
|
||||
|
static inline bool argToStdout(po::variables_map const& _args, const char* _name) |
||||
|
{ |
||||
|
return _args.count(_name) && _args[_name].as<OutputType>() != OutputType::FILE; |
||||
|
} |
||||
|
|
||||
|
static bool needStdout(po::variables_map const& _args) |
||||
|
{ |
||||
|
return argToStdout(_args, "abi") || argToStdout(_args, "natspec-user") || argToStdout(_args, "natspec-dev") || |
||||
|
argToStdout(_args, "asm") || argToStdout(_args, "opcodes") || argToStdout(_args, "binary"); |
||||
|
} |
||||
|
|
||||
|
static inline bool outputToFile(OutputType type) |
||||
|
{ |
||||
|
return type == OutputType::FILE || type == OutputType::BOTH; |
||||
|
} |
||||
|
|
||||
|
static inline bool outputToStdout(OutputType type) |
||||
|
{ |
||||
|
return type == OutputType::STDOUT || type == OutputType::BOTH; |
||||
|
} |
||||
|
|
||||
|
static std::istream& operator>>(std::istream& _in, OutputType& io_output) |
||||
|
{ |
||||
|
std::string token; |
||||
|
_in >> token; |
||||
|
if (token == "stdout") |
||||
|
io_output = OutputType::STDOUT; |
||||
|
else if (token == "file") |
||||
|
io_output = OutputType::FILE; |
||||
|
else if (token == "both") |
||||
|
io_output = OutputType::BOTH; |
||||
|
else |
||||
|
throw boost::program_options::invalid_option_value(token); |
||||
|
return _in; |
||||
|
} |
||||
|
|
||||
|
void CommandLineInterface::handleBinary(string const& _contract) |
||||
|
{ |
||||
|
auto choice = m_args["binary"].as<OutputType>(); |
||||
|
if (outputToStdout(choice)) |
||||
|
{ |
||||
|
cout << "Binary: " << endl; |
||||
|
cout << toHex(m_compiler.getBytecode(_contract)) << endl; |
||||
|
} |
||||
|
|
||||
|
if (outputToFile(choice)) |
||||
|
{ |
||||
|
ofstream outFile(_contract + ".binary"); |
||||
|
outFile << toHex(m_compiler.getBytecode(_contract)); |
||||
|
outFile.close(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void CommandLineInterface::handleOpcode(string const& _contract) |
||||
|
{ |
||||
|
// TODO: Figure out why the wrong operator << (from boost) is used here
|
||||
|
auto choice = m_args["opcode"].as<OutputType>(); |
||||
|
if (outputToStdout(choice)) |
||||
|
{ |
||||
|
cout << "Opcodes: " << endl; |
||||
|
dev::operator<<(cout, m_compiler.getBytecode(_contract)); |
||||
|
cout << endl; |
||||
|
} |
||||
|
|
||||
|
if (outputToFile(choice)) |
||||
|
{ |
||||
|
ofstream outFile(_contract + ".opcode"); |
||||
|
dev::operator<<(outFile, m_compiler.getBytecode(_contract)); |
||||
|
outFile.close(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void CommandLineInterface::handleBytecode(string const& _contract) |
||||
|
{ |
||||
|
if (m_args.count("opcodes")) |
||||
|
handleOpcode(_contract); |
||||
|
if (m_args.count("binary")) |
||||
|
handleBinary(_contract); |
||||
|
} |
||||
|
|
||||
|
void CommandLineInterface::handleJson(DocumentationType _type, |
||||
|
string const& _contract) |
||||
|
{ |
||||
|
std::string argName; |
||||
|
std::string suffix; |
||||
|
std::string title; |
||||
|
switch(_type) |
||||
|
{ |
||||
|
case DocumentationType::ABI_INTERFACE: |
||||
|
argName = "abi"; |
||||
|
suffix = ".abi"; |
||||
|
title = "Contract ABI"; |
||||
|
break; |
||||
|
case DocumentationType::NATSPEC_USER: |
||||
|
argName = "natspec-user"; |
||||
|
suffix = ".docuser"; |
||||
|
title = "User Documentation"; |
||||
|
break; |
||||
|
case DocumentationType::NATSPEC_DEV: |
||||
|
argName = "natspec-dev"; |
||||
|
suffix = ".docdev"; |
||||
|
title = "Developer Documentation"; |
||||
|
break; |
||||
|
default: |
||||
|
// should never happen
|
||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown documentation _type")); |
||||
|
} |
||||
|
|
||||
|
if (m_args.count(argName)) |
||||
|
{ |
||||
|
auto choice = m_args[argName].as<OutputType>(); |
||||
|
if (outputToStdout(choice)) |
||||
|
{ |
||||
|
cout << title << endl; |
||||
|
cout << m_compiler.getJsonDocumentation(_contract, _type); |
||||
|
} |
||||
|
|
||||
|
if (outputToFile(choice)) |
||||
|
{ |
||||
|
ofstream outFile(_contract + suffix); |
||||
|
outFile << m_compiler.getJsonDocumentation(_contract, _type); |
||||
|
outFile.close(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool CommandLineInterface::parseArguments(int argc, char** argv) |
||||
|
{ |
||||
|
#define OUTPUT_TYPE_STR "Legal values:\n" \ |
||||
|
"\tstdout: Print it to standard output\n" \ |
||||
|
"\tfile: Print it to a file with same name\n" \ |
||||
|
"\tboth: Print both to a file and the stdout\n" |
||||
|
// Declare the supported options.
|
||||
|
po::options_description desc("Allowed options"); |
||||
|
desc.add_options() |
||||
|
("help", "Show help message and exit") |
||||
|
("version", "Show version and exit") |
||||
|
("optimize", po::value<bool>()->default_value(false), "Optimize bytecode for size") |
||||
|
("input-file", po::value<vector<string>>(), "input file") |
||||
|
("ast", po::value<OutputType>(), |
||||
|
"Request to output the AST of the contract. " OUTPUT_TYPE_STR) |
||||
|
("asm", po::value<OutputType>(), |
||||
|
"Request to output the EVM assembly of the contract. " OUTPUT_TYPE_STR) |
||||
|
("opcodes", po::value<OutputType>(), |
||||
|
"Request to output the Opcodes of the contract. " OUTPUT_TYPE_STR) |
||||
|
("binary", po::value<OutputType>(), |
||||
|
"Request to output the contract in binary (hexadecimal). " OUTPUT_TYPE_STR) |
||||
|
("abi", po::value<OutputType>(), |
||||
|
"Request to output the contract's ABI interface. " OUTPUT_TYPE_STR) |
||||
|
("natspec-user", po::value<OutputType>(), |
||||
|
"Request to output the contract's Natspec user documentation. " OUTPUT_TYPE_STR) |
||||
|
("natspec-dev", po::value<OutputType>(), |
||||
|
"Request to output the contract's Natspec developer documentation. " OUTPUT_TYPE_STR); |
||||
|
#undef OUTPUT_TYPE_STR |
||||
|
|
||||
|
// All positional options should be interpreted as input files
|
||||
|
po::positional_options_description p; |
||||
|
p.add("input-file", -1); |
||||
|
|
||||
|
// parse the compiler arguments
|
||||
|
try |
||||
|
{ |
||||
|
po::store(po::command_line_parser(argc, argv).options(desc).positional(p).allow_unregistered().run(), m_args); |
||||
|
} |
||||
|
catch (po::error const& exception) |
||||
|
{ |
||||
|
cout << exception.what() << endl; |
||||
|
return false; |
||||
|
} |
||||
|
po::notify(m_args); |
||||
|
|
||||
|
if (m_args.count("help")) |
||||
|
{ |
||||
|
cout << desc; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (m_args.count("version")) |
||||
|
{ |
||||
|
version(); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool CommandLineInterface::processInput() |
||||
|
{ |
||||
|
if (!m_args.count("input-file")) |
||||
|
{ |
||||
|
string s; |
||||
|
while (!cin.eof()) |
||||
|
{ |
||||
|
getline(cin, s); |
||||
|
m_sourceCodes["<stdin>"].append(s); |
||||
|
} |
||||
|
} |
||||
|
else |
||||
|
for (string const& infile: m_args["input-file"].as<vector<string>>()) |
||||
|
m_sourceCodes[infile] = asString(dev::contents(infile)); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
for (auto const& sourceCode: m_sourceCodes) |
||||
|
m_compiler.addSource(sourceCode.first, sourceCode.second); |
||||
|
// TODO: Perhaps we should not compile unless requested
|
||||
|
m_compiler.compile(m_args["optimize"].as<bool>()); |
||||
|
} |
||||
|
catch (ParserError const& exception) |
||||
|
{ |
||||
|
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Parser error", m_compiler); |
||||
|
return false; |
||||
|
} |
||||
|
catch (DeclarationError const& exception) |
||||
|
{ |
||||
|
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Declaration error", m_compiler); |
||||
|
return false; |
||||
|
} |
||||
|
catch (TypeError const& exception) |
||||
|
{ |
||||
|
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Type error", m_compiler); |
||||
|
return false; |
||||
|
} |
||||
|
catch (CompilerError const& exception) |
||||
|
{ |
||||
|
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Compiler error", m_compiler); |
||||
|
return false; |
||||
|
} |
||||
|
catch (InternalCompilerError const& exception) |
||||
|
{ |
||||
|
SourceReferenceFormatter::printExceptionInformation(cerr, exception, "Internal compiler error", m_compiler); |
||||
|
return false; |
||||
|
} |
||||
|
catch (Exception const& exception) |
||||
|
{ |
||||
|
cerr << "Exception during compilation: " << boost::diagnostic_information(exception) << endl; |
||||
|
return false; |
||||
|
} |
||||
|
catch (...) |
||||
|
{ |
||||
|
cerr << "Unknown exception during compilation." << endl; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
void CommandLineInterface::actOnInput() |
||||
|
{ |
||||
|
// do we need AST output?
|
||||
|
if (m_args.count("ast")) |
||||
|
{ |
||||
|
auto choice = m_args["ast"].as<OutputType>(); |
||||
|
if (outputToStdout(choice)) |
||||
|
{ |
||||
|
cout << "Syntax trees:" << endl << endl; |
||||
|
for (auto const& sourceCode: m_sourceCodes) |
||||
|
{ |
||||
|
cout << endl << "======= " << sourceCode.first << " =======" << endl; |
||||
|
ASTPrinter printer(m_compiler.getAST(sourceCode.first), sourceCode.second); |
||||
|
printer.print(cout); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (outputToFile(choice)) |
||||
|
{ |
||||
|
for (auto const& sourceCode: m_sourceCodes) |
||||
|
{ |
||||
|
boost::filesystem::path p(sourceCode.first); |
||||
|
ofstream outFile(p.stem().string() + ".ast"); |
||||
|
ASTPrinter printer(m_compiler.getAST(sourceCode.first), sourceCode.second); |
||||
|
printer.print(outFile); |
||||
|
outFile.close(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
vector<string> contracts = m_compiler.getContractNames(); |
||||
|
for (string const& contract: contracts) |
||||
|
{ |
||||
|
if (needStdout(m_args)) |
||||
|
cout << endl << "======= " << contract << " =======" << endl; |
||||
|
|
||||
|
// do we need EVM assembly?
|
||||
|
if (m_args.count("asm")) |
||||
|
{ |
||||
|
auto choice = m_args["asm"].as<OutputType>(); |
||||
|
if (outputToStdout(choice)) |
||||
|
{ |
||||
|
cout << "EVM assembly:" << endl; |
||||
|
m_compiler.streamAssembly(cout, contract); |
||||
|
} |
||||
|
|
||||
|
if (outputToFile(choice)) |
||||
|
{ |
||||
|
ofstream outFile(contract + ".evm"); |
||||
|
m_compiler.streamAssembly(outFile, contract); |
||||
|
outFile.close(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
handleBytecode(contract); |
||||
|
handleJson(DocumentationType::ABI_INTERFACE, contract); |
||||
|
handleJson(DocumentationType::NATSPEC_DEV, contract); |
||||
|
handleJson(DocumentationType::NATSPEC_USER, contract); |
||||
|
} // end of contracts iteration
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
/*
|
||||
|
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 <lefteris@ethdev.com> |
||||
|
* @date 2014 |
||||
|
* Solidity command line interface. |
||||
|
*/ |
||||
|
#pragma once |
||||
|
|
||||
|
#include <boost/program_options.hpp> |
||||
|
|
||||
|
#include <libsolidity/CompilerStack.h> |
||||
|
|
||||
|
namespace dev |
||||
|
{ |
||||
|
namespace solidity |
||||
|
{ |
||||
|
|
||||
|
//forward declaration
|
||||
|
enum class DocumentationType: uint8_t; |
||||
|
|
||||
|
enum class OutputType: uint8_t |
||||
|
{ |
||||
|
STDOUT, |
||||
|
FILE, |
||||
|
BOTH |
||||
|
}; |
||||
|
|
||||
|
class CommandLineInterface |
||||
|
{ |
||||
|
public: |
||||
|
CommandLineInterface() {} |
||||
|
|
||||
|
/// Parse command line arguments and return false if we should not continue
|
||||
|
bool parseArguments(int argc, char** argv); |
||||
|
/// Parse the files and create source code objects
|
||||
|
bool processInput(); |
||||
|
/// Perform actions on the input depending on provided compiler arguments
|
||||
|
void actOnInput(); |
||||
|
|
||||
|
private: |
||||
|
void handleBinary(std::string const& _contract); |
||||
|
void handleOpcode(std::string const& _contract); |
||||
|
void handleBytecode(std::string const& _contract); |
||||
|
void handleJson(DocumentationType _type, |
||||
|
std::string const& _contract); |
||||
|
|
||||
|
/// Compiler arguments variable map
|
||||
|
boost::program_options::variables_map m_args; |
||||
|
/// map of input files to source code strings
|
||||
|
std::map<std::string, std::string> m_sourceCodes; |
||||
|
/// Solidity compiler stack
|
||||
|
dev::solidity::CompilerStack m_compiler; |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
} |
File diff suppressed because it is too large
Loading…
Reference in new issue