/* 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 * Parser part that determines the declarations corresponding to names and the types of expressions. */ #include #include #include namespace dev { namespace solidity { class NameAndTypeResolver::ScopeHelper { public: ScopeHelper(NameAndTypeResolver& _resolver, ASTString const& _name, ASTNode& _declaration) : m_resolver(_resolver) { m_resolver.registerName(_name, _declaration); m_resolver.enterNewSubScope(_declaration); } ~ScopeHelper() { m_resolver.closeCurrentScope(); } private: NameAndTypeResolver& m_resolver; }; NameAndTypeResolver::NameAndTypeResolver() { } void NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract) { reset(); handleContract(_contract); } void NameAndTypeResolver::handleContract(ContractDefinition& _contract) { ScopeHelper scopeHelper(*this, _contract.getName(), _contract); for (ptr const& variable : _contract.getStateVariables()) registerName(variable->getName(), *variable); // @todo structs for (ptr const& function : _contract.getDefinedFunctions()) handleFunction(*function); // @todo resolve names used in mappings } void NameAndTypeResolver::reset() { m_scopes.clear(); m_globalScope = Scope(); m_currentScope = &m_globalScope; } void NameAndTypeResolver::handleFunction(FunctionDefinition& _function) { ScopeHelper scopeHelper(*this, _function.getName(), _function); // @todo resolve names used in mappings for (ptr const& variable : _function.getParameters()) registerName(variable->getName(), *variable); if (_function.hasReturnParameters()) for (ptr const& variable : _function.getReturnParameters()) registerName(variable->getName(), *variable); handleFunctionBody(_function.getBody()); } void NameAndTypeResolver::handleFunctionBody(Block& _functionBody) { registerVariablesInFunction(_functionBody); resolveReferencesInFunction(_functionBody); } void NameAndTypeResolver::registerVariablesInFunction(Block& _functionBody) { class VariableDeclarationFinder : public ASTVisitor { public: VariableDeclarationFinder(NameAndTypeResolver& _resolver) : m_resolver(_resolver) {} virtual bool visit(VariableDeclaration& _variable) override { m_resolver.registerName(_variable.getName(), _variable); return false; } private: NameAndTypeResolver& m_resolver; }; VariableDeclarationFinder declarationFinder(*this); _functionBody.accept(declarationFinder); } void NameAndTypeResolver::resolveReferencesInFunction(Block& _functionBody) { class ReferencesResolver : public ASTVisitor { public: ReferencesResolver(NameAndTypeResolver& _resolver) : m_resolver(_resolver) {} virtual bool visit(Identifier& _identifier) override { ASTNode* node = m_resolver.getNameFromCurrentScope(_identifier.getName()); if (node == nullptr) throw std::exception(); // @todo _identifier.setReferencedObject(*node); return false; } private: NameAndTypeResolver& m_resolver; }; ReferencesResolver referencesResolver(*this); _functionBody.accept(referencesResolver); } void NameAndTypeResolver::registerName(ASTString const& _name, ASTNode& _declaration) { if (!m_currentScope->registerName(_name, _declaration)) throw std::exception(); // @todo } ASTNode* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) { return m_currentScope->resolveName(_name, _recursive); } void NameAndTypeResolver::enterNewSubScope(ASTNode& _node) { decltype(m_scopes)::iterator iter; bool newlyAdded; std::tie(iter, newlyAdded) = m_scopes.emplace(&_node, Scope(m_currentScope)); BOOST_ASSERT(newlyAdded); m_currentScope = &iter->second; } void NameAndTypeResolver::closeCurrentScope() { m_currentScope = m_currentScope->getOuterScope(); } } }