diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 2a66a6d69..04fc7757c 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -1626,7 +1626,7 @@ void Main::on_data_textChanged()
catch (dev::Exception const& exception)
{
ostringstream error;
- solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner());
+ solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
solidity = "
Solidity
" + QString::fromStdString(error.str()).toHtmlEscaped() + "
";
}
catch (...)
diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h
index 50b9df413..fffc5843f 100644
--- a/alethzero/MainWin.h
+++ b/alethzero/MainWin.h
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp
index 858fd53ff..766ca485d 100644
--- a/libdevcrypto/CryptoPP.cpp
+++ b/libdevcrypto/CryptoPP.cpp
@@ -52,6 +52,12 @@ void Secp256k1::decrypt(Secret const& _k, bytes& io_text)
{
CryptoPP::ECIES::Decryptor d;
initializeDLScheme(_k, d);
+
+ if (!io_text.size())
+ {
+ io_text.resize(1);
+ io_text[0] = 0;
+ }
size_t clen = io_text.size();
bytes plain;
diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp
index d130194cc..e3346754b 100644
--- a/libethereum/Client.cpp
+++ b/libethereum/Client.cpp
@@ -217,7 +217,7 @@ void Client::noteChanged(h256Set const& _filters)
for (auto& i: m_watches)
if (_filters.count(i.second.id))
{
- cwatch << "!!!" << i.first << i.second.id;
+// cwatch << "!!!" << i.first << i.second.id;
i.second.changes++;
}
}
diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp
index 42c063d3f..9e2f5ee07 100644
--- a/libethereum/Executive.cpp
+++ b/libethereum/Executive.cpp
@@ -21,6 +21,7 @@
#include
#include
+#include
#include
#include "Interface.h"
#include "Executive.h"
@@ -32,13 +33,6 @@ using namespace dev::eth;
#define ETH_VMTRACE 1
-Executive::~Executive()
-{
- // TODO: Make safe.
- delete m_ext;
- delete m_vm;
-}
-
u256 Executive::gasUsed() const
{
return m_t.gas() - m_endGas;
@@ -112,9 +106,9 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
if (m_s.addressHasCode(_receiveAddress))
{
- m_vm = VMFactory::create(VMFactory::Interpreter, _gas).release();
+ m_vm = VMFactory::create(_gas);
bytes const& c = m_s.code(_receiveAddress);
- m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms);
+ m_ext.reset(new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms));
}
else
m_endGas = _gas;
@@ -131,8 +125,8 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception);
// Execute _init.
- m_vm = VMFactory::create(VMFactory::Interpreter, _gas).release();
- m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms);
+ m_vm = VMFactory::create(_gas);
+ m_ext.reset(new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms));
return _init.empty();
}
@@ -141,7 +135,7 @@ OnOpFunc Executive::simpleTrace()
return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt)
{
ExtVM const& ext = *(ExtVM const*)voidExt;
- VM& vm = *(VM*)voidVM; // TODO: Ok for now, because only interpeter/VM supports OnOp callback, but safer solution would be nice
+ VM& vm = *(VM*)voidVM;
ostringstream o;
o << endl << " STACK" << endl;
diff --git a/libethereum/Executive.h b/libethereum/Executive.h
index 1a9a27d52..f2ee6a77d 100644
--- a/libethereum/Executive.h
+++ b/libethereum/Executive.h
@@ -25,17 +25,17 @@
#include
#include
#include
+#include
#include "Transaction.h"
-#include "Manifest.h"
+#include "ExtVM.h"
namespace dev
{
namespace eth
{
-class VMFace;
-class ExtVM;
class State;
+struct Manifest;
struct VMTraceChannel: public LogChannel { static const char* name() { return "EVM"; } static const int verbosity = 11; };
@@ -43,7 +43,9 @@ class Executive
{
public:
Executive(State& _s, Manifest* o_ms = nullptr): m_s(_s), m_ms(o_ms) {}
- ~Executive();
+ ~Executive() = default;
+ Executive(Executive const&) = delete;
+ void operator=(Executive) = delete;
bool setup(bytesConstRef _transaction);
bool create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress);
@@ -68,8 +70,8 @@ public:
private:
State& m_s;
- ExtVM* m_ext = nullptr; // TODO: make safe.
- VMFace* m_vm = nullptr;
+ std::unique_ptr m_ext;
+ std::unique_ptr m_vm;
Manifest* m_ms = nullptr;
bytesConstRef m_out;
Address m_newAddress;
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index 66d24a27b..539cb55f0 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -29,10 +29,11 @@
#include
#include
#include
-#include
+#include
#include "BlockChain.h"
#include "Defaults.h"
#include "ExtVM.h"
+#include "Executive.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
@@ -171,8 +172,7 @@ State::State(State const& _s):
m_previousBlock(_s.m_previousBlock),
m_currentBlock(_s.m_currentBlock),
m_ourAddress(_s.m_ourAddress),
- m_blockReward(_s.m_blockReward),
- m_vmKind(_s.m_vmKind)
+ m_blockReward(_s.m_blockReward)
{
paranoia("after state cloning (copy cons).", true);
}
@@ -206,7 +206,6 @@ State& State::operator=(State const& _s)
m_ourAddress = _s.m_ourAddress;
m_blockReward = _s.m_blockReward;
m_lastTx = _s.m_lastTx;
- m_vmKind = _s.m_vmKind;
paranoia("after state cloning (assignment op)", true);
return *this;
}
@@ -1103,7 +1102,7 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return false;
}
}
- catch (InvalidTrie)
+ catch (InvalidTrie const&)
{
cwarn << "BAD TRIE" << (e ? "[enforced" : "[unenforced") << "refs]";
cnote << m_db.keys();
@@ -1215,20 +1214,19 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
}
else if (addressHasCode(_codeAddress))
{
- auto vmObj = VMFactory::create(getVMKind(), *_gas);
- auto& vm = *vmObj;
+ auto vm = VMFactory::create(*_gas);
ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level);
bool revert = false;
try
{
- auto out = vm.go(evm, _onOp);
+ auto out = vm->go(evm, _onOp);
memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
if (o_sub)
*o_sub += evm.sub;
if (o_ms)
o_ms->output = out.toBytes();
- *_gas = vm.gas();
+ *_gas = vm->gas();
}
catch (VMException const& _e)
{
@@ -1275,20 +1273,19 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
m_cache[newAddress] = Account(balance(newAddress) + _endowment, Account::ContractConception);
// Execute init code.
- auto vmObj = VMFactory::create(getVMKind(), *_gas);
- auto& vm = *vmObj;
+ auto vm = VMFactory::create(*_gas);
ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms, _level);
bool revert = false;
bytesConstRef out;
try
{
- out = vm.go(evm, _onOp);
+ out = vm->go(evm, _onOp);
if (o_ms)
o_ms->output = out.toBytes();
if (o_sub)
*o_sub += evm.sub;
- *_gas = vm.gas();
+ *_gas = vm->gas();
}
catch (VMException const& _e)
{
diff --git a/libethereum/State.h b/libethereum/State.h
index f7bc0d119..6b53ce925 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -30,7 +30,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -38,9 +37,7 @@
#include "Account.h"
#include "Transaction.h"
#include "TransactionReceipt.h"
-#include "Executive.h"
#include "AccountDiff.h"
-#include "VMFactory.h"
namespace dev
{
@@ -262,12 +259,6 @@ public:
/// the block since all state changes are ultimately reversed.
void cleanup(bool _fullCommit);
- /// Sets VM kind to be used by the state
- void setVMKind(VMFactory::Kind _kind) { m_vmKind = _kind; }
-
- /// Get the kind of VM used by the state
- VMFactory::Kind getVMKind() const { return m_vmKind; }
-
private:
/// Undo the changes to the state for committing to mine.
void uncommitToMine();
@@ -335,8 +326,6 @@ private:
u256 m_blockReward;
- VMFactory::Kind m_vmKind = VMFactory::Interpreter; ///< The kind of VM used by the state
-
static std::string c_defaultPath;
static const std::map c_precompiled;
diff --git a/libethereum/VMFactory.cpp b/libethereum/VMFactory.cpp
deleted file mode 100644
index 3077ed546..000000000
--- a/libethereum/VMFactory.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#include
-
-#if ETH_EVMJIT
- #include
-#endif
-
-#include "VMFactory.h"
-
-namespace dev
-{
-namespace eth
-{
-
-std::unique_ptr VMFactory::create(VMFactory::Kind _kind, u256 _gas)
-{
-#if ETH_EVMJIT
- auto vm = _kind == Kind::JIT ? static_cast(new JitVM)
- : static_cast(new VM);
-#else
- VMFace* vm = new VM;
-#endif
-
- vm->reset(_gas);
- return std::unique_ptr(vm);
-}
-
-}
-}
diff --git a/libethereum/VMFactory.h b/libethereum/VMFactory.h
deleted file mode 100644
index 5d8edc391..000000000
--- a/libethereum/VMFactory.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include
-
-namespace dev
-{
-namespace eth
-{
-
-/**
- */
-
-class VMFactory
-{
-public:
- enum Kind: bool {
- Interpreter,
-#if ETH_EVMJIT
- JIT
-#endif
- };
-
- static std::unique_ptr create(Kind, u256 _gas = 0);
-};
-
-
-}
-}
diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h
index 4a175ff4e..52798cd89 100644
--- a/libevm/ExtVMFace.h
+++ b/libevm/ExtVMFace.h
@@ -150,7 +150,7 @@ public:
BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
- unsigned depth; ///< Depth of the present call.
+ unsigned depth = 0; ///< Depth of the present call.
};
}
diff --git a/libevm/VM.cpp b/libevm/VM.cpp
index ba158de2a..44620a3d5 100644
--- a/libevm/VM.cpp
+++ b/libevm/VM.cpp
@@ -35,7 +35,7 @@ void VM::reset(u256 _gas) noexcept
bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps)
{
if (auto defaultExt = dynamic_cast(&_ext))
- return go(*defaultExt, _onOp, _steps);
+ return goImpl(*defaultExt, _onOp, _steps);
else
- return go(_ext, _onOp, _steps);
+ return goImpl(_ext, _onOp, _steps);
}
diff --git a/libevm/VM.h b/libevm/VM.h
index c95242dfa..d03760a78 100644
--- a/libevm/VM.h
+++ b/libevm/VM.h
@@ -27,17 +27,14 @@
#include
#include
#include
-#include "VMFace.h"
#include "FeeStructure.h"
-#include "ExtVMFace.h"
+#include "VMFace.h"
namespace dev
{
namespace eth
{
-class VMFactory;
-
// Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash.
// Currently we just pull out the right (low-order in BE) 160-bits.
inline Address asAddress(u256 _item)
@@ -52,7 +49,7 @@ inline u256 fromAddress(Address _a)
/**
*/
-class VM : public VMFace
+class VM: public VMFace
{
public:
virtual void reset(u256 _gas = 0) noexcept override final;
@@ -61,17 +58,20 @@ public:
void require(u256 _n) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); } }
void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } }
+
u256 curPC() const { return m_curPC; }
bytes const& memory() const { return m_temp; }
u256s const& stack() const { return m_stack; }
private:
- friend VMFactory;
+ friend class VMFactory;
+
+ /// Construct VM object.
explicit VM(u256 _gas = 0): VMFace(_gas) {}
template
- bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps);
+ bytesConstRef goImpl(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1);
u256 m_curPC = 0;
bytes m_temp;
@@ -83,7 +83,7 @@ private:
}
// INLINE:
-template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps)
+template dev::bytesConstRef dev::eth::VM::goImpl(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps)
{
auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; };
@@ -518,12 +518,12 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
break;
case Instruction::CALLDATALOAD:
{
- if ((unsigned)m_stack.back() + 31 < _ext.data.size())
+ if ((unsigned)m_stack.back() + (uint64_t)31 < _ext.data.size())
m_stack.back() = (u256)*(h256 const*)(_ext.data.data() + (unsigned)m_stack.back());
else
{
h256 r;
- for (unsigned i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + 32, j = 0; i < e; ++i, ++j)
+ for (uint64_t i = (unsigned)m_stack.back(), e = (unsigned)m_stack.back() + (uint64_t)32, j = 0; i < e; ++i, ++j)
r[j] = i < _ext.data.size() ? _ext.data[i] : 0;
m_stack.back() = (u256)r;
}
@@ -532,51 +532,49 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::CALLDATASIZE:
m_stack.push_back(_ext.data.size());
break;
- case Instruction::CALLDATACOPY:
- {
- unsigned mf = (unsigned)m_stack.back();
- m_stack.pop_back();
- u256 cf = m_stack.back();
- m_stack.pop_back();
- unsigned l = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned el = cf + l > (u256)_ext.data.size() ? (u256)_ext.data.size() < cf ? 0 : _ext.data.size() - (unsigned)cf : l;
- memcpy(m_temp.data() + mf, _ext.data.data() + (unsigned)cf, el);
- memset(m_temp.data() + mf + el, 0, l - el);
- break;
- }
case Instruction::CODESIZE:
m_stack.push_back(_ext.code.size());
break;
- case Instruction::CODECOPY:
- {
- unsigned mf = (unsigned)m_stack.back();
- m_stack.pop_back();
- u256 cf = (u256)m_stack.back();
- m_stack.pop_back();
- unsigned l = (unsigned)m_stack.back();
- m_stack.pop_back();
- unsigned el = cf + l > (u256)_ext.code.size() ? (u256)_ext.code.size() < cf ? 0 : _ext.code.size() - (unsigned)cf : l;
- memcpy(m_temp.data() + mf, _ext.code.data() + (unsigned)cf, el);
- memset(m_temp.data() + mf + el, 0, l - el);
- break;
- }
case Instruction::EXTCODESIZE:
m_stack.back() = _ext.codeAt(asAddress(m_stack.back())).size();
break;
+ case Instruction::CALLDATACOPY:
+ case Instruction::CODECOPY:
case Instruction::EXTCODECOPY:
{
- Address a = asAddress(m_stack.back());
- m_stack.pop_back();
- unsigned mf = (unsigned)m_stack.back();
+ Address a;
+ if (inst == Instruction::EXTCODECOPY)
+ {
+ a = asAddress(m_stack.back());
+ m_stack.pop_back();
+ }
+ unsigned offset = (unsigned)m_stack.back();
m_stack.pop_back();
- u256 cf = m_stack.back();
+ u256 index = m_stack.back();
m_stack.pop_back();
- unsigned l = (unsigned)m_stack.back();
+ unsigned size = (unsigned)m_stack.back();
m_stack.pop_back();
- unsigned el = cf + l > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < cf ? 0 : _ext.codeAt(a).size() - (unsigned)cf : l;
- memcpy(m_temp.data() + mf, _ext.codeAt(a).data() + (unsigned)cf, el);
- memset(m_temp.data() + mf + el, 0, l - el);
+ unsigned sizeToBeCopied;
+ switch(inst)
+ {
+ case Instruction::CALLDATACOPY:
+ sizeToBeCopied = index + (bigint)size > (u256)_ext.data.size() ? (u256)_ext.data.size() < index ? 0 : _ext.data.size() - (unsigned)index : size;
+ memcpy(m_temp.data() + offset, _ext.data.data() + (unsigned)index, sizeToBeCopied);
+ break;
+ case Instruction::CODECOPY:
+ sizeToBeCopied = index + (bigint)size > (u256)_ext.code.size() ? (u256)_ext.code.size() < index ? 0 : _ext.code.size() - (unsigned)index : size;
+ memcpy(m_temp.data() + offset, _ext.code.data() + (unsigned)index, sizeToBeCopied);
+ break;
+ case Instruction::EXTCODECOPY:
+ sizeToBeCopied = index + (bigint)size > (u256)_ext.codeAt(a).size() ? (u256)_ext.codeAt(a).size() < index ? 0 : _ext.codeAt(a).size() - (unsigned)index : size;
+ memcpy(m_temp.data() + offset, _ext.codeAt(a).data() + (unsigned)index, sizeToBeCopied);
+ break;
+ default:
+ // this is unreachable, but if someone introduces a bug in the future, he may get here.
+ BOOST_THROW_EXCEPTION(InvalidOpcode() << errinfo_comment("CALLDATACOPY, CODECOPY or EXTCODECOPY instruction requested."));
+ break;
+ }
+ memset(m_temp.data() + offset + sizeToBeCopied, 0, size - sizeToBeCopied);
break;
}
case Instruction::GASPRICE:
diff --git a/libevm/VMFace.h b/libevm/VMFace.h
index f4dd3096e..319da7fc1 100644
--- a/libevm/VMFace.h
+++ b/libevm/VMFace.h
@@ -32,7 +32,7 @@ struct BreakPointHit: virtual VMException {};
struct BadInstruction: virtual VMException {};
struct BadJumpDestination: virtual VMException {};
struct OutOfGas: virtual VMException {};
-struct StackTooSmall: virtual public VMException {};
+struct StackTooSmall: virtual VMException {};
/**
*/
@@ -47,7 +47,7 @@ public:
VMFace(VMFace const&) = delete;
void operator=(VMFace const&) = delete;
- virtual void reset(u256 _gas = 0) noexcept;
+ virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; }
virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0;
diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp
new file mode 100644
index 000000000..90e17c553
--- /dev/null
+++ b/libevm/VMFactory.cpp
@@ -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 .
+*/
+
+#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 VMFactory::create(u256 _gas)
+{
+ asserts(g_kind == VMKind::Interpreter && "Only interpreter supported for now");
+ return std::unique_ptr(new VM(_gas));
+}
+
+}
+}
+
+
+
diff --git a/libevm/VMFace.cpp b/libevm/VMFactory.h
similarity index 74%
rename from libevm/VMFace.cpp
rename to libevm/VMFactory.h
index 136bd5223..c5d9c4f65 100644
--- a/libevm/VMFace.cpp
+++ b/libevm/VMFactory.h
@@ -14,14 +14,31 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see .
*/
+#pragma once
#include "VMFace.h"
-#include "VM.h"
-using namespace dev;
-using namespace dev::eth;
+namespace dev
+{
+namespace eth
+{
-void VMFace::reset(u256 _gas) noexcept
+enum class VMKind: bool
{
- m_gas = _gas;
+ Interpreter,
+ JIT
+};
+
+class VMFactory
+{
+public:
+ VMFactory() = delete;
+
+ static std::unique_ptr create(u256 _gas);
+
+ static void setKind(VMKind _kind);
+
+};
+
+}
}
diff --git a/libp2p/Common.h b/libp2p/Common.h
index 34f47b236..d46c5eed1 100644
--- a/libp2p/Common.h
+++ b/libp2p/Common.h
@@ -57,7 +57,7 @@ class Session;
struct NetWarn: public LogChannel { static const char* name() { return "!N!"; } static const int verbosity = 0; };
struct NetNote: public LogChannel { static const char* name() { return "*N*"; } static const int verbosity = 1; };
struct NetMessageSummary: public LogChannel { static const char* name() { return "-N-"; } static const int verbosity = 2; };
-struct NetConnect: public LogChannel { static const char* name() { return "+N+"; } static const int verbosity = 4; };
+struct NetConnect: public LogChannel { static const char* name() { return "+N+"; } static const int verbosity = 10; };
struct NetMessageDetail: public LogChannel { static const char* name() { return "=N="; } static const int verbosity = 5; };
struct NetTriviaSummary: public LogChannel { static const char* name() { return "-N-"; } static const int verbosity = 10; };
struct NetTriviaDetail: public LogChannel { static const char* name() { return "=N="; } static const int verbosity = 11; };
diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp
index 7d08910aa..93a6ce672 100644
--- a/libp2p/Host.cpp
+++ b/libp2p/Host.cpp
@@ -15,22 +15,11 @@
along with cpp-ethereum. If not, see .
*/
/** @file Host.cpp
- * @authors:
- * Gav Wood
- * Eric Lombrozo (Windows version of populateAddresses())
+ * @author Alex Leverington
+ * @author Gav Wood
* @date 2014
*/
-#include "Host.h"
-
-#include
-#ifdef _WIN32
-// winsock is already included
-// #include
-#else
-#include
-#endif
-
#include
#include
#include
@@ -43,166 +32,18 @@
#include "Common.h"
#include "Capability.h"
#include "UPnP.h"
+#include "Host.h"
using namespace std;
using namespace dev;
using namespace dev::p2p;
-std::vector Host::getInterfaceAddresses()
-{
- std::vector 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 Host::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 Host::traverseNAT(std::vector 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;
-}
-
Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool _start):
Worker("p2p", 0),
m_clientVersion(_clientVersion),
m_netPrefs(_n),
- m_ifAddresses(getInterfaceAddresses()),
- m_ioService(new ba::io_service(2)),
- m_acceptor(new bi::tcp::acceptor(*m_ioService)),
- m_socket(new bi::tcp::socket(*m_ioService)),
+ m_ifAddresses(Network::getInterfaceAddresses()),
+ m_ioService(2),
+ m_acceptorV4(m_ioService),
m_key(KeyPair::create())
{
for (auto address: m_ifAddresses)
@@ -216,7 +57,7 @@ Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bool
Host::~Host()
{
- quit();
+ stop();
}
void Host::start()
@@ -226,30 +67,78 @@ void Host::start()
void Host::stop()
{
+ // called to force io_service to kill any remaining tasks it might have -
+ // such tasks may involve socket reads from Capabilities that maintain references
+ // to resources we're about to free.
+
{
- // prevent m_run from being set to false at same time as set to true by start()
+ // Although m_run is set by stop() or start(), it effects m_runTimer so x_runTimer is used instead of a mutex for m_run.
+ // when m_run == false, run() will cause this::run() to stop() ioservice
Guard l(x_runTimer);
- // once m_run is false the scheduler will shutdown network and stopWorking()
+ // ignore if already stopped/stopping
+ if (!m_run)
+ return;
m_run = false;
}
- // we know shutdown is complete when m_timer is reset
- while (m_timer)
+ // wait for m_timer to reset (indicating network scheduler has stopped)
+ while (!!m_timer)
this_thread::sleep_for(chrono::milliseconds(50));
+
+ // stop worker thread
stopWorking();
}
-void Host::quit()
+void Host::doneWorking()
{
- // called to force io_service to kill any remaining tasks it might have -
- // such tasks may involve socket reads from Capabilities that maintain references
- // to resources we're about to free.
- if (isWorking())
- stop();
- m_acceptor.reset();
- m_socket.reset();
+ // reset ioservice (allows manually polling network, below)
+ m_ioService.reset();
+
+ // shutdown acceptor
+ m_acceptorV4.cancel();
+ if (m_acceptorV4.is_open())
+ m_acceptorV4.close();
+
+ // There maybe an incoming connection which started but hasn't finished.
+ // Wait for acceptor to end itself instead of assuming it's complete.
+ // This helps ensure a peer isn't stopped at the same time it's starting
+ // and that socket for pending connection is closed.
+ while (m_accepting)
+ m_ioService.poll();
+
+ // stop capabilities (eth: stops syncing or block/tx broadcast)
+ for (auto const& h: m_capabilities)
+ h.second->onStopping();
+
+ // disconnect peers
+ for (unsigned n = 0;; n = 0)
+ {
+ {
+ RecursiveGuard l(x_peers);
+ for (auto i: m_peers)
+ if (auto p = i.second.lock())
+ if (p->isOpen())
+ {
+ p->disconnect(ClientQuit);
+ n++;
+ }
+ }
+ if (!n)
+ break;
+
+ // poll so that peers send out disconnect packets
+ m_ioService.poll();
+ }
+
+ // stop network (again; helpful to call before subsequent reset())
+ m_ioService.stop();
+
+ // reset network (allows reusing ioservice in future)
m_ioService.reset();
- // m_acceptor & m_socket are DANGEROUS now.
+
+ // finally, clear out peers (in case they're lingering)
+ RecursiveGuard l(x_peers);
+ m_peers.clear();
}
unsigned Host::protocolVersion() const
@@ -407,7 +296,7 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
if (_upnp)
{
bi::address upnpifaddr;
- bi::tcp::endpoint upnpep = traverseNAT(m_ifAddresses, m_listenPort, upnpifaddr);
+ bi::tcp::endpoint upnpep = Network::traverseNAT(m_ifAddresses, m_listenPort, upnpifaddr);
if (!upnpep.address().is_unspecified() && !upnpifaddr.is_unspecified())
{
if (!m_peerAddresses.count(upnpep.address()))
@@ -431,18 +320,18 @@ void Host::determinePublic(string const& _publicAddress, bool _upnp)
m_public = bi::tcp::endpoint(bi::address(), m_listenPort);
}
-void Host::ensureAccepting()
+void Host::runAcceptor()
{
- // return if there's no io-server (quit called) or we're not listening
- if (!m_ioService || m_listenPort < 1)
- return;
-
- if (!m_accepting)
+ assert(m_listenPort > 0);
+
+ if (m_run && !m_accepting)
{
clog(NetConnect) << "Listening on local port " << m_listenPort << " (public: " << m_public << ")";
m_accepting = true;
- m_acceptor->async_accept(*m_socket, [=](boost::system::error_code ec)
+ m_socket.reset(new bi::tcp::socket(m_ioService));
+ m_acceptorV4.async_accept(*m_socket, [=](boost::system::error_code ec)
{
+ bool success = false;
if (!ec)
{
try
@@ -452,8 +341,9 @@ void Host::ensureAccepting()
} catch (...){}
bi::address remoteAddress = m_socket->remote_endpoint().address();
// Port defaults to 0 - we let the hello tell us which port the peer listens to
- auto p = std::make_shared(this, std::move(*m_socket), bi::tcp::endpoint(remoteAddress, 0));
+ auto p = std::make_shared(this, std::move(*m_socket.release()), bi::tcp::endpoint(remoteAddress, 0));
p->start();
+ success = true;
}
catch (Exception const& _e)
{
@@ -464,9 +354,17 @@ void Host::ensureAccepting()
clog(NetWarn) << "ERROR: " << _e.what();
}
}
+
+ if (!success && m_socket->is_open())
+ {
+ boost::system::error_code ec;
+ m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
+ m_socket->close();
+ }
+
m_accepting = false;
if (ec.value() < 1)
- ensureAccepting();
+ runAcceptor();
});
}
}
@@ -480,17 +378,16 @@ string Host::pocHost()
void Host::connect(std::string const& _addr, unsigned short _port) noexcept
{
- // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
- if (!m_ioService)
+ if (!m_run)
return;
- for (int i = 0; i < 2; ++i)
+ for (auto first: {true, false})
{
try
{
- if (i == 0)
+ if (first)
{
- bi::tcp::resolver r(*m_ioService);
+ bi::tcp::resolver r(m_ioService);
connect(r.resolve({_addr, toString(_port)})->endpoint());
}
else
@@ -512,12 +409,11 @@ void Host::connect(std::string const& _addr, unsigned short _port) noexcept
void Host::connect(bi::tcp::endpoint const& _ep)
{
- // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
- if (!m_ioService)
+ if (!m_run)
return;
clog(NetConnect) << "Attempting single-shot connection to " << _ep;
- bi::tcp::socket* s = new bi::tcp::socket(*m_ioService);
+ bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
s->async_connect(_ep, [=](boost::system::error_code const& ec)
{
if (ec)
@@ -534,8 +430,7 @@ void Host::connect(bi::tcp::endpoint const& _ep)
void Host::connect(std::shared_ptr const& _n)
{
- // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
- if (!m_ioService)
+ if (!m_run)
return;
// prevent concurrently connecting to a node; todo: better abstraction
@@ -551,27 +446,32 @@ void Host::connect(std::shared_ptr const& _n)
_n->lastAttempted = std::chrono::system_clock::now();
_n->failedAttempts++;
m_ready -= _n->index;
- bi::tcp::socket* s = new bi::tcp::socket(*m_ioService);
- s->async_connect(_n->address, [=](boost::system::error_code const& ec)
- {
- if (ec)
- {
- clog(NetConnect) << "Connection refused to node" << _n->id.abridged() << "@" << _n->address << "(" << ec.message() << ")";
- _n->lastDisconnect = TCPError;
- _n->lastAttempted = std::chrono::system_clock::now();
- m_ready += _n->index;
- }
- else
+ bi::tcp::socket* s = new bi::tcp::socket(m_ioService);
+
+ auto n = node(_n->id);
+ if (n)
+ s->async_connect(_n->address, [=](boost::system::error_code const& ec)
{
- clog(NetConnect) << "Connected to" << _n->id.abridged() << "@" << _n->address;
- _n->lastConnected = std::chrono::system_clock::now();
- auto p = make_shared(this, std::move(*s), node(_n->id), true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism.
- p->start();
- }
- delete s;
- Guard l(x_pendingNodeConns);
- m_pendingNodeConns.erase(nptr);
- });
+ if (ec)
+ {
+ clog(NetConnect) << "Connection refused to node" << _n->id.abridged() << "@" << _n->address << "(" << ec.message() << ")";
+ _n->lastDisconnect = TCPError;
+ _n->lastAttempted = std::chrono::system_clock::now();
+ m_ready += _n->index;
+ }
+ else
+ {
+ clog(NetConnect) << "Connected to" << _n->id.abridged() << "@" << _n->address;
+ _n->lastConnected = std::chrono::system_clock::now();
+ auto p = make_shared(this, std::move(*s), n, true); // true because we don't care about ids matched for now. Once we have permenant IDs this will matter a lot more and we can institute a safer mechanism.
+ p->start();
+ }
+ delete s;
+ Guard l(x_pendingNodeConns);
+ m_pendingNodeConns.erase(nptr);
+ });
+ else
+ clog(NetWarn) << "Trying to connect to node not in node table.";
}
bool Host::havePeer(NodeId _id) const
@@ -680,8 +580,7 @@ void Host::prunePeers()
PeerInfos Host::peers(bool _updatePing) const
{
- // if there's no ioService, it means we've had quit() called - bomb out - we're not allowed in here.
- if (!m_ioService)
+ if (!m_run)
return PeerInfos();
RecursiveGuard l(x_peers);
@@ -698,152 +597,95 @@ PeerInfos Host::peers(bool _updatePing) const
return ret;
}
-void Host::run(boost::system::error_code const& error)
+void Host::run(boost::system::error_code const&)
{
- m_lastTick += c_timerInterval;
-
- if (error || !m_ioService)
+ if (!m_run)
{
- // timer died or io service went away, so stop here
+ // stopping io service allows running manual network operations for shutdown
+ // and also stops blocking worker thread, allowing worker thread to exit
+ m_ioService.stop();
+
+ // resetting timer signals network that nothing else can be scheduled to run
m_timer.reset();
return;
}
- // network running
- if (m_run)
+ m_lastTick += c_timerInterval;
+ if (m_lastTick >= c_timerInterval * 10)
{
- if (m_lastTick >= c_timerInterval * 10)
- {
- growPeers();
- prunePeers();
- m_lastTick = 0;
- }
-
- if (m_hadNewNodes)
- {
- for (auto p: m_peers)
- if (auto pp = p.second.lock())
- pp->serviceNodesRequest();
-
- m_hadNewNodes = false;
- }
-
- if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s.
- {
- for (auto p: m_peers)
- if (auto pp = p.second.lock())
- if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60))
- pp->disconnect(PingTimeout);
- pingAll();
- }
-
- auto runcb = [this](boost::system::error_code const& error) -> void { run(error); };
- m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval));
- m_timer->async_wait(runcb);
-
- return;
+ growPeers();
+ prunePeers();
+ m_lastTick = 0;
}
- // network stopping
- if (!m_run)
+ if (m_hadNewNodes)
{
- // close acceptor
- if (m_acceptor->is_open())
- {
- if (m_accepting)
- m_acceptor->cancel();
- m_acceptor->close();
- m_accepting = false;
- }
-
- // stop capabilities (eth: stops syncing or block/tx broadcast)
- for (auto const& h: m_capabilities)
- h.second->onStopping();
-
- // disconnect peers
- for (unsigned n = 0;; n = 0)
- {
- {
- RecursiveGuard l(x_peers);
- for (auto i: m_peers)
- if (auto p = i.second.lock())
- if (p->isOpen())
- {
- p->disconnect(ClientQuit);
- n++;
- }
- }
- if (!n)
- break;
- this_thread::sleep_for(chrono::milliseconds(100));
- }
-
- if (m_socket->is_open())
- m_socket->close();
+ for (auto p: m_peers)
+ if (auto pp = p.second.lock())
+ pp->serviceNodesRequest();
- // m_run is false, so we're stopping; kill timer
- m_lastTick = 0;
-
- // causes parent thread's stop() to continue which calls stopWorking()
- m_timer.reset();
-
- // stop ioservice (stops blocking worker thread, allowing thread to join)
- if (!!m_ioService)
- m_ioService->stop();
- return;
+ m_hadNewNodes = false;
+ }
+
+ if (chrono::steady_clock::now() - m_lastPing > chrono::seconds(30)) // ping every 30s.
+ {
+ for (auto p: m_peers)
+ if (auto pp = p.second.lock())
+ if (chrono::steady_clock::now() - pp->m_lastReceived > chrono::seconds(60))
+ pp->disconnect(PingTimeout);
+ pingAll();
}
+
+ auto runcb = [this](boost::system::error_code const& error) -> void { run(error); };
+ m_timer->expires_from_now(boost::posix_time::milliseconds(c_timerInterval));
+ m_timer->async_wait(runcb);
}
void Host::startedWorking()
{
- if (!m_timer)
+ asserts(!m_timer);
+
{
- // no timer means this is first run and network must be started
- // (run once when host worker thread calls startedWorking())
-
- {
- // prevent m_run from being set to true at same time as set to false by stop()
- // don't release mutex until m_timer is set so in case stop() is called at same
- // time, stop will wait on m_timer and graceful network shutdown.
- Guard l(x_runTimer);
- // reset io service and create deadline timer
- m_timer.reset(new boost::asio::deadline_timer(*m_ioService));
- m_run = true;
- }
- m_ioService->reset();
-
- // try to open acceptor (todo: ipv6)
- m_listenPort = listen4(m_acceptor.get(), m_netPrefs.listenPort);
-
- // start capability threads
- for (auto const& h: m_capabilities)
- h.second->onStarting();
-
- // determine public IP, but only if we're able to listen for connections
- // todo: GUI when listen is unavailable in UI
- if (m_listenPort)
- {
- determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
- ensureAccepting();
- }
-
- // if m_public address is valid then add us to node list
- // todo: abstract empty() and emplace logic
- if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
- noteNode(id(), m_public, Origin::Perfect, false);
+ // prevent m_run from being set to true at same time as set to false by stop()
+ // don't release mutex until m_timer is set so in case stop() is called at same
+ // time, stop will wait on m_timer and graceful network shutdown.
+ Guard l(x_runTimer);
+ // create deadline timer
+ m_timer.reset(new boost::asio::deadline_timer(m_ioService));
+ m_run = true;
+ }
+
+ // try to open acceptor (todo: ipv6)
+ m_listenPort = Network::listen4(m_acceptorV4, m_netPrefs.listenPort);
+
+ // start capability threads
+ for (auto const& h: m_capabilities)
+ h.second->onStarting();
+
+ // determine public IP, but only if we're able to listen for connections
+ // todo: GUI when listen is unavailable in UI
+ if (m_listenPort)
+ {
+ determinePublic(m_netPrefs.publicIP, m_netPrefs.upnp);
- clog(NetNote) << "Id:" << id().abridged();
+ if (m_listenPort > 0)
+ runAcceptor();
}
+ // if m_public address is valid then add us to node list
+ // todo: abstract empty() and emplace logic
+ if (!m_public.address().is_unspecified() && (m_nodes.empty() || m_nodes[m_nodesList[0]]->id != id()))
+ noteNode(id(), m_public, Origin::Perfect, false);
+
+ clog(NetNote) << "Id:" << id().abridged();
+
run(boost::system::error_code());
}
void Host::doWork()
{
- // no ioService means we've had quit() called - bomb out - we're not allowed in here.
- if (asserts(!!m_ioService))
- return;
- m_ioService->run();
+ if (m_run)
+ m_ioService.run();
}
void Host::pingAll()
diff --git a/libp2p/Host.h b/libp2p/Host.h
index 644afeb69..a146d6a66 100644
--- a/libp2p/Host.h
+++ b/libp2p/Host.h
@@ -14,7 +14,8 @@
You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see .
*/
-/** @file EthereumHost.h
+/** @file Host.h
+ * @author Alex Leverington
* @author Gav Wood
* @date 2014
*/
@@ -34,9 +35,10 @@
#include
#include
#include "HostCapability.h"
+#include "Network.h"
#include "Common.h"
namespace ba = boost::asio;
-namespace bi = boost::asio::ip;
+namespace bi = ba::ip;
namespace dev
{
@@ -101,16 +103,6 @@ struct Node
using Nodes = std::vector;
-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 The Host class
* Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe.
@@ -120,17 +112,6 @@ class Host: public Worker
friend class Session;
friend class HostCapabilityFace;
friend struct Node;
-
- /// Static network interface methods
-public:
- /// @returns public and private interface addresses
- static std::vector 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 const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr);
public:
/// Start server, listening for connections on the given port.
@@ -187,14 +168,12 @@ public:
void start();
/// Stop network. @threadsafe
+ /// Resets acceptor, socket, and IO service. Called by deallocator.
void stop();
/// @returns if network is running.
bool isStarted() const { return m_run; }
- /// Reset acceptor, socket, and IO service. Called by deallocator. Maybe called by implementation when ordered deallocation is required.
- void quit();
-
NodeId id() const { return m_key.pub(); }
void registerPeer(std::shared_ptr _s, CapDescs const& _caps);
@@ -205,7 +184,8 @@ private:
/// Populate m_peerAddresses with available public addresses.
void determinePublic(std::string const& _publicAddress, bool _upnp);
- void ensureAccepting();
+ /// Called only from startedWorking().
+ void runAcceptor();
void seal(bytes& _b);
@@ -214,11 +194,14 @@ private:
/// Called by Worker. Not thread-safe; to be called only by worker.
virtual void startedWorking();
- /// Called by startedWorking. Not thread-safe; to be called only be worker callback.
+ /// Called by startedWorking. Not thread-safe; to be called only be Worker.
void run(boost::system::error_code const& error); ///< Run network. Called serially via ASIO deadline timer. Manages connection state transitions.
- /// Run network
+ /// Run network. Not thread-safe; to be called only by worker.
virtual void doWork();
+
+ /// Shutdown network. Not thread-safe; to be called only by worker.
+ virtual void doneWorking();
std::shared_ptr noteNode(NodeId _id, bi::tcp::endpoint _a, Origin _o, bool _ready, NodeId _oldId = NodeId());
Nodes potentialPeers(RangeMask const& _known);
@@ -235,8 +218,8 @@ private:
int m_listenPort = -1; ///< What port are we listening on. -1 means binding failed or acceptor hasn't been initialized.
- std::unique_ptr m_ioService; ///< IOService for network stuff.
- std::unique_ptr m_acceptor; ///< Listening acceptor.
+ ba::io_service m_ioService; ///< IOService for network stuff.
+ bi::tcp::acceptor m_acceptorV4; ///< Listening acceptor.
std::unique_ptr m_socket; ///< Listening socket.
std::unique_ptr m_timer; ///< Timer which, when network is running, calls scheduler() every c_timerInterval ms.
diff --git a/libp2p/Network.cpp b/libp2p/Network.cpp
new file mode 100644
index 000000000..8ca8dd135
--- /dev/null
+++ b/libp2p/Network.cpp
@@ -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 .
+*/
+/** @file Network.cpp
+ * @author Alex Leverington
+ * @author Gav Wood
+ * @author Eric Lombrozo (Windows version of getInterfaceAddresses())
+ * @date 2014
+ */
+
+#include
+#ifndef _WIN32
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include "Common.h"
+#include "UPnP.h"
+#include "Network.h"
+
+using namespace std;
+using namespace dev;
+using namespace dev::p2p;
+
+std::vector Network::getInterfaceAddresses()
+{
+ std::vector 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 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;
+}
diff --git a/libp2p/Network.h b/libp2p/Network.h
new file mode 100644
index 000000000..944d390c8
--- /dev/null
+++ b/libp2p/Network.h
@@ -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 .
+*/
+/** @file Network.h
+ * @author Alex Leverington
+ * @author Gav Wood
+ * @date 2014
+ */
+
+#pragma once
+
+#include
+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 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 const& _ifAddresses, unsigned short _listenPort, bi::address& o_upnpifaddr);
+};
+
+}
+}
diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp
index 958473870..cb0a60a92 100644
--- a/libp2p/Session.cpp
+++ b/libp2p/Session.cpp
@@ -75,7 +75,11 @@ Session::~Session()
try
{
if (m_socket.is_open())
+ {
+ boost::system::error_code ec;
+ m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
m_socket.close();
+ }
}
catch (...){}
}
@@ -479,6 +483,8 @@ void Session::drop(DisconnectReason _reason)
try
{
clogS(NetConnect) << "Closing " << m_socket.remote_endpoint() << "(" << reasonOf(_reason) << ")";
+ boost::system::error_code ec;
+ m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
m_socket.close();
}
catch (...) {}
diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp
index 4bd0b2c0e..8174d138a 100644
--- a/libsolidity/AST.cpp
+++ b/libsolidity/AST.cpp
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
using namespace std;
@@ -33,38 +34,34 @@ namespace dev
namespace solidity
{
-void ContractDefinition::accept(ASTVisitor& _visitor)
+TypeError ASTNode::createTypeError(string const& _description) const
{
- if (_visitor.visit(*this))
- {
- listAccept(m_definedStructs, _visitor);
- listAccept(m_stateVariables, _visitor);
- listAccept(m_definedFunctions, _visitor);
- }
- _visitor.endVisit(*this);
+ return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
}
-void StructDefinition::accept(ASTVisitor& _visitor)
+vector ContractDefinition::getInterfaceFunctions() const
{
- if (_visitor.visit(*this))
- listAccept(m_members, _visitor);
- _visitor.endVisit(*this);
-}
+ vector exportedFunctions;
+ for (ASTPointer const& f: m_definedFunctions)
+ if (f->isPublic() && f->getName() != getName())
+ exportedFunctions.push_back(f.get());
+ auto compareNames = [](FunctionDefinition const* _a, FunctionDefinition const* _b)
+ {
+ return _a->getName().compare(_b->getName()) < 0;
+ };
-void StructDefinition::checkValidityOfMembers()
-{
- checkMemberTypes();
- checkRecursion();
+ sort(exportedFunctions.begin(), exportedFunctions.end(), compareNames);
+ return exportedFunctions;
}
-void StructDefinition::checkMemberTypes()
+void StructDefinition::checkMemberTypes() const
{
for (ASTPointer const& member: getMembers())
if (!member->getType()->canBeStored())
BOOST_THROW_EXCEPTION(member->createTypeError("Type cannot be used in struct."));
}
-void StructDefinition::checkRecursion()
+void StructDefinition::checkRecursion() const
{
set definitionsSeen;
vector queue = {this};
@@ -79,239 +76,12 @@ void StructDefinition::checkRecursion()
for (ASTPointer const& member: def->getMembers())
if (member->getType()->getCategory() == Type::Category::STRUCT)
{
- UserDefinedTypeName const& typeName = dynamic_cast(*member->getTypeName());
+ UserDefinedTypeName const& typeName = dynamic_cast(*member->getTypeName());
queue.push_back(&dynamic_cast(*typeName.getReferencedDeclaration()));
}
}
}
-void ParameterList::accept(ASTVisitor& _visitor)
-{
- 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 VariableDeclaration::accept(ASTVisitor& _visitor)
-{
- 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 ElementaryTypeName::accept(ASTVisitor& _visitor)
-{
- _visitor.visit(*this);
- _visitor.endVisit(*this);
-}
-
-void UserDefinedTypeName::accept(ASTVisitor& _visitor)
-{
- _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 Statement::accept(ASTVisitor& _visitor)
-{
- _visitor.visit(*this);
- _visitor.endVisit(*this);
-}
-
-void Block::accept(ASTVisitor& _visitor)
-{
- 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 BreakableStatement::accept(ASTVisitor& _visitor)
-{
- _visitor.visit(*this);
- _visitor.endVisit(*this);
-}
-
-void WhileStatement::accept(ASTVisitor& _visitor)
-{
- 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 Break::accept(ASTVisitor& _visitor)
-{
- _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 ExpressionStatement::accept(ASTVisitor& _visitor)
-{
- 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 Assignment::accept(ASTVisitor& _visitor)
-{
- 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 BinaryOperation::accept(ASTVisitor& _visitor)
-{
- 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 MemberAccess::accept(ASTVisitor& _visitor)
-{
- 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 Identifier::accept(ASTVisitor& _visitor)
-{
- _visitor.visit(*this);
- _visitor.endVisit(*this);
-}
-
-void ElementaryTypeNameExpression::accept(ASTVisitor& _visitor)
-{
- _visitor.visit(*this);
- _visitor.endVisit(*this);
-}
-
-void Literal::accept(ASTVisitor& _visitor)
-{
- _visitor.visit(*this);
- _visitor.endVisit(*this);
-}
-
-TypeError ASTNode::createTypeError(string const& _description) const
-{
- return TypeError() << errinfo_sourceLocation(getLocation()) << errinfo_comment(_description);
-}
-
-vector ContractDefinition::getInterfaceFunctions() const
-{
- vector exportedFunctions;
- for (ASTPointer const& f: m_definedFunctions)
- if (f->isPublic() && f->getName() != getName())
- exportedFunctions.push_back(f.get());
- auto compareNames = [](FunctionDefinition const* _a, FunctionDefinition const* _b)
- {
- return _a->getName().compare(_b->getName()) < 0;
- };
-
- sort(exportedFunctions.begin(), exportedFunctions.end(), compareNames);
- return exportedFunctions;
-}
-
void FunctionDefinition::checkTypeRequirements()
{
for (ASTPointer const& var: getParameters() + getReturnParameters())
@@ -519,7 +289,7 @@ void Identifier::checkTypeRequirements()
if (asserts(m_referencedDeclaration))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier not resolved."));
- VariableDeclaration* variable = dynamic_cast(m_referencedDeclaration);
+ VariableDeclaration const* variable = dynamic_cast(m_referencedDeclaration);
if (variable)
{
if (!variable->getType())
@@ -529,29 +299,29 @@ void Identifier::checkTypeRequirements()
return;
}
//@todo can we unify these with TypeName::toType()?
- StructDefinition* structDef = dynamic_cast(m_referencedDeclaration);
+ StructDefinition const* structDef = dynamic_cast(m_referencedDeclaration);
if (structDef)
{
// note that we do not have a struct type here
- m_type = make_shared(make_shared(*structDef));
+ m_type = make_shared(make_shared(*structDef));
return;
}
- FunctionDefinition* functionDef = dynamic_cast(m_referencedDeclaration);
+ FunctionDefinition const* functionDef = dynamic_cast(m_referencedDeclaration);
if (functionDef)
{
// a function reference is not a TypeType, because calling a TypeType converts to the type.
// Calling a function (e.g. function(12), otherContract.function(34)) does not do a type
// conversion.
- m_type = make_shared(*functionDef);
+ m_type = make_shared(*functionDef);
return;
}
- ContractDefinition* contractDef = dynamic_cast(m_referencedDeclaration);
+ ContractDefinition const* contractDef = dynamic_cast(m_referencedDeclaration);
if (contractDef)
{
- m_type = make_shared(make_shared(*contractDef));
+ m_type = make_shared(make_shared(*contractDef));
return;
}
- MagicVariableDeclaration* magicVariable = dynamic_cast(m_referencedDeclaration);
+ MagicVariableDeclaration const* magicVariable = dynamic_cast(m_referencedDeclaration);
if (magicVariable)
{
m_type = magicVariable->getType();
@@ -562,7 +332,7 @@ void Identifier::checkTypeRequirements()
void ElementaryTypeNameExpression::checkTypeRequirements()
{
- m_type = make_shared(Type::fromElementaryTypeName(m_typeToken));
+ m_type = make_shared(Type::fromElementaryTypeName(m_typeToken));
}
void Literal::checkTypeRequirements()
diff --git a/libsolidity/AST.h b/libsolidity/AST.h
index d29e84a0a..0faea3fb9 100644
--- a/libsolidity/AST.h
+++ b/libsolidity/AST.h
@@ -39,6 +39,7 @@ namespace solidity
{
class ASTVisitor;
+class ASTConstVisitor;
/**
@@ -54,12 +55,19 @@ public:
virtual ~ASTNode() {}
virtual void accept(ASTVisitor& _visitor) = 0;
+ virtual void accept(ASTConstVisitor& _visitor) const = 0;
template
static void listAccept(std::vector>& _list, ASTVisitor& _visitor)
{
for (ASTPointer& element: _list)
element->accept(_visitor);
}
+ template
+ static void listAccept(std::vector> const& _list, ASTConstVisitor& _visitor)
+ {
+ for (ASTPointer const& element: _list)
+ element->accept(_visitor);
+ }
/// Returns the source code location of this node.
Location const& getLocation() const { return m_location; }
@@ -79,6 +87,44 @@ private:
Location m_location;
};
+/**
+ * Source unit containing import directives and contract definitions.
+ */
+class SourceUnit: public ASTNode
+{
+public:
+ SourceUnit(Location const& _location, std::vector> const& _nodes):
+ ASTNode(_location), m_nodes(_nodes) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ std::vector> getNodes() const { return m_nodes; }
+
+private:
+ std::vector> m_nodes;
+};
+
+/**
+ * Import directive for referencing other files / source objects.
+ * Example: import "abc.sol"
+ * Source objects are identified by a string which can be a file name but does not have to be.
+ */
+class ImportDirective: public ASTNode
+{
+public:
+ ImportDirective(Location const& _location, ASTPointer const& _identifier):
+ ASTNode(_location), m_identifier(_identifier) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ ASTString const& getIdentifier() const { return *m_identifier; }
+
+private:
+ ASTPointer m_identifier;
+};
+
/**
* Abstract AST class for a declaration (contract, function, struct, variable).
*/
@@ -86,18 +132,18 @@ class Declaration: public ASTNode
{
public:
Declaration(Location const& _location, ASTPointer const& _name):
- ASTNode(_location), m_name(_name) {}
+ ASTNode(_location), m_name(_name), m_scope(nullptr) {}
/// @returns the declared name.
ASTString const& getName() const { return *m_name; }
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
/// Available only after name and type resolution step.
- Declaration* getScope() const { return m_scope; }
- void setScope(Declaration* const& _scope) { m_scope = _scope; }
+ Declaration const* getScope() const { return m_scope; }
+ void setScope(Declaration const* _scope) { m_scope = _scope; }
private:
ASTPointer m_name;
- Declaration* m_scope;
+ Declaration const* m_scope;
};
/**
@@ -120,6 +166,7 @@ public:
{}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector> const& getDefinedStructs() const { return m_definedStructs; }
std::vector> const& getStateVariables() const { return m_stateVariables; }
@@ -142,16 +189,17 @@ public:
std::vector> const& _members):
Declaration(_location, _name), m_members(_members) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector> const& getMembers() const { return m_members; }
/// Checks that the members do not include any recursive structs and have valid types
/// (e.g. no functions).
- void checkValidityOfMembers();
+ void checkValidityOfMembers() const;
private:
- void checkMemberTypes();
- void checkRecursion();
+ void checkMemberTypes() const;
+ void checkRecursion() const;
std::vector> m_members;
};
@@ -168,6 +216,7 @@ public:
std::vector> const& _parameters):
ASTNode(_location), m_parameters(_parameters) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
std::vector> const& getParameters() const { return m_parameters; }
@@ -194,14 +243,15 @@ public:
{}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
bool isPublic() const { return m_isPublic; }
bool isDeclaredConst() const { return m_isDeclaredConst; }
std::vector> const& getParameters() const { return m_parameters->getParameters(); }
- ParameterList& getParameterList() { return *m_parameters; }
+ ParameterList const& getParameterList() const { return *m_parameters; }
std::vector> const& getReturnParameters() const { return m_returnParameters->getParameters(); }
ASTPointer const& getReturnParameterList() const { return m_returnParameters; }
- Block& getBody() { return *m_body; }
+ Block const& getBody() const { return *m_body; }
/// @return A shared pointer of an ASTString.
/// Can contain a nullptr in which case indicates absence of documentation
ASTPointer const& getDocumentation() const { return m_documentation; }
@@ -234,15 +284,16 @@ public:
ASTPointer const& _name):
Declaration(_location, _name), m_typeName(_type) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
- TypeName* getTypeName() const { return m_typeName.get(); }
+ TypeName const* getTypeName() const { return m_typeName.get(); }
/// Returns the declared or inferred type. Can be an empty pointer if no type was explicitly
/// declared and there is no assignment to the variable that fixes the type.
std::shared_ptr const& getType() const { return m_type; }
void setType(std::shared_ptr const& _type) { m_type = _type; }
- bool isLocalVariable() const { return !!dynamic_cast(getScope()); }
+ bool isLocalVariable() const { return !!dynamic_cast(getScope()); }
private:
ASTPointer m_typeName; ///< can be empty ("var")
@@ -261,6 +312,8 @@ public:
Declaration(Location(), std::make_shared(_name)), m_type(_type) {}
virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError()
<< errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
+ virtual void accept(ASTConstVisitor&) const override { BOOST_THROW_EXCEPTION(InternalCompilerError()
+ << errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
std::shared_ptr const& getType() const { return m_type; }
@@ -279,11 +332,12 @@ class TypeName: public ASTNode
public:
explicit TypeName(Location const& _location): ASTNode(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
/// Retrieve the element of the type hierarchy this node refers to. Can return an empty shared
/// pointer until the types have been resolved using the @ref NameAndTypeResolver.
/// If it returns an empty shared pointer after that, this indicates that the type was not found.
- virtual std::shared_ptr toType() const = 0;
+ virtual std::shared_ptr toType() const = 0;
};
/**
@@ -299,7 +353,8 @@ public:
if (asserts(Token::isElementaryTypeName(_type))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override;
- virtual std::shared_ptr toType() const override { return Type::fromElementaryTypeName(m_type); }
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+ virtual std::shared_ptr toType() const override { return Type::fromElementaryTypeName(m_type); }
Token::Value getTypeName() const { return m_type; }
@@ -314,18 +369,19 @@ class UserDefinedTypeName: public TypeName
{
public:
UserDefinedTypeName(Location const& _location, ASTPointer const& _name):
- TypeName(_location), m_name(_name) {}
+ TypeName(_location), m_name(_name), m_referencedDeclaration(nullptr) {}
virtual void accept(ASTVisitor& _visitor) override;
- virtual std::shared_ptr toType() const override { return Type::fromUserDefinedTypeName(*this); }
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+ virtual std::shared_ptr toType() const override { return Type::fromUserDefinedTypeName(*this); }
ASTString const& getName() const { return *m_name; }
- void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; }
+ void setReferencedDeclaration(Declaration const& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; }
Declaration const* getReferencedDeclaration() const { return m_referencedDeclaration; }
private:
ASTPointer m_name;
- Declaration* m_referencedDeclaration;
+ Declaration const* m_referencedDeclaration;
};
/**
@@ -338,7 +394,8 @@ public:
ASTPointer const& _valueType):
TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {}
virtual void accept(ASTVisitor& _visitor) override;
- virtual std::shared_ptr toType() const override { return Type::fromMapping(*this); }
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+ virtual std::shared_ptr toType() const override { return Type::fromMapping(*this); }
ElementaryTypeName const& getKeyType() const { return *m_keyType; }
TypeName const& getValueType() const { return *m_valueType; }
@@ -361,7 +418,6 @@ class Statement: public ASTNode
{
public:
explicit Statement(Location const& _location): ASTNode(_location) {}
- virtual void accept(ASTVisitor& _visitor) override;
/// Check all type requirements, throws exception if some requirement is not met.
/// This includes checking that operators are applicable to their arguments but also that
@@ -378,6 +434,7 @@ public:
Block(Location const& _location, std::vector> const& _statements):
Statement(_location), m_statements(_statements) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
@@ -397,12 +454,13 @@ public:
Statement(_location),
m_condition(_condition), m_trueBody(_trueBody), m_falseBody(_falseBody) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
- Expression& getCondition() const { return *m_condition; }
- Statement& getTrueStatement() const { return *m_trueBody; }
+ Expression const& getCondition() const { return *m_condition; }
+ Statement const& getTrueStatement() const { return *m_trueBody; }
/// @returns the "else" part of the if statement or nullptr if there is no "else" part.
- Statement* getFalseStatement() const { return m_falseBody.get(); }
+ Statement const* getFalseStatement() const { return m_falseBody.get(); }
private:
ASTPointer m_condition;
@@ -411,13 +469,12 @@ private:
};
/**
- * Statement in which a break statement is legal.
+ * Statement in which a break statement is legal (abstract class).
*/
class BreakableStatement: public Statement
{
public:
BreakableStatement(Location const& _location): Statement(_location) {}
- virtual void accept(ASTVisitor& _visitor) override;
};
class WhileStatement: public BreakableStatement
@@ -427,10 +484,11 @@ public:
ASTPointer const& _body):
BreakableStatement(_location), m_condition(_condition), m_body(_body) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
- Expression& getCondition() const { return *m_condition; }
- Statement& getBody() const { return *m_body; }
+ Expression const& getCondition() const { return *m_condition; }
+ Statement const& getBody() const { return *m_body; }
private:
ASTPointer m_condition;
@@ -442,6 +500,7 @@ class Continue: public Statement
public:
Continue(Location const& _location): Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override {}
};
@@ -450,6 +509,7 @@ class Break: public Statement
public:
Break(Location const& _location): Statement(_location) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override {}
};
@@ -457,8 +517,9 @@ class Return: public Statement
{
public:
Return(Location const& _location, ASTPointer _expression):
- Statement(_location), m_expression(_expression) {}
+ Statement(_location), m_expression(_expression), m_returnParameters(nullptr) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
void setFunctionReturnParameters(ParameterList& _parameters) { m_returnParameters = &_parameters; }
@@ -468,7 +529,7 @@ public:
BOOST_THROW_EXCEPTION(InternalCompilerError());
return *m_returnParameters;
}
- Expression* getExpression() const { return m_expression.get(); }
+ Expression const* getExpression() const { return m_expression.get(); }
private:
ASTPointer m_expression; ///< value to return, optional
@@ -489,10 +550,11 @@ public:
ASTPointer _value):
Statement(_location), m_variable(_variable), m_value(_value) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
VariableDeclaration const& getDeclaration() const { return *m_variable; }
- Expression* getExpression() const { return m_value.get(); }
+ Expression const* getExpression() const { return m_value.get(); }
private:
ASTPointer m_variable;
@@ -508,9 +570,10 @@ public:
ExpressionStatement(Location const& _location, ASTPointer _expression):
Statement(_location), m_expression(_expression) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
- Expression& getExpression() const { return *m_expression; }
+ Expression const& getExpression() const { return *m_expression; }
private:
ASTPointer m_expression;
@@ -572,11 +635,12 @@ public:
if (asserts(Token::isAssignmentOp(_assignmentOperator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
- Expression& getLeftHandSide() const { return *m_leftHandSide; }
+ Expression const& getLeftHandSide() const { return *m_leftHandSide; }
Token::Value getAssignmentOperator() const { return m_assigmentOperator; }
- Expression& getRightHandSide() const { return *m_rightHandSide; }
+ Expression const& getRightHandSide() const { return *m_rightHandSide; }
private:
ASTPointer m_leftHandSide;
@@ -599,11 +663,12 @@ public:
if (asserts(Token::isUnaryOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
Token::Value getOperator() const { return m_operator; }
bool isPrefixOperation() const { return m_isPrefix; }
- Expression& getSubExpression() const { return *m_subExpression; }
+ Expression const& getSubExpression() const { return *m_subExpression; }
private:
Token::Value m_operator;
@@ -625,10 +690,11 @@ public:
if (asserts(Token::isBinaryOp(_operator) || Token::isCompareOp(_operator))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
- Expression& getLeftExpression() const { return *m_left; }
- Expression& getRightExpression() const { return *m_right; }
+ Expression const& getLeftExpression() const { return *m_left; }
+ Expression const& getRightExpression() const { return *m_right; }
Token::Value getOperator() const { return m_operator; }
Type const& getCommonType() const { return *m_commonType; }
@@ -652,10 +718,11 @@ public:
std::vector> const& _arguments):
Expression(_location), m_expression(_expression), m_arguments(_arguments) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
- Expression& getExpression() const { return *m_expression; }
- std::vector> const& getArguments() const { return m_arguments; }
+ Expression const& getExpression() const { return *m_expression; }
+ std::vector> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; }
/// Returns true if this is not an actual function call, but an explicit type conversion
/// or constructor call.
@@ -676,7 +743,8 @@ public:
ASTPointer const& _memberName):
Expression(_location), m_expression(_expression), m_memberName(_memberName) {}
virtual void accept(ASTVisitor& _visitor) override;
- Expression& getExpression() const { return *m_expression; }
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+ Expression const& getExpression() const { return *m_expression; }
ASTString const& getMemberName() const { return *m_memberName; }
virtual void checkTypeRequirements() override;
@@ -695,10 +763,11 @@ public:
ASTPointer const& _index):
Expression(_location), m_base(_base), m_index(_index) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
- Expression& getBaseExpression() const { return *m_base; }
- Expression& getIndexExpression() const { return *m_index; }
+ Expression const& getBaseExpression() const { return *m_base; }
+ Expression const& getIndexExpression() const { return *m_index; }
private:
ASTPointer m_base;
@@ -722,20 +791,21 @@ class Identifier: public PrimaryExpression
{
public:
Identifier(Location const& _location, ASTPointer const& _name):
- PrimaryExpression(_location), m_name(_name) {}
+ PrimaryExpression(_location), m_name(_name), m_referencedDeclaration(nullptr) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
ASTString const& getName() const { return *m_name; }
- void setReferencedDeclaration(Declaration& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; }
- Declaration* getReferencedDeclaration() { return m_referencedDeclaration; }
+ void setReferencedDeclaration(Declaration const& _referencedDeclaration) { m_referencedDeclaration = &_referencedDeclaration; }
+ Declaration const* getReferencedDeclaration() const { return m_referencedDeclaration; }
private:
ASTPointer m_name;
/// Declaration the name refers to.
- Declaration* m_referencedDeclaration;
+ Declaration const* m_referencedDeclaration;
};
/**
@@ -752,6 +822,7 @@ public:
if (asserts(Token::isElementaryTypeName(_typeToken))) BOOST_THROW_EXCEPTION(InternalCompilerError());
}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
Token::Value getTypeToken() const { return m_typeToken; }
@@ -769,6 +840,7 @@ public:
Literal(Location const& _location, Token::Value _token, ASTPointer const& _value):
PrimaryExpression(_location), m_token(_token), m_value(_value) {}
virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
virtual void checkTypeRequirements() override;
Token::Value getToken() const { return m_token; }
diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h
index a369c8a79..8b4bac1ce 100644
--- a/libsolidity/ASTForward.h
+++ b/libsolidity/ASTForward.h
@@ -34,6 +34,8 @@ namespace solidity
{
class ASTNode;
+class SourceUnit;
+class ImportDirective;
class Declaration;
class ContractDefinition;
class StructDefinition;
diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp
index 987ad11cc..eddb51340 100644
--- a/libsolidity/ASTPrinter.cpp
+++ b/libsolidity/ASTPrinter.cpp
@@ -30,7 +30,7 @@ namespace dev
namespace solidity
{
-ASTPrinter::ASTPrinter(ASTNode& _ast, string const& _source):
+ASTPrinter::ASTPrinter(ASTNode const& _ast, string const& _source):
m_indentation(0), m_source(_source), m_ast(&_ast)
{
}
@@ -43,28 +43,35 @@ void ASTPrinter::print(ostream& _stream)
}
-bool ASTPrinter::visit(ContractDefinition& _node)
+bool ASTPrinter::visit(ImportDirective const& _node)
+{
+ writeLine("ImportDirective \"" + _node.getIdentifier() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ContractDefinition const& _node)
{
writeLine("ContractDefinition \"" + _node.getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(StructDefinition& _node)
+bool ASTPrinter::visit(StructDefinition const& _node)
{
writeLine("StructDefinition \"" + _node.getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(ParameterList& _node)
+bool ASTPrinter::visit(ParameterList const& _node)
{
writeLine("ParameterList");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(FunctionDefinition& _node)
+bool ASTPrinter::visit(FunctionDefinition const& _node)
{
writeLine("FunctionDefinition \"" + _node.getName() + "\"" +
(_node.isPublic() ? " - public" : "") +
@@ -73,112 +80,112 @@ bool ASTPrinter::visit(FunctionDefinition& _node)
return goDeeper();
}
-bool ASTPrinter::visit(VariableDeclaration& _node)
+bool ASTPrinter::visit(VariableDeclaration const& _node)
{
writeLine("VariableDeclaration \"" + _node.getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(TypeName& _node)
+bool ASTPrinter::visit(TypeName const& _node)
{
writeLine("TypeName");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(ElementaryTypeName& _node)
+bool ASTPrinter::visit(ElementaryTypeName const& _node)
{
writeLine(string("ElementaryTypeName ") + Token::toString(_node.getTypeName()));
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(UserDefinedTypeName& _node)
+bool ASTPrinter::visit(UserDefinedTypeName const& _node)
{
writeLine("UserDefinedTypeName \"" + _node.getName() + "\"");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(Mapping& _node)
+bool ASTPrinter::visit(Mapping const& _node)
{
writeLine("Mapping");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(Statement& _node)
+bool ASTPrinter::visit(Statement const& _node)
{
writeLine("Statement");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(Block& _node)
+bool ASTPrinter::visit(Block const& _node)
{
writeLine("Block");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(IfStatement& _node)
+bool ASTPrinter::visit(IfStatement const& _node)
{
writeLine("IfStatement");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(BreakableStatement& _node)
+bool ASTPrinter::visit(BreakableStatement const& _node)
{
writeLine("BreakableStatement");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(WhileStatement& _node)
+bool ASTPrinter::visit(WhileStatement const& _node)
{
writeLine("WhileStatement");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(Continue& _node)
+bool ASTPrinter::visit(Continue const& _node)
{
writeLine("Continue");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(Break& _node)
+bool ASTPrinter::visit(Break const& _node)
{
writeLine("Break");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(Return& _node)
+bool ASTPrinter::visit(Return const& _node)
{
writeLine("Return");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(VariableDefinition& _node)
+bool ASTPrinter::visit(VariableDefinition const& _node)
{
writeLine("VariableDefinition");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(ExpressionStatement& _node)
+bool ASTPrinter::visit(ExpressionStatement const& _node)
{
writeLine("ExpressionStatement");
printSourcePart(_node);
return goDeeper();
}
-bool ASTPrinter::visit(Expression& _node)
+bool ASTPrinter::visit(Expression const& _node)
{
writeLine("Expression");
printType(_node);
@@ -186,7 +193,7 @@ bool ASTPrinter::visit(Expression& _node)
return goDeeper();
}
-bool ASTPrinter::visit(Assignment& _node)
+bool ASTPrinter::visit(Assignment const& _node)
{
writeLine(string("Assignment using operator ") + Token::toString(_node.getAssignmentOperator()));
printType(_node);
@@ -194,7 +201,7 @@ bool ASTPrinter::visit(Assignment& _node)
return goDeeper();
}
-bool ASTPrinter::visit(UnaryOperation& _node)
+bool ASTPrinter::visit(UnaryOperation const& _node)
{
writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") +
") " + Token::toString(_node.getOperator()));
@@ -203,7 +210,7 @@ bool ASTPrinter::visit(UnaryOperation& _node)
return goDeeper();
}
-bool ASTPrinter::visit(BinaryOperation& _node)
+bool ASTPrinter::visit(BinaryOperation const& _node)
{
writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator()));
printType(_node);
@@ -211,7 +218,7 @@ bool ASTPrinter::visit(BinaryOperation& _node)
return goDeeper();
}
-bool ASTPrinter::visit(FunctionCall& _node)
+bool ASTPrinter::visit(FunctionCall const& _node)
{
writeLine("FunctionCall");
printType(_node);
@@ -219,7 +226,7 @@ bool ASTPrinter::visit(FunctionCall& _node)
return goDeeper();
}
-bool ASTPrinter::visit(MemberAccess& _node)
+bool ASTPrinter::visit(MemberAccess const& _node)
{
writeLine("MemberAccess to member " + _node.getMemberName());
printType(_node);
@@ -227,7 +234,7 @@ bool ASTPrinter::visit(MemberAccess& _node)
return goDeeper();
}
-bool ASTPrinter::visit(IndexAccess& _node)
+bool ASTPrinter::visit(IndexAccess const& _node)
{
writeLine("IndexAccess");
printType(_node);
@@ -235,7 +242,7 @@ bool ASTPrinter::visit(IndexAccess& _node)
return goDeeper();
}
-bool ASTPrinter::visit(PrimaryExpression& _node)
+bool ASTPrinter::visit(PrimaryExpression const& _node)
{
writeLine("PrimaryExpression");
printType(_node);
@@ -243,7 +250,7 @@ bool ASTPrinter::visit(PrimaryExpression& _node)
return goDeeper();
}
-bool ASTPrinter::visit(Identifier& _node)
+bool ASTPrinter::visit(Identifier const& _node)
{
writeLine(string("Identifier ") + _node.getName());
printType(_node);
@@ -251,7 +258,7 @@ bool ASTPrinter::visit(Identifier& _node)
return goDeeper();
}
-bool ASTPrinter::visit(ElementaryTypeNameExpression& _node)
+bool ASTPrinter::visit(ElementaryTypeNameExpression const& _node)
{
writeLine(string("ElementaryTypeNameExpression ") + Token::toString(_node.getTypeToken()));
printType(_node);
@@ -259,7 +266,7 @@ bool ASTPrinter::visit(ElementaryTypeNameExpression& _node)
return goDeeper();
}
-bool ASTPrinter::visit(Literal& _node)
+bool ASTPrinter::visit(Literal const& _node)
{
char const* tokenString = Token::toString(_node.getToken());
if (!tokenString)
@@ -270,157 +277,157 @@ bool ASTPrinter::visit(Literal& _node)
return goDeeper();
}
-void ASTPrinter::endVisit(ASTNode&)
+void ASTPrinter::endVisit(ImportDirective const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(ContractDefinition&)
+void ASTPrinter::endVisit(ContractDefinition const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(StructDefinition&)
+void ASTPrinter::endVisit(StructDefinition const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(ParameterList&)
+void ASTPrinter::endVisit(ParameterList const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(FunctionDefinition&)
+void ASTPrinter::endVisit(FunctionDefinition const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(VariableDeclaration&)
+void ASTPrinter::endVisit(VariableDeclaration const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(TypeName&)
+void ASTPrinter::endVisit(TypeName const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(ElementaryTypeName&)
+void ASTPrinter::endVisit(ElementaryTypeName const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(UserDefinedTypeName&)
+void ASTPrinter::endVisit(UserDefinedTypeName const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Mapping&)
+void ASTPrinter::endVisit(Mapping const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Statement&)
+void ASTPrinter::endVisit(Statement const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Block&)
+void ASTPrinter::endVisit(Block const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(IfStatement&)
+void ASTPrinter::endVisit(IfStatement const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(BreakableStatement&)
+void ASTPrinter::endVisit(BreakableStatement const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(WhileStatement&)
+void ASTPrinter::endVisit(WhileStatement const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Continue&)
+void ASTPrinter::endVisit(Continue const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Break&)
+void ASTPrinter::endVisit(Break const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Return&)
+void ASTPrinter::endVisit(Return const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(VariableDefinition&)
+void ASTPrinter::endVisit(VariableDefinition const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(ExpressionStatement&)
+void ASTPrinter::endVisit(ExpressionStatement const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Expression&)
+void ASTPrinter::endVisit(Expression const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Assignment&)
+void ASTPrinter::endVisit(Assignment const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(UnaryOperation&)
+void ASTPrinter::endVisit(UnaryOperation const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(BinaryOperation&)
+void ASTPrinter::endVisit(BinaryOperation const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(FunctionCall&)
+void ASTPrinter::endVisit(FunctionCall const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(MemberAccess&)
+void ASTPrinter::endVisit(MemberAccess const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(IndexAccess&)
+void ASTPrinter::endVisit(IndexAccess const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(PrimaryExpression&)
+void ASTPrinter::endVisit(PrimaryExpression const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Identifier&)
+void ASTPrinter::endVisit(Identifier const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(ElementaryTypeNameExpression&)
+void ASTPrinter::endVisit(ElementaryTypeNameExpression const&)
{
m_indentation--;
}
-void ASTPrinter::endVisit(Literal&)
+void ASTPrinter::endVisit(Literal const&)
{
m_indentation--;
}
diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h
index e0757fbc4..5a9187154 100644
--- a/libsolidity/ASTPrinter.h
+++ b/libsolidity/ASTPrinter.h
@@ -33,77 +33,78 @@ namespace solidity
/**
* Pretty-printer for the abstract syntax tree (the "pretty" is arguable) for debugging purposes.
*/
-class ASTPrinter: public ASTVisitor
+class ASTPrinter: public ASTConstVisitor
{
public:
/// Create a printer for the given abstract syntax tree. If the source is specified,
/// the corresponding parts of the source are printed with each node.
- ASTPrinter(ASTNode& _ast, std::string const& _source = std::string());
+ ASTPrinter(ASTNode const& _ast, std::string const& _source = std::string());
/// Output the string representation of the AST to _stream.
void print(std::ostream& _stream);
- bool visit(ContractDefinition& _node) override;
- bool visit(StructDefinition& _node) override;
- bool visit(ParameterList& _node) override;
- bool visit(FunctionDefinition& _node) override;
- bool visit(VariableDeclaration& _node) override;
- bool visit(TypeName& _node) override;
- bool visit(ElementaryTypeName& _node) override;
- bool visit(UserDefinedTypeName& _node) override;
- bool visit(Mapping& _node) override;
- bool visit(Statement& _node) override;
- bool visit(Block& _node) override;
- bool visit(IfStatement& _node) override;
- bool visit(BreakableStatement& _node) override;
- bool visit(WhileStatement& _node) override;
- bool visit(Continue& _node) override;
- bool visit(Break& _node) override;
- bool visit(Return& _node) override;
- bool visit(VariableDefinition& _node) override;
- bool visit(ExpressionStatement& _node) override;
- bool visit(Expression& _node) override;
- bool visit(Assignment& _node) override;
- bool visit(UnaryOperation& _node) override;
- bool visit(BinaryOperation& _node) override;
- bool visit(FunctionCall& _node) override;
- bool visit(MemberAccess& _node) override;
- bool visit(IndexAccess& _node) override;
- bool visit(PrimaryExpression& _node) override;
- bool visit(Identifier& _node) override;
- bool visit(ElementaryTypeNameExpression& _node) override;
- bool visit(Literal& _node) override;
+ bool visit(ImportDirective const& _node) override;
+ bool visit(ContractDefinition const& _node) override;
+ bool visit(StructDefinition const& _node) override;
+ bool visit(ParameterList const& _node) override;
+ bool visit(FunctionDefinition const& _node) override;
+ bool visit(VariableDeclaration const& _node) override;
+ bool visit(TypeName const& _node) override;
+ bool visit(ElementaryTypeName const& _node) override;
+ bool visit(UserDefinedTypeName const& _node) override;
+ bool visit(Mapping const& _node) override;
+ bool visit(Statement const& _node) override;
+ bool visit(Block const& _node) override;
+ bool visit(IfStatement const& _node) override;
+ bool visit(BreakableStatement const& _node) override;
+ bool visit(WhileStatement const& _node) override;
+ bool visit(Continue const& _node) override;
+ bool visit(Break const& _node) override;
+ bool visit(Return const& _node) override;
+ bool visit(VariableDefinition const& _node) override;
+ bool visit(ExpressionStatement const& _node) override;
+ bool visit(Expression const& _node) override;
+ bool visit(Assignment const& _node) override;
+ bool visit(UnaryOperation const& _node) override;
+ bool visit(BinaryOperation const& _node) override;
+ bool visit(FunctionCall const& _node) override;
+ bool visit(MemberAccess const& _node) override;
+ bool visit(IndexAccess const& _node) override;
+ bool visit(PrimaryExpression const& _node) override;
+ bool visit(Identifier const& _node) override;
+ bool visit(ElementaryTypeNameExpression const& _node) override;
+ bool visit(Literal const& _node) override;
- void endVisit(ASTNode& _node) override;
- void endVisit(ContractDefinition&) override;
- void endVisit(StructDefinition&) override;
- void endVisit(ParameterList&) override;
- void endVisit(FunctionDefinition&) override;
- void endVisit(VariableDeclaration&) override;
- void endVisit(TypeName&) override;
- void endVisit(ElementaryTypeName&) override;
- void endVisit(UserDefinedTypeName&) override;
- void endVisit(Mapping&) override;
- void endVisit(Statement&) override;
- void endVisit(Block&) override;
- void endVisit(IfStatement&) override;
- void endVisit(BreakableStatement&) override;
- void endVisit(WhileStatement&) override;
- void endVisit(Continue&) override;
- void endVisit(Break&) override;
- void endVisit(Return&) override;
- void endVisit(VariableDefinition&) override;
- void endVisit(ExpressionStatement&) override;
- void endVisit(Expression&) override;
- void endVisit(Assignment&) override;
- void endVisit(UnaryOperation&) override;
- void endVisit(BinaryOperation&) override;
- void endVisit(FunctionCall&) override;
- void endVisit(MemberAccess&) override;
- void endVisit(IndexAccess&) override;
- void endVisit(PrimaryExpression&) override;
- void endVisit(Identifier&) override;
- void endVisit(ElementaryTypeNameExpression&) override;
- void endVisit(Literal&) override;
+ void endVisit(ImportDirective const&) override;
+ void endVisit(ContractDefinition const&) override;
+ void endVisit(StructDefinition const&) override;
+ void endVisit(ParameterList const&) override;
+ void endVisit(FunctionDefinition const&) override;
+ void endVisit(VariableDeclaration const&) override;
+ void endVisit(TypeName const&) override;
+ void endVisit(ElementaryTypeName const&) override;
+ void endVisit(UserDefinedTypeName const&) override;
+ void endVisit(Mapping const&) override;
+ void endVisit(Statement const&) override;
+ void endVisit(Block const&) override;
+ void endVisit(IfStatement const&) override;
+ void endVisit(BreakableStatement const&) override;
+ void endVisit(WhileStatement const&) override;
+ void endVisit(Continue const&) override;
+ void endVisit(Break const&) override;
+ void endVisit(Return const&) override;
+ void endVisit(VariableDefinition const&) override;
+ void endVisit(ExpressionStatement const&) override;
+ void endVisit(Expression const&) override;
+ void endVisit(Assignment const&) override;
+ void endVisit(UnaryOperation const&) override;
+ void endVisit(BinaryOperation const&) override;
+ void endVisit(FunctionCall const&) override;
+ void endVisit(MemberAccess const&) override;
+ void endVisit(IndexAccess const&) override;
+ void endVisit(PrimaryExpression const&) override;
+ void endVisit(Identifier const&) override;
+ void endVisit(ElementaryTypeNameExpression const&) override;
+ void endVisit(Literal const&) override;
private:
void printSourcePart(ASTNode const& _node);
@@ -114,7 +115,7 @@ private:
int m_indentation;
std::string m_source;
- ASTNode* m_ast;
+ ASTNode const* m_ast;
std::ostream* m_ostream;
};
diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h
index 6e579f358..4e1a49458 100644
--- a/libsolidity/ASTVisitor.h
+++ b/libsolidity/ASTVisitor.h
@@ -42,6 +42,8 @@ class ASTVisitor
{
public:
virtual bool visit(ASTNode&) { return true; }
+ virtual bool visit(SourceUnit&) { return true; }
+ virtual bool visit(ImportDirective&) { return true; }
virtual bool visit(ContractDefinition&) { return true; }
virtual bool visit(StructDefinition&) { return true; }
virtual bool visit(ParameterList&) { return true; }
@@ -74,6 +76,8 @@ public:
virtual bool visit(Literal&) { return true; }
virtual void endVisit(ASTNode&) { }
+ virtual void endVisit(SourceUnit&) { }
+ virtual void endVisit(ImportDirective&) { }
virtual void endVisit(ContractDefinition&) { }
virtual void endVisit(StructDefinition&) { }
virtual void endVisit(ParameterList&) { }
@@ -106,5 +110,77 @@ public:
virtual void endVisit(Literal&) { }
};
+class ASTConstVisitor
+{
+public:
+ virtual bool visit(ASTNode const&) { return true; }
+ virtual bool visit(SourceUnit const&) { return true; }
+ virtual bool visit(ImportDirective const&) { return true; }
+ virtual bool visit(ContractDefinition const&) { return true; }
+ virtual bool visit(StructDefinition const&) { return true; }
+ virtual bool visit(ParameterList const&) { return true; }
+ virtual bool visit(FunctionDefinition const&) { return true; }
+ virtual bool visit(VariableDeclaration const&) { return true; }
+ virtual bool visit(TypeName const&) { return true; }
+ virtual bool visit(ElementaryTypeName const&) { return true; }
+ virtual bool visit(UserDefinedTypeName const&) { return true; }
+ virtual bool visit(Mapping const&) { return true; }
+ virtual bool visit(Statement const&) { return true; }
+ virtual bool visit(Block const&) { return true; }
+ virtual bool visit(IfStatement const&) { return true; }
+ virtual bool visit(BreakableStatement const&) { return true; }
+ virtual bool visit(WhileStatement const&) { return true; }
+ virtual bool visit(Continue const&) { return true; }
+ virtual bool visit(Break const&) { return true; }
+ virtual bool visit(Return const&) { return true; }
+ virtual bool visit(VariableDefinition const&) { return true; }
+ virtual bool visit(ExpressionStatement const&) { return true; }
+ virtual bool visit(Expression const&) { return true; }
+ virtual bool visit(Assignment const&) { return true; }
+ virtual bool visit(UnaryOperation const&) { return true; }
+ virtual bool visit(BinaryOperation const&) { return true; }
+ virtual bool visit(FunctionCall const&) { return true; }
+ virtual bool visit(MemberAccess const&) { return true; }
+ virtual bool visit(IndexAccess const&) { return true; }
+ virtual bool visit(PrimaryExpression const&) { return true; }
+ virtual bool visit(Identifier const&) { return true; }
+ virtual bool visit(ElementaryTypeNameExpression const&) { return true; }
+ virtual bool visit(Literal const&) { return true; }
+
+ virtual void endVisit(ASTNode const&) { }
+ virtual void endVisit(SourceUnit const&) { }
+ virtual void endVisit(ImportDirective const&) { }
+ virtual void endVisit(ContractDefinition const&) { }
+ virtual void endVisit(StructDefinition const&) { }
+ virtual void endVisit(ParameterList const&) { }
+ virtual void endVisit(FunctionDefinition const&) { }
+ virtual void endVisit(VariableDeclaration const&) { }
+ virtual void endVisit(TypeName const&) { }
+ virtual void endVisit(ElementaryTypeName const&) { }
+ virtual void endVisit(UserDefinedTypeName const&) { }
+ virtual void endVisit(Mapping const&) { }
+ virtual void endVisit(Statement const&) { }
+ virtual void endVisit(Block const&) { }
+ virtual void endVisit(IfStatement const&) { }
+ virtual void endVisit(BreakableStatement const&) { }
+ virtual void endVisit(WhileStatement const&) { }
+ virtual void endVisit(Continue const&) { }
+ virtual void endVisit(Break const&) { }
+ virtual void endVisit(Return const&) { }
+ virtual void endVisit(VariableDefinition const&) { }
+ virtual void endVisit(ExpressionStatement const&) { }
+ virtual void endVisit(Expression const&) { }
+ virtual void endVisit(Assignment const&) { }
+ virtual void endVisit(UnaryOperation const&) { }
+ virtual void endVisit(BinaryOperation const&) { }
+ virtual void endVisit(FunctionCall const&) { }
+ virtual void endVisit(MemberAccess const&) { }
+ virtual void endVisit(IndexAccess const&) { }
+ virtual void endVisit(PrimaryExpression const&) { }
+ virtual void endVisit(Identifier const&) { }
+ virtual void endVisit(ElementaryTypeNameExpression const&) { }
+ virtual void endVisit(Literal const&) { }
+};
+
}
}
diff --git a/libsolidity/AST_accept.h b/libsolidity/AST_accept.h
new file mode 100644
index 000000000..173273c6d
--- /dev/null
+++ b/libsolidity/AST_accept.h
@@ -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 .
+*/
+/**
+ * @author Christian
+ * @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
+#include
+
+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);
+}
+
+}
+}
diff --git a/libsolidity/BaseTypes.h b/libsolidity/BaseTypes.h
index d1ffd7bbc..a8fd77c86 100644
--- a/libsolidity/BaseTypes.h
+++ b/libsolidity/BaseTypes.h
@@ -22,6 +22,8 @@
#pragma once
+#include
+#include
#include
namespace dev
@@ -35,19 +37,19 @@ namespace solidity
*/
struct Location
{
- Location(int _start, int _end): start(_start), end(_end) { }
+ Location(int _start, int _end, std::shared_ptr _sourceName):
+ start(_start), end(_end), sourceName(_sourceName) { }
Location(): start(-1), end(-1) { }
- bool IsValid() const { return start >= 0 && end >= start; }
-
int start;
int end;
+ std::shared_ptr sourceName;
};
/// Stream output for Location (used e.g. in boost exceptions).
inline std::ostream& operator<<(std::ostream& _out, Location const& _location)
{
- return _out << "[" << _location.start << "," << _location.end << ")";
+ return _out << *_location.sourceName << "[" << _location.start << "," << _location.end << ")";
}
}
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index 17ad4fd16..b094af194 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -26,13 +26,14 @@
#include
#include
#include
+#include
using namespace std;
namespace dev {
namespace solidity {
-void Compiler::compileContract(ContractDefinition& _contract, vector const& _magicGlobals)
+void Compiler::compileContract(ContractDefinition const& _contract, vector const& _magicGlobals)
{
m_context = CompilerContext(); // clear it just in case
@@ -135,7 +136,7 @@ unsigned Compiler::appendCalldataUnpacker(FunctionDefinition const& _function, b
for (ASTPointer const& var: _function.getParameters())
{
unsigned const numBytes = var->getType()->getCalldataEncodedSize();
- if (numBytes == 0)
+ if (numBytes == 0 || numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(var->getLocation())
<< errinfo_comment("Type " + var->getType()->toString() + " not yet supported."));
@@ -154,18 +155,20 @@ void Compiler::appendReturnValuePacker(FunctionDefinition const& _function)
//@todo this can be also done more efficiently
unsigned dataOffset = 0;
vector> const& parameters = _function.getReturnParameters();
+ unsigned stackDepth = CompilerUtils(m_context).getSizeOnStack(parameters);
for (unsigned i = 0; i < parameters.size(); ++i)
{
Type const& paramType = *parameters[i]->getType();
unsigned numBytes = paramType.getCalldataEncodedSize();
- if (numBytes == 0)
+ if (numBytes == 0 || numBytes > 32)
BOOST_THROW_EXCEPTION(CompilerError()
<< errinfo_sourceLocation(parameters[i]->getLocation())
<< errinfo_comment("Type " + paramType.toString() + " not yet supported."));
- m_context << eth::dupInstruction(parameters.size() - i);
+ CompilerUtils(m_context).copyToStackTop(stackDepth, paramType);
if (numBytes != 32)
m_context << (u256(1) << ((32 - numBytes) * 8)) << eth::Instruction::MUL;
m_context << u256(dataOffset) << eth::Instruction::MSTORE;
+ stackDepth -= paramType.getSizeOnStack();
dataOffset += numBytes;
}
// note that the stack is not cleaned up here
@@ -179,7 +182,7 @@ void Compiler::registerStateVariables(ContractDefinition const& _contract)
m_context.addStateVariable(*variable);
}
-bool Compiler::visit(FunctionDefinition& _function)
+bool Compiler::visit(FunctionDefinition const& _function)
{
//@todo to simplify this, the calling convention could by changed such that
// caller puts: [retarg0] ... [retargm] [return address] [arg0] ... [argn]
@@ -195,15 +198,12 @@ bool Compiler::visit(FunctionDefinition& _function)
// stack upon entry: [return address] [arg0] [arg1] ... [argn]
// reserve additional slots: [retarg0] ... [retargm] [localvar0] ... [localvarp]
- unsigned const numArguments = _function.getParameters().size();
- unsigned const numReturnValues = _function.getReturnParameters().size();
- unsigned const numLocalVariables = _function.getLocalVariables().size();
-
- for (ASTPointer const& variable: _function.getParameters() + _function.getReturnParameters())
+ for (ASTPointer const& variable: _function.getParameters())
m_context.addVariable(*variable);
+ for (ASTPointer const& variable: _function.getReturnParameters())
+ m_context.addAndInitializeVariable(*variable);
for (VariableDeclaration const* localVariable: _function.getLocalVariables())
- m_context.addVariable(*localVariable);
- m_context.initializeLocalVariables(numReturnValues + numLocalVariables);
+ m_context.addAndInitializeVariable(*localVariable);
_function.getBody().accept(*this);
@@ -215,12 +215,16 @@ bool Compiler::visit(FunctionDefinition& _function)
// Note that the fact that the return arguments are of increasing index is vital for this
// algorithm to work.
+ unsigned const argumentsSize = CompilerUtils::getSizeOnStack(_function.getParameters());
+ unsigned const returnValuesSize = CompilerUtils::getSizeOnStack(_function.getReturnParameters());
+ unsigned const localVariablesSize = CompilerUtils::getSizeOnStack(_function.getLocalVariables());
+
vector stackLayout;
- stackLayout.push_back(numReturnValues); // target of return address
- stackLayout += vector(numArguments, -1); // discard all arguments
- for (unsigned i = 0; i < numReturnValues; ++i)
+ stackLayout.push_back(returnValuesSize); // target of return address
+ stackLayout += vector(argumentsSize, -1); // discard all arguments
+ for (unsigned i = 0; i < returnValuesSize; ++i)
stackLayout.push_back(i);
- stackLayout += vector(numLocalVariables, -1);
+ stackLayout += vector(localVariablesSize, -1);
while (stackLayout.back() != int(stackLayout.size() - 1))
if (stackLayout.back() < 0)
@@ -240,7 +244,7 @@ bool Compiler::visit(FunctionDefinition& _function)
return false;
}
-bool Compiler::visit(IfStatement& _ifStatement)
+bool Compiler::visit(IfStatement const& _ifStatement)
{
ExpressionCompiler::compileExpression(m_context, _ifStatement.getCondition());
eth::AssemblyItem trueTag = m_context.appendConditionalJump();
@@ -253,7 +257,7 @@ bool Compiler::visit(IfStatement& _ifStatement)
return false;
}
-bool Compiler::visit(WhileStatement& _whileStatement)
+bool Compiler::visit(WhileStatement const& _whileStatement)
{
eth::AssemblyItem loopStart = m_context.newTag();
eth::AssemblyItem loopEnd = m_context.newTag();
@@ -275,58 +279,53 @@ bool Compiler::visit(WhileStatement& _whileStatement)
return false;
}
-bool Compiler::visit(Continue&)
+bool Compiler::visit(Continue const&)
{
if (!m_continueTags.empty())
m_context.appendJumpTo(m_continueTags.back());
return false;
}
-bool Compiler::visit(Break&)
+bool Compiler::visit(Break const&)
{
if (!m_breakTags.empty())
m_context.appendJumpTo(m_breakTags.back());
return false;
}
-bool Compiler::visit(Return& _return)
+bool Compiler::visit(Return const& _return)
{
//@todo modifications are needed to make this work with functions returning multiple values
- if (Expression* expression = _return.getExpression())
+ if (Expression const* expression = _return.getExpression())
{
ExpressionCompiler::compileExpression(m_context, *expression);
VariableDeclaration const& firstVariable = *_return.getFunctionReturnParameters().getParameters().front();
ExpressionCompiler::appendTypeConversion(m_context, *expression->getType(), *firstVariable.getType());
- unsigned stackPosition = m_context.baseToCurrentStackOffset(m_context.getBaseStackOffsetOfVariable(firstVariable));
- m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP;
+ CompilerUtils(m_context).moveToStackVariable(firstVariable);
}
m_context.appendJumpTo(m_returnTag);
return false;
}
-bool Compiler::visit(VariableDefinition& _variableDefinition)
+bool Compiler::visit(VariableDefinition const& _variableDefinition)
{
- if (Expression* expression = _variableDefinition.getExpression())
+ if (Expression const* expression = _variableDefinition.getExpression())
{
ExpressionCompiler::compileExpression(m_context, *expression);
ExpressionCompiler::appendTypeConversion(m_context,
*expression->getType(),
*_variableDefinition.getDeclaration().getType());
- unsigned baseStackOffset = m_context.getBaseStackOffsetOfVariable(_variableDefinition.getDeclaration());
- unsigned stackPosition = m_context.baseToCurrentStackOffset(baseStackOffset);
- m_context << eth::swapInstruction(stackPosition) << eth::Instruction::POP;
+ CompilerUtils(m_context).moveToStackVariable(_variableDefinition.getDeclaration());
}
return false;
}
-bool Compiler::visit(ExpressionStatement& _expressionStatement)
+bool Compiler::visit(ExpressionStatement const& _expressionStatement)
{
- Expression& expression = _expressionStatement.getExpression();
+ Expression const& expression = _expressionStatement.getExpression();
ExpressionCompiler::compileExpression(m_context, expression);
-// Type::Category category = expression.getType()->getCategory();
- for (unsigned i = 0; i < expression.getType()->getSizeOnStack(); ++i)
- m_context << eth::Instruction::POP;
+ CompilerUtils(m_context).popStackElement(*expression.getType());
return false;
}
diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h
index 70e6c44f2..4b8f02c5d 100644
--- a/libsolidity/Compiler.h
+++ b/libsolidity/Compiler.h
@@ -27,12 +27,12 @@
namespace dev {
namespace solidity {
-class Compiler: private ASTVisitor
+class Compiler: private ASTConstVisitor
{
public:
Compiler(): m_returnTag(m_context.newTag()) {}
- void compileContract(ContractDefinition& _contract, std::vector const& _magicGlobals);
+ void compileContract(ContractDefinition const& _contract, std::vector const& _magicGlobals);
bytes getAssembledBytecode(bool _optimize = false) { return m_context.getAssembledBytecode(_optimize); }
void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); }
@@ -48,14 +48,14 @@ private:
void registerStateVariables(ContractDefinition const& _contract);
- virtual bool visit(FunctionDefinition& _function) override;
- virtual bool visit(IfStatement& _ifStatement) override;
- virtual bool visit(WhileStatement& _whileStatement) override;
- virtual bool visit(Continue& _continue) override;
- virtual bool visit(Break& _break) override;
- virtual bool visit(Return& _return) override;
- virtual bool visit(VariableDefinition& _variableDefinition) override;
- virtual bool visit(ExpressionStatement& _expressionStatement) override;
+ virtual bool visit(FunctionDefinition const& _function) override;
+ virtual bool visit(IfStatement const& _ifStatement) override;
+ virtual bool visit(WhileStatement const& _whileStatement) override;
+ virtual bool visit(Continue const& _continue) override;
+ virtual bool visit(Break const& _break) override;
+ virtual bool visit(Return const& _return) override;
+ virtual bool visit(VariableDefinition const& _variableDefinition) override;
+ virtual bool visit(ExpressionStatement const& _expressionStatement) override;
CompilerContext m_context;
diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp
index b89a8e5b5..cd22c4e8b 100644
--- a/libsolidity/CompilerContext.cpp
+++ b/libsolidity/CompilerContext.cpp
@@ -41,20 +41,30 @@ void CompilerContext::addStateVariable(VariableDeclaration const& _declaration)
m_stateVariablesSize += _declaration.getType()->getStorageSize();
}
-void CompilerContext::initializeLocalVariables(unsigned _numVariables)
+void CompilerContext::addVariable(VariableDeclaration const& _declaration)
{
- if (_numVariables > 0)
- {
+ m_localVariables[&_declaration] = m_localVariablesSize;
+ m_localVariablesSize += _declaration.getType()->getSizeOnStack();
+}
+
+void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration)
+{
+ addVariable(_declaration);
+
+ unsigned const size = _declaration.getType()->getSizeOnStack();
+ for (unsigned i = 0; i < size; ++i)
*this << u256(0);
- for (unsigned i = 1; i < _numVariables; ++i)
- *this << eth::Instruction::DUP1;
- m_asm.adjustDeposit(-_numVariables);
- }
+ m_asm.adjustDeposit(-size);
+}
+
+void CompilerContext::addFunction(FunctionDefinition const& _function)
+{
+ m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag()));
}
bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
{
- return std::find(m_localVariables.begin(), m_localVariables.end(), _declaration) != m_localVariables.end();
+ return m_localVariables.count(_declaration) > 0;
}
eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition const& _function) const
@@ -67,10 +77,10 @@ eth::AssemblyItem CompilerContext::getFunctionEntryLabel(FunctionDefinition cons
unsigned CompilerContext::getBaseStackOffsetOfVariable(Declaration const& _declaration) const
{
- auto res = find(begin(m_localVariables), end(m_localVariables), &_declaration);
+ auto res = m_localVariables.find(&_declaration);
if (asserts(res != m_localVariables.end()))
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Variable not found on stack."));
- return unsigned(end(m_localVariables) - res - 1);
+ return m_localVariablesSize - res->second - 1;
}
unsigned CompilerContext::baseToCurrentStackOffset(unsigned _baseOffset) const
diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h
index 6a48e1485..652e65a63 100644
--- a/libsolidity/CompilerContext.h
+++ b/libsolidity/CompilerContext.h
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
namespace dev {
@@ -43,9 +44,9 @@ public:
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
void addStateVariable(VariableDeclaration const& _declaration);
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
- void initializeLocalVariables(unsigned _numVariables);
- void addVariable(VariableDeclaration const& _declaration) { m_localVariables.push_back(&_declaration); }
- void addFunction(FunctionDefinition const& _function) { m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag())); }
+ void addVariable(VariableDeclaration const& _declaration);
+ void addAndInitializeVariable(VariableDeclaration const& _declaration);
+ void addFunction(FunctionDefinition const& _function);
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
@@ -98,8 +99,10 @@ private:
u256 m_stateVariablesSize;
/// Storage offsets of state variables
std::map m_stateVariables;
- /// Offsets of local variables on the stack.
- std::vector m_localVariables;
+ /// Offsets of local variables on the stack (relative to stack base).
+ std::map m_localVariables;
+ /// Sum of stack sizes of local variables
+ unsigned m_localVariablesSize;
/// Labels pointing to the entry points of funcitons.
std::map m_functionEntryLabels;
};
diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp
index c83257a1d..d46754856 100644
--- a/libsolidity/CompilerStack.cpp
+++ b/libsolidity/CompilerStack.cpp
@@ -36,22 +36,43 @@ namespace dev
namespace solidity
{
-CompilerStack::CompilerStack(): m_interfaceHandler(make_shared()) {}
+void CompilerStack::addSource(string const& _name, string const& _content)
+{
+ if (m_sources.count(_name))
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source by given name already exists."));
+
+ reset(true);
+ m_sources[_name].scanner = make_shared(CharStream(_content), _name);
+}
void CompilerStack::setSource(string const& _sourceCode)
{
reset();
- m_scanner = make_shared(CharStream(_sourceCode));
+ addSource("", _sourceCode);
}
void CompilerStack::parse()
{
- if (!m_scanner)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source not available."));
- m_contractASTNode = Parser().parse(m_scanner);
+ for (auto& sourcePair: m_sources)
+ {
+ sourcePair.second.scanner->reset();
+ sourcePair.second.ast = Parser().parse(sourcePair.second.scanner);
+ }
+ resolveImports();
+
m_globalContext = make_shared();
- m_globalContext->setCurrentContract(*m_contractASTNode);
- NameAndTypeResolver(m_globalContext->getDeclarations()).resolveNamesAndTypes(*m_contractASTNode);
+ NameAndTypeResolver resolver(m_globalContext->getDeclarations());
+ for (Source const* source: m_sourceOrder)
+ resolver.registerDeclarations(*source->ast);
+ for (Source const* source: m_sourceOrder)
+ for (ASTPointer const& node: source->ast->getNodes())
+ if (ContractDefinition* contract = dynamic_cast(node.get()))
+ {
+ m_globalContext->setCurrentContract(*contract);
+ resolver.updateDeclaration(*m_globalContext->getCurrentThis());
+ resolver.resolveNamesAndTypes(*contract);
+ m_contracts[contract->getName()].contract = contract;
+ }
m_parseSuccessful = true;
}
@@ -61,54 +82,90 @@ void CompilerStack::parse(string const& _sourceCode)
parse();
}
-bytes const& CompilerStack::compile(bool _optimize)
+vector CompilerStack::getContractNames() const
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
- m_bytecode.clear();
- m_compiler = make_shared();
- m_compiler->compileContract(*m_contractASTNode, m_globalContext->getMagicVariables());
- return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
+ vector contractNames;
+ for (auto const& contract: m_contracts)
+ contractNames.push_back(contract.first);
+ return contractNames;
+}
+
+void CompilerStack::compile(bool _optimize)
+{
+ if (!m_parseSuccessful)
+ parse();
+ for (Source const* source: m_sourceOrder)
+ for (ASTPointer const& node: source->ast->getNodes())
+ if (ContractDefinition* contract = dynamic_cast(node.get()))
+ {
+ m_globalContext->setCurrentContract(*contract);
+ shared_ptr