diff options
author | Christian <c@ethdev.com> | 2015-01-16 03:04:06 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2015-01-20 06:35:04 +0800 |
commit | 914fcedd0e2217300ee28f13bc4c006860f81a12 (patch) | |
tree | a0536dbf1e36ac7ce96ca68febda501915f9c973 /NameAndTypeResolver.cpp | |
parent | 4631e54e08184df7b6788f37b0ad2f808d1d73cc (diff) | |
download | dexon-solidity-914fcedd0e2217300ee28f13bc4c006860f81a12.tar dexon-solidity-914fcedd0e2217300ee28f13bc4c006860f81a12.tar.gz dexon-solidity-914fcedd0e2217300ee28f13bc4c006860f81a12.tar.bz2 dexon-solidity-914fcedd0e2217300ee28f13bc4c006860f81a12.tar.lz dexon-solidity-914fcedd0e2217300ee28f13bc4c006860f81a12.tar.xz dexon-solidity-914fcedd0e2217300ee28f13bc4c006860f81a12.tar.zst dexon-solidity-914fcedd0e2217300ee28f13bc4c006860f81a12.zip |
Import inherited members into the contract's scope.
Diffstat (limited to 'NameAndTypeResolver.cpp')
-rw-r--r-- | NameAndTypeResolver.cpp | 99 |
1 files changed, 98 insertions, 1 deletions
diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp index 3774537d..2a73f21b 100644 --- a/NameAndTypeResolver.cpp +++ b/NameAndTypeResolver.cpp @@ -46,7 +46,17 @@ void NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit) void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { + m_currentScope = &m_scopes[nullptr]; + + for (ASTPointer<Identifier> const& baseContract: _contract.getBaseContracts()) + ReferencesResolver resolver(*baseContract, *this, nullptr); + m_currentScope = &m_scopes[&_contract]; + + linearizeBaseContracts(_contract); + for (ContractDefinition const* base: _contract.getLinearizedBaseContracts()) + importInheritedScope(*base); + for (ASTPointer<StructDefinition> const& structDef: _contract.getDefinedStructs()) ReferencesResolver resolver(*structDef, *this, nullptr); for (ASTPointer<VariableDeclaration> const& variable: _contract.getStateVariables()) @@ -57,7 +67,6 @@ void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) ReferencesResolver referencesResolver(*function, *this, function->getReturnParameterList().get()); } - m_currentScope = &m_scopes[nullptr]; } void NameAndTypeResolver::checkTypeRequirements(ContractDefinition& _contract) @@ -86,6 +95,94 @@ Declaration const* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& return m_currentScope->resolveName(_name, _recursive); } +void NameAndTypeResolver::importInheritedScope(ContractDefinition const& _base) +{ + auto iterator = m_scopes.find(&_base); + solAssert(iterator != end(m_scopes), ""); + for (auto const& nameAndDeclaration: iterator->second.getDeclarations()) + { + Declaration const* declaration = nameAndDeclaration.second; + if (declaration->getScope() == &_base) + m_currentScope->registerDeclaration(*declaration); + } +} + +void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract) const +{ + // order in the lists is from derived to base + // list of lists to linearize, the last element is the list of direct bases + list<list<ContractDefinition const*>> input(1, {&_contract}); + for (ASTPointer<Identifier> const& baseIdentifier: _contract.getBaseContracts()) + { + ContractDefinition const* base = dynamic_cast<ContractDefinition const*>( + baseIdentifier->getReferencedDeclaration()); + if (!base) + BOOST_THROW_EXCEPTION(baseIdentifier->createTypeError("Contract expected.")); + // "push_back" has the effect that bases mentioned earlier can overwrite members of bases + // mentioned later + input.back().push_back(base); + vector<ContractDefinition const*> const& basesBases = base->getLinearizedBaseContracts(); + if (basesBases.empty()) + BOOST_THROW_EXCEPTION(baseIdentifier->createTypeError("Definition of base has to precede definition of derived contract")); + input.push_front(list<ContractDefinition const*>(basesBases.begin(), basesBases.end())); + } + vector<ContractDefinition const*> result = cThreeMerge(input); + if (result.empty()) + BOOST_THROW_EXCEPTION(_contract.createTypeError("Linearization of inheritance graph impossible")); + _contract.setLinearizedBaseContracts(result); +} + +template <class _T> +vector<_T const*> NameAndTypeResolver::cThreeMerge(list<list<_T const*>>& _toMerge) +{ + // returns true iff _candidate appears only as last element of the lists + auto appearsOnlyAtHead = [&](_T const* _candidate) -> bool + { + for (list<_T const*> const& bases: _toMerge) + { + solAssert(!bases.empty(), ""); + if (find(++bases.begin(), bases.end(), _candidate) != bases.end()) + return false; + } + return true; + }; + // returns the next candidate to append to the linearized list or nullptr on failure + auto nextCandidate = [&]() -> _T const* + { + for (list<_T const*> const& bases: _toMerge) + { + solAssert(!bases.empty(), ""); + if (appearsOnlyAtHead(bases.front())) + return bases.front(); + } + return nullptr; + }; + // removes the given contract from all lists + auto removeCandidate = [&](_T const* _candidate) + { + for (auto it = _toMerge.begin(); it != _toMerge.end();) + { + it->remove(_candidate); + if (it->empty()) + it = _toMerge.erase(it); + else + ++it; + } + }; + + _toMerge.remove_if([](list<_T const*> const& _bases) { return _bases.empty(); }); + vector<_T const*> result; + while (!_toMerge.empty()) + { + _T const* candidate = nextCandidate(); + if (!candidate) + return vector<_T const*>(); + result.push_back(candidate); + removeCandidate(candidate); + } + return result; +} + DeclarationRegistrationHelper::DeclarationRegistrationHelper(map<ASTNode const*, DeclarationContainer>& _scopes, ASTNode& _astRoot): m_scopes(_scopes), m_currentScope(nullptr) |