mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #288 from chriseth/import_contexts
Do not clutter importee when importing.
This commit is contained in:
commit
591a4f1ff4
@ -28,15 +28,19 @@ using namespace std;
|
|||||||
using namespace dev;
|
using namespace dev;
|
||||||
using namespace dev::solidity;
|
using namespace dev::solidity;
|
||||||
|
|
||||||
Declaration const* DeclarationContainer::conflictingDeclaration(Declaration const& _declaration) const
|
Declaration const* DeclarationContainer::conflictingDeclaration(
|
||||||
|
Declaration const& _declaration,
|
||||||
|
ASTString const* _name
|
||||||
|
) const
|
||||||
{
|
{
|
||||||
ASTString const& declarationName(_declaration.name());
|
if (!_name)
|
||||||
solAssert(!declarationName.empty(), "");
|
_name = &_declaration.name();
|
||||||
|
solAssert(!_name->empty(), "");
|
||||||
vector<Declaration const*> declarations;
|
vector<Declaration const*> declarations;
|
||||||
if (m_declarations.count(declarationName))
|
if (m_declarations.count(*_name))
|
||||||
declarations += m_declarations.at(declarationName);
|
declarations += m_declarations.at(*_name);
|
||||||
if (m_invisibleDeclarations.count(declarationName))
|
if (m_invisibleDeclarations.count(*_name))
|
||||||
declarations += m_invisibleDeclarations.at(declarationName);
|
declarations += m_invisibleDeclarations.at(*_name);
|
||||||
|
|
||||||
if (dynamic_cast<FunctionDefinition const*>(&_declaration))
|
if (dynamic_cast<FunctionDefinition const*>(&_declaration))
|
||||||
{
|
{
|
||||||
@ -51,25 +55,31 @@ Declaration const* DeclarationContainer::conflictingDeclaration(Declaration cons
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update)
|
bool DeclarationContainer::registerDeclaration(
|
||||||
|
Declaration const& _declaration,
|
||||||
|
ASTString const* _name,
|
||||||
|
bool _invisible,
|
||||||
|
bool _update
|
||||||
|
)
|
||||||
{
|
{
|
||||||
ASTString const& declarationName(_declaration.name());
|
if (!_name)
|
||||||
if (declarationName.empty())
|
_name = &_declaration.name();
|
||||||
|
if (_name->empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (_update)
|
if (_update)
|
||||||
{
|
{
|
||||||
solAssert(!dynamic_cast<FunctionDefinition const*>(&_declaration), "Attempt to update function definition.");
|
solAssert(!dynamic_cast<FunctionDefinition const*>(&_declaration), "Attempt to update function definition.");
|
||||||
m_declarations.erase(declarationName);
|
m_declarations.erase(*_name);
|
||||||
m_invisibleDeclarations.erase(declarationName);
|
m_invisibleDeclarations.erase(*_name);
|
||||||
}
|
}
|
||||||
else if (conflictingDeclaration(_declaration))
|
else if (conflictingDeclaration(_declaration))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (_invisible)
|
if (_invisible)
|
||||||
m_invisibleDeclarations[declarationName].push_back(&_declaration);
|
m_invisibleDeclarations[*_name].push_back(&_declaration);
|
||||||
else
|
else
|
||||||
m_declarations[declarationName].push_back(&_declaration);
|
m_declarations[*_name].push_back(&_declaration);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,23 +41,24 @@ class DeclarationContainer
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DeclarationContainer(
|
explicit DeclarationContainer(
|
||||||
Declaration const* _enclosingDeclaration = nullptr,
|
ASTNode const* _enclosingNode = nullptr,
|
||||||
DeclarationContainer const* _enclosingContainer = nullptr
|
DeclarationContainer const* _enclosingContainer = nullptr
|
||||||
):
|
):
|
||||||
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
|
m_enclosingNode(_enclosingNode), m_enclosingContainer(_enclosingContainer) {}
|
||||||
/// Registers the declaration in the scope unless its name is already declared or the name is empty.
|
/// Registers the declaration in the scope unless its name is already declared or the name is empty.
|
||||||
|
/// @param _name the name to register, if nullptr the intrinsic name of @a _declaration is used.
|
||||||
/// @param _invisible if true, registers the declaration, reports name clashes but does not return it in @a resolveName
|
/// @param _invisible if true, registers the declaration, reports name clashes but does not return it in @a resolveName
|
||||||
/// @param _update if true, replaces a potential declaration that is already present
|
/// @param _update if true, replaces a potential declaration that is already present
|
||||||
/// @returns false if the name was already declared.
|
/// @returns false if the name was already declared.
|
||||||
bool registerDeclaration(Declaration const& _declaration, bool _invisible = false, bool _update = false);
|
bool registerDeclaration(Declaration const& _declaration, ASTString const* _name = nullptr, bool _invisible = false, bool _update = false);
|
||||||
std::vector<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const;
|
std::vector<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const;
|
||||||
Declaration const* enclosingDeclaration() const { return m_enclosingDeclaration; }
|
ASTNode const* enclosingNode() const { return m_enclosingNode; }
|
||||||
std::map<ASTString, std::vector<Declaration const*>> const& declarations() const { return m_declarations; }
|
std::map<ASTString, std::vector<Declaration const*>> const& declarations() const { return m_declarations; }
|
||||||
/// @returns whether declaration is valid, and if not also returns previous declaration.
|
/// @returns whether declaration is valid, and if not also returns previous declaration.
|
||||||
Declaration const* conflictingDeclaration(Declaration const& _declaration) const;
|
Declaration const* conflictingDeclaration(Declaration const& _declaration, ASTString const* _name = nullptr) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Declaration const* m_enclosingDeclaration;
|
ASTNode const* m_enclosingNode;
|
||||||
DeclarationContainer const* m_enclosingContainer;
|
DeclarationContainer const* m_enclosingContainer;
|
||||||
std::map<ASTString, std::vector<Declaration const*>> m_declarations;
|
std::map<ASTString, std::vector<Declaration const*>> m_declarations;
|
||||||
std::map<ASTString, std::vector<Declaration const*>> m_invisibleDeclarations;
|
std::map<ASTString, std::vector<Declaration const*>> m_invisibleDeclarations;
|
||||||
|
@ -38,12 +38,18 @@ NameAndTypeResolver::NameAndTypeResolver(
|
|||||||
) :
|
) :
|
||||||
m_errors(_errors)
|
m_errors(_errors)
|
||||||
{
|
{
|
||||||
|
if (!m_scopes[nullptr])
|
||||||
|
m_scopes[nullptr].reset(new DeclarationContainer());
|
||||||
for (Declaration const* declaration: _globals)
|
for (Declaration const* declaration: _globals)
|
||||||
m_scopes[nullptr].registerDeclaration(*declaration);
|
m_scopes[nullptr]->registerDeclaration(*declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
|
bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
|
||||||
{
|
{
|
||||||
|
solAssert(!m_scopes[&_sourceUnit], "");
|
||||||
|
m_scopes[&_sourceUnit].reset(new DeclarationContainer(nullptr, m_scopes[nullptr].get()));
|
||||||
|
m_currentScope = m_scopes[&_sourceUnit].get();
|
||||||
|
|
||||||
// The helper registers all declarations in m_scopes as a side-effect of its construction.
|
// The helper registers all declarations in m_scopes as a side-effect of its construction.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -58,11 +64,43 @@ bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, SourceUnit const*> const& _sourceUnits)
|
||||||
|
{
|
||||||
|
DeclarationContainer& target = *m_scopes.at(&_sourceUnit);
|
||||||
|
bool error = false;
|
||||||
|
for (auto const& node: _sourceUnit.nodes())
|
||||||
|
if (auto imp = dynamic_cast<ImportDirective const*>(node.get()))
|
||||||
|
{
|
||||||
|
string const& path = imp->annotation().absolutePath;
|
||||||
|
if (!_sourceUnits.count(path))
|
||||||
|
{
|
||||||
|
reportDeclarationError( node->location(),
|
||||||
|
"Import \"" +
|
||||||
|
path +
|
||||||
|
"\" (referenced as \"" +
|
||||||
|
imp->identifier() +
|
||||||
|
"\") not found."
|
||||||
|
);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto scope = m_scopes.find(_sourceUnits.at(path));
|
||||||
|
solAssert(scope != end(m_scopes), "");
|
||||||
|
for (auto const& nameAndDeclaration: scope->second->declarations())
|
||||||
|
for (auto const& declaration: nameAndDeclaration.second)
|
||||||
|
target.registerDeclaration(*declaration, &nameAndDeclaration.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !error;
|
||||||
|
}
|
||||||
|
|
||||||
bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_currentScope = &m_scopes[nullptr];
|
m_currentScope = m_scopes[_contract.scope()].get();
|
||||||
|
solAssert(!!m_currentScope, "");
|
||||||
|
|
||||||
ReferencesResolver resolver(m_errors, *this, nullptr);
|
ReferencesResolver resolver(m_errors, *this, nullptr);
|
||||||
bool success = true;
|
bool success = true;
|
||||||
@ -70,12 +108,12 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
if (!resolver.resolve(*baseContract))
|
if (!resolver.resolve(*baseContract))
|
||||||
success = false;
|
success = false;
|
||||||
|
|
||||||
m_currentScope = &m_scopes[&_contract];
|
m_currentScope = m_scopes[&_contract].get();
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
linearizeBaseContracts(_contract);
|
linearizeBaseContracts(_contract);
|
||||||
std::vector<ContractDefinition const*> properBases(
|
vector<ContractDefinition const*> properBases(
|
||||||
++_contract.annotation().linearizedBaseContracts.begin(),
|
++_contract.annotation().linearizedBaseContracts.begin(),
|
||||||
_contract.annotation().linearizedBaseContracts.end()
|
_contract.annotation().linearizedBaseContracts.end()
|
||||||
);
|
);
|
||||||
@ -87,7 +125,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
// these can contain code, only resolve parameters for now
|
// these can contain code, only resolve parameters for now
|
||||||
for (ASTPointer<ASTNode> const& node: _contract.subNodes())
|
for (ASTPointer<ASTNode> const& node: _contract.subNodes())
|
||||||
{
|
{
|
||||||
m_currentScope = &m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract];
|
m_currentScope = m_scopes[m_scopes.count(node.get()) ? node.get() : &_contract].get();
|
||||||
if (!resolver.resolve(*node))
|
if (!resolver.resolve(*node))
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
@ -95,12 +133,12 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
if (!success)
|
if (!success)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_currentScope = &m_scopes[&_contract];
|
m_currentScope = m_scopes[&_contract].get();
|
||||||
|
|
||||||
// now resolve references inside the code
|
// now resolve references inside the code
|
||||||
for (ModifierDefinition const* modifier: _contract.functionModifiers())
|
for (ModifierDefinition const* modifier: _contract.functionModifiers())
|
||||||
{
|
{
|
||||||
m_currentScope = &m_scopes[modifier];
|
m_currentScope = m_scopes[modifier].get();
|
||||||
ReferencesResolver resolver(m_errors, *this, nullptr, true);
|
ReferencesResolver resolver(m_errors, *this, nullptr, true);
|
||||||
if (!resolver.resolve(*modifier))
|
if (!resolver.resolve(*modifier))
|
||||||
success = false;
|
success = false;
|
||||||
@ -108,7 +146,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
|
|||||||
|
|
||||||
for (FunctionDefinition const* function: _contract.definedFunctions())
|
for (FunctionDefinition const* function: _contract.definedFunctions())
|
||||||
{
|
{
|
||||||
m_currentScope = &m_scopes[function];
|
m_currentScope = m_scopes[function].get();
|
||||||
if (!ReferencesResolver(
|
if (!ReferencesResolver(
|
||||||
m_errors,
|
m_errors,
|
||||||
*this,
|
*this,
|
||||||
@ -133,7 +171,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_scopes[nullptr].registerDeclaration(_declaration, false, true);
|
m_scopes[nullptr]->registerDeclaration(_declaration, nullptr, false, true);
|
||||||
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
|
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
|
||||||
}
|
}
|
||||||
catch (FatalError const&)
|
catch (FatalError const&)
|
||||||
@ -145,12 +183,12 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, Declaration const* _scope) const
|
vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, ASTNode const* _scope) const
|
||||||
{
|
{
|
||||||
auto iterator = m_scopes.find(_scope);
|
auto iterator = m_scopes.find(_scope);
|
||||||
if (iterator == end(m_scopes))
|
if (iterator == end(m_scopes))
|
||||||
return vector<Declaration const*>({});
|
return vector<Declaration const*>({});
|
||||||
return iterator->second.resolveName(_name, false);
|
return iterator->second->resolveName(_name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<Declaration const*> NameAndTypeResolver::nameFromCurrentScope(ASTString const& _name, bool _recursive) const
|
vector<Declaration const*> NameAndTypeResolver::nameFromCurrentScope(ASTString const& _name, bool _recursive) const
|
||||||
@ -166,7 +204,7 @@ Declaration const* NameAndTypeResolver::pathFromCurrentScope(vector<ASTString> c
|
|||||||
{
|
{
|
||||||
if (!m_scopes.count(candidates.front()))
|
if (!m_scopes.count(candidates.front()))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
candidates = m_scopes.at(candidates.front()).resolveName(_path[i], false);
|
candidates = m_scopes.at(candidates.front())->resolveName(_path[i], false);
|
||||||
}
|
}
|
||||||
if (candidates.size() == 1)
|
if (candidates.size() == 1)
|
||||||
return candidates.front();
|
return candidates.front();
|
||||||
@ -210,7 +248,7 @@ void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base)
|
|||||||
{
|
{
|
||||||
auto iterator = m_scopes.find(&_base);
|
auto iterator = m_scopes.find(&_base);
|
||||||
solAssert(iterator != end(m_scopes), "");
|
solAssert(iterator != end(m_scopes), "");
|
||||||
for (auto const& nameAndDeclaration: iterator->second.declarations())
|
for (auto const& nameAndDeclaration: iterator->second->declarations())
|
||||||
for (auto const& declaration: nameAndDeclaration.second)
|
for (auto const& declaration: nameAndDeclaration.second)
|
||||||
// Import if it was declared in the base, is not the constructor and is visible in derived classes
|
// Import if it was declared in the base, is not the constructor and is visible in derived classes
|
||||||
if (declaration->scope() == &_base && declaration->isVisibleInDerivedContracts())
|
if (declaration->scope() == &_base && declaration->isVisibleInDerivedContracts())
|
||||||
@ -342,14 +380,15 @@ void NameAndTypeResolver::reportFatalTypeError(Error const& _e)
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeclarationRegistrationHelper::DeclarationRegistrationHelper(
|
DeclarationRegistrationHelper::DeclarationRegistrationHelper(
|
||||||
map<ASTNode const*, DeclarationContainer>& _scopes,
|
map<ASTNode const*, unique_ptr<DeclarationContainer>>& _scopes,
|
||||||
ASTNode& _astRoot,
|
ASTNode& _astRoot,
|
||||||
ErrorList& _errors
|
ErrorList& _errors
|
||||||
):
|
):
|
||||||
m_scopes(_scopes),
|
m_scopes(_scopes),
|
||||||
m_currentScope(nullptr),
|
m_currentScope(&_astRoot),
|
||||||
m_errors(_errors)
|
m_errors(_errors)
|
||||||
{
|
{
|
||||||
|
solAssert(!!m_scopes.at(m_currentScope), "");
|
||||||
_astRoot.accept(*this);
|
_astRoot.accept(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,9 +489,10 @@ void DeclarationRegistrationHelper::endVisit(EventDefinition&)
|
|||||||
|
|
||||||
void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declaration)
|
void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declaration)
|
||||||
{
|
{
|
||||||
map<ASTNode const*, DeclarationContainer>::iterator iter;
|
map<ASTNode const*, unique_ptr<DeclarationContainer>>::iterator iter;
|
||||||
bool newlyAdded;
|
bool newlyAdded;
|
||||||
tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, DeclarationContainer(m_currentScope, &m_scopes[m_currentScope]));
|
unique_ptr<DeclarationContainer> container(new DeclarationContainer(m_currentScope, m_scopes[m_currentScope].get()));
|
||||||
|
tie(iter, newlyAdded) = m_scopes.emplace(&_declaration, move(container));
|
||||||
solAssert(newlyAdded, "Unable to add new scope.");
|
solAssert(newlyAdded, "Unable to add new scope.");
|
||||||
m_currentScope = &_declaration;
|
m_currentScope = &_declaration;
|
||||||
}
|
}
|
||||||
@ -460,16 +500,16 @@ void DeclarationRegistrationHelper::enterNewSubScope(Declaration const& _declara
|
|||||||
void DeclarationRegistrationHelper::closeCurrentScope()
|
void DeclarationRegistrationHelper::closeCurrentScope()
|
||||||
{
|
{
|
||||||
solAssert(m_currentScope, "Closed non-existing scope.");
|
solAssert(m_currentScope, "Closed non-existing scope.");
|
||||||
m_currentScope = m_scopes[m_currentScope].enclosingDeclaration();
|
m_currentScope = m_scopes[m_currentScope]->enclosingNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
|
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
|
||||||
{
|
{
|
||||||
if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract()))
|
if (!m_scopes[m_currentScope]->registerDeclaration(_declaration, nullptr, !_declaration.isVisibleInContract()))
|
||||||
{
|
{
|
||||||
SourceLocation firstDeclarationLocation;
|
SourceLocation firstDeclarationLocation;
|
||||||
SourceLocation secondDeclarationLocation;
|
SourceLocation secondDeclarationLocation;
|
||||||
Declaration const* conflictingDeclaration = m_scopes[m_currentScope].conflictingDeclaration(_declaration);
|
Declaration const* conflictingDeclaration = m_scopes[m_currentScope]->conflictingDeclaration(_declaration);
|
||||||
solAssert(conflictingDeclaration, "");
|
solAssert(conflictingDeclaration, "");
|
||||||
|
|
||||||
if (_declaration.location().start < conflictingDeclaration->location().start)
|
if (_declaration.location().start < conflictingDeclaration->location().start)
|
||||||
@ -500,14 +540,17 @@ string DeclarationRegistrationHelper::currentCanonicalName() const
|
|||||||
{
|
{
|
||||||
string ret;
|
string ret;
|
||||||
for (
|
for (
|
||||||
Declaration const* scope = m_currentScope;
|
ASTNode const* scope = m_currentScope;
|
||||||
scope != nullptr;
|
scope != nullptr;
|
||||||
scope = m_scopes[scope].enclosingDeclaration()
|
scope = m_scopes[scope]->enclosingNode()
|
||||||
)
|
)
|
||||||
|
{
|
||||||
|
if (auto decl = dynamic_cast<Declaration const*>(scope))
|
||||||
{
|
{
|
||||||
if (!ret.empty())
|
if (!ret.empty())
|
||||||
ret = "." + ret;
|
ret = "." + ret;
|
||||||
ret = scope->name() + ret;
|
ret = decl->name() + ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,8 @@ public:
|
|||||||
/// Registers all declarations found in the source unit.
|
/// Registers all declarations found in the source unit.
|
||||||
/// @returns false in case of error.
|
/// @returns false in case of error.
|
||||||
bool registerDeclarations(SourceUnit& _sourceUnit);
|
bool registerDeclarations(SourceUnit& _sourceUnit);
|
||||||
|
/// Applies the effect of import directives.
|
||||||
|
bool performImports(SourceUnit& _sourceUnit, std::map<std::string, SourceUnit const*> const& _sourceUnits);
|
||||||
/// Resolves all names and types referenced from the given contract.
|
/// Resolves all names and types referenced from the given contract.
|
||||||
/// @returns false in case of error.
|
/// @returns false in case of error.
|
||||||
bool resolveNamesAndTypes(ContractDefinition& _contract);
|
bool resolveNamesAndTypes(ContractDefinition& _contract);
|
||||||
@ -55,9 +57,9 @@ public:
|
|||||||
bool updateDeclaration(Declaration const& _declaration);
|
bool updateDeclaration(Declaration const& _declaration);
|
||||||
|
|
||||||
/// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted,
|
/// Resolves the given @a _name inside the scope @a _scope. If @a _scope is omitted,
|
||||||
/// the global scope is used (i.e. the one containing only the contract).
|
/// the global scope is used (i.e. the one containing only the pre-defined global variables).
|
||||||
/// @returns a pointer to the declaration on success or nullptr on failure.
|
/// @returns a pointer to the declaration on success or nullptr on failure.
|
||||||
std::vector<Declaration const*> resolveName(ASTString const& _name, Declaration const* _scope = nullptr) const;
|
std::vector<Declaration const*> resolveName(ASTString const& _name, ASTNode const* _scope = nullptr) const;
|
||||||
|
|
||||||
/// Resolves a name in the "current" scope. Should only be called during the initial
|
/// Resolves a name in the "current" scope. Should only be called during the initial
|
||||||
/// resolving phase.
|
/// resolving phase.
|
||||||
@ -88,11 +90,6 @@ private:
|
|||||||
template <class _T>
|
template <class _T>
|
||||||
static std::vector<_T const*> cThreeMerge(std::list<std::list<_T const*>>& _toMerge);
|
static std::vector<_T const*> cThreeMerge(std::list<std::list<_T const*>>& _toMerge);
|
||||||
|
|
||||||
/// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration,
|
|
||||||
/// where nullptr denotes the global scope. Note that structs are not scope since they do
|
|
||||||
/// not contain code.
|
|
||||||
std::map<ASTNode const*, DeclarationContainer> m_scopes;
|
|
||||||
|
|
||||||
// creates the Declaration error and adds it in the errors list
|
// creates the Declaration error and adds it in the errors list
|
||||||
void reportDeclarationError(
|
void reportDeclarationError(
|
||||||
SourceLocation _sourceLoction,
|
SourceLocation _sourceLoction,
|
||||||
@ -110,6 +107,12 @@ private:
|
|||||||
// creates the Declaration error and adds it in the errors list and throws FatalError
|
// creates the Declaration error and adds it in the errors list and throws FatalError
|
||||||
void reportFatalTypeError(Error const& _e);
|
void reportFatalTypeError(Error const& _e);
|
||||||
|
|
||||||
|
|
||||||
|
/// Maps nodes declaring a scope to scopes, i.e. ContractDefinition and FunctionDeclaration,
|
||||||
|
/// where nullptr denotes the global scope. Note that structs are not scope since they do
|
||||||
|
/// not contain code.
|
||||||
|
std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>> m_scopes;
|
||||||
|
|
||||||
DeclarationContainer* m_currentScope = nullptr;
|
DeclarationContainer* m_currentScope = nullptr;
|
||||||
ErrorList& m_errors;
|
ErrorList& m_errors;
|
||||||
};
|
};
|
||||||
@ -121,7 +124,11 @@ private:
|
|||||||
class DeclarationRegistrationHelper: private ASTVisitor
|
class DeclarationRegistrationHelper: private ASTVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeclarationRegistrationHelper(std::map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot, ErrorList& _errors);
|
DeclarationRegistrationHelper(
|
||||||
|
std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>>& _scopes,
|
||||||
|
ASTNode& _astRoot,
|
||||||
|
ErrorList& _errors
|
||||||
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool visit(ContractDefinition& _contract) override;
|
bool visit(ContractDefinition& _contract) override;
|
||||||
@ -159,8 +166,8 @@ private:
|
|||||||
// creates the Declaration error and adds it in the errors list and throws FatalError
|
// creates the Declaration error and adds it in the errors list and throws FatalError
|
||||||
void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description);
|
void fatalDeclarationError(SourceLocation _sourceLocation, std::string const& _description);
|
||||||
|
|
||||||
std::map<ASTNode const*, DeclarationContainer>& m_scopes;
|
std::map<ASTNode const*, std::unique_ptr<DeclarationContainer>>& m_scopes;
|
||||||
Declaration const* m_currentScope = nullptr;
|
ASTNode const* m_currentScope = nullptr;
|
||||||
VariableScope* m_currentFunction = nullptr;
|
VariableScope* m_currentFunction = nullptr;
|
||||||
ErrorList& m_errors;
|
ErrorList& m_errors;
|
||||||
};
|
};
|
||||||
|
@ -139,7 +139,9 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
|||||||
bool isPointer = true;
|
bool isPointer = true;
|
||||||
if (_variable.isExternalCallableParameter())
|
if (_variable.isExternalCallableParameter())
|
||||||
{
|
{
|
||||||
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
|
auto const& contract = dynamic_cast<ContractDefinition const&>(
|
||||||
|
*dynamic_cast<Declaration const&>(*_variable.scope()).scope()
|
||||||
|
);
|
||||||
if (contract.isLibrary())
|
if (contract.isLibrary())
|
||||||
{
|
{
|
||||||
if (varLoc == Location::Memory)
|
if (varLoc == Location::Memory)
|
||||||
@ -162,9 +164,11 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
|
|||||||
else
|
else
|
||||||
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
|
typeLoc = varLoc == Location::Memory ? DataLocation::Memory : DataLocation::Storage;
|
||||||
}
|
}
|
||||||
else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
|
else if (_variable.isCallableParameter() && dynamic_cast<Declaration const&>(*_variable.scope()).isPublic())
|
||||||
{
|
{
|
||||||
auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
|
auto const& contract = dynamic_cast<ContractDefinition const&>(
|
||||||
|
*dynamic_cast<Declaration const&>(*_variable.scope()).scope()
|
||||||
|
);
|
||||||
// force locations of public or external function (return) parameters to memory
|
// force locations of public or external function (return) parameters to memory
|
||||||
if (varLoc == Location::Storage && !contract.isLibrary())
|
if (varLoc == Location::Storage && !contract.isLibrary())
|
||||||
fatalTypeError(_variable.location(),
|
fatalTypeError(_variable.location(),
|
||||||
|
@ -56,6 +56,13 @@ Error ASTNode::createTypeError(string const& _description) const
|
|||||||
return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
|
return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImportAnnotation& ImportDirective::annotation() const
|
||||||
|
{
|
||||||
|
if (!m_annotation)
|
||||||
|
m_annotation = new ImportAnnotation();
|
||||||
|
return static_cast<ImportAnnotation&>(*m_annotation);
|
||||||
|
}
|
||||||
|
|
||||||
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
|
||||||
{
|
{
|
||||||
auto exportedFunctionList = interfaceFunctionList();
|
auto exportedFunctionList = interfaceFunctionList();
|
||||||
|
@ -142,6 +142,7 @@ public:
|
|||||||
virtual void accept(ASTConstVisitor& _visitor) const override;
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
ASTString const& identifier() const { return *m_identifier; }
|
ASTString const& identifier() const { return *m_identifier; }
|
||||||
|
virtual ImportAnnotation& annotation() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ASTPointer<ASTString> m_identifier;
|
ASTPointer<ASTString> m_identifier;
|
||||||
@ -172,8 +173,8 @@ public:
|
|||||||
|
|
||||||
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
|
/// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
|
||||||
/// Available only after name and type resolution step.
|
/// Available only after name and type resolution step.
|
||||||
Declaration const* scope() const { return m_scope; }
|
ASTNode const* scope() const { return m_scope; }
|
||||||
void setScope(Declaration const* _scope) { m_scope = _scope; }
|
void setScope(ASTNode const* _scope) { m_scope = _scope; }
|
||||||
|
|
||||||
virtual bool isLValue() const { return false; }
|
virtual bool isLValue() const { return false; }
|
||||||
virtual bool isPartOfExternalInterface() const { return false; }
|
virtual bool isPartOfExternalInterface() const { return false; }
|
||||||
@ -190,7 +191,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
ASTPointer<ASTString> m_name;
|
ASTPointer<ASTString> m_name;
|
||||||
Visibility m_visibility;
|
Visibility m_visibility;
|
||||||
Declaration const* m_scope;
|
ASTNode const* m_scope;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,6 +54,12 @@ struct DocumentedAnnotation
|
|||||||
std::multimap<std::string, DocTag> docTags;
|
std::multimap<std::string, DocTag> docTags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ImportAnnotation: ASTAnnotation
|
||||||
|
{
|
||||||
|
/// The absolute path of the source unit to import.
|
||||||
|
std::string absolutePath;
|
||||||
|
};
|
||||||
|
|
||||||
struct TypeDeclarationAnnotation: ASTAnnotation
|
struct TypeDeclarationAnnotation: ASTAnnotation
|
||||||
{
|
{
|
||||||
/// The name of this type, prefixed by proper namespaces if globally accessible.
|
/// The name of this type, prefixed by proper namespaces if globally accessible.
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
#include <libsolidity/parsing/Scanner.h>
|
#include <libsolidity/parsing/Scanner.h>
|
||||||
#include <libsolidity/parsing/Parser.h>
|
#include <libsolidity/parsing/Parser.h>
|
||||||
@ -103,12 +104,14 @@ bool CompilerStack::parse()
|
|||||||
m_errors.clear();
|
m_errors.clear();
|
||||||
m_parseSuccessful = false;
|
m_parseSuccessful = false;
|
||||||
|
|
||||||
|
map<string, SourceUnit const*> sourceUnitsByName;
|
||||||
for (auto& sourcePair: m_sources)
|
for (auto& sourcePair: m_sources)
|
||||||
{
|
{
|
||||||
sourcePair.second.scanner->reset();
|
sourcePair.second.scanner->reset();
|
||||||
sourcePair.second.ast = Parser(m_errors).parse(sourcePair.second.scanner);
|
sourcePair.second.ast = Parser(m_errors).parse(sourcePair.second.scanner);
|
||||||
if (!sourcePair.second.ast)
|
if (!sourcePair.second.ast)
|
||||||
solAssert(!Error::containsOnlyWarnings(m_errors), "Parser returned null but did not report error.");
|
solAssert(!Error::containsOnlyWarnings(m_errors), "Parser returned null but did not report error.");
|
||||||
|
sourceUnitsByName[sourcePair.first] = sourcePair.second.ast.get();
|
||||||
}
|
}
|
||||||
if (!Error::containsOnlyWarnings(m_errors))
|
if (!Error::containsOnlyWarnings(m_errors))
|
||||||
// errors while parsing. sould stop before type checking
|
// errors while parsing. sould stop before type checking
|
||||||
@ -128,6 +131,10 @@ bool CompilerStack::parse()
|
|||||||
if (!resolver.registerDeclarations(*source->ast))
|
if (!resolver.registerDeclarations(*source->ast))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
for (Source const* source: m_sourceOrder)
|
||||||
|
if (!resolver.performImports(*source->ast, sourceUnitsByName))
|
||||||
|
return false;
|
||||||
|
|
||||||
for (Source const* source: m_sourceOrder)
|
for (Source const* source: m_sourceOrder)
|
||||||
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
|
for (ASTPointer<ASTNode> const& node: source->ast->nodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
@ -361,7 +368,7 @@ void CompilerStack::resolveImports()
|
|||||||
vector<Source const*> sourceOrder;
|
vector<Source const*> sourceOrder;
|
||||||
set<Source const*> sourcesSeen;
|
set<Source const*> sourcesSeen;
|
||||||
|
|
||||||
function<void(Source const*)> toposort = [&](Source const* _source)
|
function<void(string const&, Source const*)> toposort = [&](string const& _sourceName, Source const* _source)
|
||||||
{
|
{
|
||||||
if (sourcesSeen.count(_source))
|
if (sourcesSeen.count(_source))
|
||||||
return;
|
return;
|
||||||
@ -369,26 +376,44 @@ void CompilerStack::resolveImports()
|
|||||||
for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
|
for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
|
||||||
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
|
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
|
||||||
{
|
{
|
||||||
string const& id = import->identifier();
|
string path = absolutePath(import->identifier(), _sourceName);
|
||||||
if (!m_sources.count(id))
|
import->annotation().absolutePath = path;
|
||||||
|
if (!m_sources.count(path))
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
Error(Error::Type::ParserError)
|
Error(Error::Type::ParserError)
|
||||||
<< errinfo_sourceLocation(import->location())
|
<< errinfo_sourceLocation(import->location())
|
||||||
<< errinfo_comment("Source not found.")
|
<< errinfo_comment("Source not found.")
|
||||||
);
|
);
|
||||||
|
|
||||||
toposort(&m_sources[id]);
|
toposort(path, &m_sources[path]);
|
||||||
}
|
}
|
||||||
sourceOrder.push_back(_source);
|
sourceOrder.push_back(_source);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto const& sourcePair: m_sources)
|
for (auto const& sourcePair: m_sources)
|
||||||
if (!sourcePair.second.isLibrary)
|
if (!sourcePair.second.isLibrary)
|
||||||
toposort(&sourcePair.second);
|
toposort(sourcePair.first, &sourcePair.second);
|
||||||
|
|
||||||
swap(m_sourceOrder, sourceOrder);
|
swap(m_sourceOrder, sourceOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string CompilerStack::absolutePath(string const& _path, string const& _reference) const
|
||||||
|
{
|
||||||
|
// Anything that does not start with `.` is an absolute path.
|
||||||
|
if (_path.empty() || _path.front() != '.')
|
||||||
|
return _path;
|
||||||
|
using path = boost::filesystem::path;
|
||||||
|
path p(_path);
|
||||||
|
path result(_reference);
|
||||||
|
result.remove_filename();
|
||||||
|
for (path::iterator it = p.begin(); it != p.end(); ++it)
|
||||||
|
if (*it == "..")
|
||||||
|
result = result.parent_path();
|
||||||
|
else if (*it != ".")
|
||||||
|
result /= *it;
|
||||||
|
return result.string();
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerStack::compileContract(
|
void CompilerStack::compileContract(
|
||||||
bool _optimize,
|
bool _optimize,
|
||||||
unsigned _runs,
|
unsigned _runs,
|
||||||
|
@ -199,6 +199,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void resolveImports();
|
void resolveImports();
|
||||||
|
/// @returns the absolute path corresponding to @a _path relative to @a _reference.
|
||||||
|
std::string absolutePath(std::string const& _path, std::string const& _reference) const;
|
||||||
/// Compile a single contract and put the result in @a _compiledContracts.
|
/// Compile a single contract and put the result in @a _compiledContracts.
|
||||||
void compileContract(
|
void compileContract(
|
||||||
bool _optimize,
|
bool _optimize,
|
||||||
|
100
test/libsolidity/Imports.cpp
Normal file
100
test/libsolidity/Imports.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
This file is part of cpp-ethereum.
|
||||||
|
|
||||||
|
cpp-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
cpp-ethereum is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @author Christian <c@ethdev.com>
|
||||||
|
* @date 2015
|
||||||
|
* Tests for high level features like import.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <libsolidity/interface/Exceptions.h>
|
||||||
|
#include <libsolidity/interface/CompilerStack.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace dev
|
||||||
|
{
|
||||||
|
namespace solidity
|
||||||
|
{
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(SolidityImports)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(smoke_test)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "contract C {}");
|
||||||
|
BOOST_CHECK(c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(regular_import)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "contract C {}");
|
||||||
|
c.addSource("b", "import \"a\"; contract D is C {}");
|
||||||
|
BOOST_CHECK(c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(import_does_not_clutter_importee)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "contract C { D d; }");
|
||||||
|
c.addSource("b", "import \"a\"; contract D is C {}");
|
||||||
|
BOOST_CHECK(!c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(import_is_transitive)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "contract C { }");
|
||||||
|
c.addSource("b", "import \"a\";");
|
||||||
|
c.addSource("c", "import \"b\"; contract D is C {}");
|
||||||
|
BOOST_CHECK(c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(circular_import)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "import \"b\"; contract C { D d; }");
|
||||||
|
c.addSource("b", "import \"a\"; contract D { C c; }");
|
||||||
|
BOOST_CHECK(c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(relative_import)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "import \"./dir/b\"; contract A is B {}");
|
||||||
|
c.addSource("dir/b", "contract B {}");
|
||||||
|
c.addSource("dir/c", "import \"../a\"; contract C is A {}");
|
||||||
|
BOOST_CHECK(c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(relative_import_multiplex)
|
||||||
|
{
|
||||||
|
CompilerStack c;
|
||||||
|
c.addSource("a", "contract A {}");
|
||||||
|
c.addSource("dir/a/b/c", "import \"../../.././a\"; contract B is A {}");
|
||||||
|
BOOST_CHECK(c.compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end namespaces
|
@ -71,18 +71,21 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Declaration const& resolveDeclaration(
|
Declaration const& resolveDeclaration(
|
||||||
vector<string> const& _namespacedName, NameAndTypeResolver const& _resolver)
|
SourceUnit const& _sourceUnit,
|
||||||
|
vector<string> const& _namespacedName,
|
||||||
|
NameAndTypeResolver const& _resolver
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Declaration const* declaration = nullptr;
|
ASTNode const* scope = &_sourceUnit;
|
||||||
// bracers are required, cause msvc couldnt handle this macro in for statement
|
// bracers are required, cause msvc couldnt handle this macro in for statement
|
||||||
for (string const& namePart: _namespacedName)
|
for (string const& namePart: _namespacedName)
|
||||||
{
|
{
|
||||||
auto declarations = _resolver.resolveName(namePart, declaration);
|
auto declarations = _resolver.resolveName(namePart, scope);
|
||||||
BOOST_REQUIRE(!declarations.empty());
|
BOOST_REQUIRE(!declarations.empty());
|
||||||
BOOST_REQUIRE(declaration = *declarations.begin());
|
BOOST_REQUIRE(scope = *declarations.begin());
|
||||||
}
|
}
|
||||||
BOOST_REQUIRE(declaration);
|
BOOST_REQUIRE(scope);
|
||||||
return *declaration;
|
return dynamic_cast<Declaration const&>(*scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes compileFirstExpression(
|
bytes compileFirstExpression(
|
||||||
@ -140,13 +143,17 @@ bytes compileFirstExpression(
|
|||||||
unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack
|
unsigned parametersSize = _localVariables.size(); // assume they are all one slot on the stack
|
||||||
context.adjustStackOffset(parametersSize);
|
context.adjustStackOffset(parametersSize);
|
||||||
for (vector<string> const& variable: _localVariables)
|
for (vector<string> const& variable: _localVariables)
|
||||||
context.addVariable(dynamic_cast<VariableDeclaration const&>(resolveDeclaration(variable, resolver)),
|
context.addVariable(
|
||||||
parametersSize--);
|
dynamic_cast<VariableDeclaration const&>(resolveDeclaration(*sourceUnit, variable, resolver)),
|
||||||
|
parametersSize--
|
||||||
|
);
|
||||||
|
|
||||||
ExpressionCompiler(context).compile(*extractor.expression());
|
ExpressionCompiler(context).compile(*extractor.expression());
|
||||||
|
|
||||||
for (vector<string> const& function: _functions)
|
for (vector<string> const& function: _functions)
|
||||||
context << context.functionEntryLabel(dynamic_cast<FunctionDefinition const&>(resolveDeclaration(function, resolver)));
|
context << context.functionEntryLabel(dynamic_cast<FunctionDefinition const&>(
|
||||||
|
resolveDeclaration(*sourceUnit, function, resolver)
|
||||||
|
));
|
||||||
bytes instructions = context.assembledObject().bytecode;
|
bytes instructions = context.assembledObject().bytecode;
|
||||||
// debug
|
// debug
|
||||||
// cout << eth::disassemble(instructions) << endl;
|
// cout << eth::disassemble(instructions) << endl;
|
||||||
|
Loading…
Reference in New Issue
Block a user