diff options
author | Christian <c@ethdev.com> | 2014-10-13 21:07:21 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2014-10-13 23:02:21 +0800 |
commit | 4f791179640fdcfbbd62c4c7a2a5273081b7b742 (patch) | |
tree | 7c7576b991884befde24473b5f6370b8afa83b2f | |
parent | 98bdd7429974521946a1aa3bffa038fc515f745c (diff) | |
download | dexon-solidity-4f791179640fdcfbbd62c4c7a2a5273081b7b742.tar dexon-solidity-4f791179640fdcfbbd62c4c7a2a5273081b7b742.tar.gz dexon-solidity-4f791179640fdcfbbd62c4c7a2a5273081b7b742.tar.bz2 dexon-solidity-4f791179640fdcfbbd62c4c7a2a5273081b7b742.tar.lz dexon-solidity-4f791179640fdcfbbd62c4c7a2a5273081b7b742.tar.xz dexon-solidity-4f791179640fdcfbbd62c4c7a2a5273081b7b742.tar.zst dexon-solidity-4f791179640fdcfbbd62c4c7a2a5273081b7b742.zip |
Name resolution.
-rw-r--r-- | AST.h | 17 | ||||
-rw-r--r-- | ASTForward.h | 1 | ||||
-rw-r--r-- | ASTPrinter.cpp | 12 | ||||
-rw-r--r-- | ASTPrinter.h | 116 | ||||
-rw-r--r-- | ASTVisitor.h | 2 | ||||
-rw-r--r-- | NameAndTypeResolver.cpp | 142 | ||||
-rw-r--r-- | NameAndTypeResolver.h | 40 | ||||
-rw-r--r-- | Parser.cpp | 9 | ||||
-rw-r--r-- | Parser.h | 4 | ||||
-rw-r--r-- | Scope.h | 39 |
10 files changed, 318 insertions, 64 deletions
@@ -72,6 +72,9 @@ public: virtual void accept(ASTVisitor& _visitor) override; const ASTString& getName() const { return *m_name; } + vecptr<StructDefinition> const& getDefinedStructs() { return m_definedStructs; } + vecptr<VariableDeclaration> const& getStateVariables() { return m_stateVariables; } + vecptr<FunctionDefinition> const& getDefinedFunctions() { return m_definedFunctions; } private: ptr<ASTString> m_name; vecptr<StructDefinition> m_definedStructs; @@ -105,6 +108,8 @@ public: : ASTNode(_location), m_parameters(_parameters) {} virtual void accept(ASTVisitor& _visitor) override; + + vecptr<VariableDeclaration> const& getParameters() { return m_parameters; } private: vecptr<VariableDeclaration> m_parameters; }; @@ -126,12 +131,16 @@ public: const ASTString& getName() const { return *m_name; } bool isPublic() const { return m_isPublic; } bool isDeclaredConst() const { return m_isDeclaredConst; } + vecptr<VariableDeclaration> const& getParameters() { return m_parameters->getParameters(); } + bool hasReturnParameters() const { return m_returnParameters.get() != nullptr; } + vecptr<VariableDeclaration> const& getReturnParameters() { return m_returnParameters->getParameters(); } + Block& getBody() { return *m_body; } private: ptr<ASTString> m_name; bool m_isPublic; ptr<ParameterList> m_parameters; bool m_isDeclaredConst; - ptr<ParameterList> m_returnParameters; + ptr<ParameterList> m_returnParameters; //< either "null"pointer or pointer to non-empty parameter list ptr<Block> m_body; }; @@ -145,6 +154,7 @@ public: {} virtual void accept(ASTVisitor& _visitor) override; + TypeName* getTypeName() const { return m_type.get(); } const ASTString& getName() const { return *m_name; } private: ptr<TypeName> m_type; ///< can be empty ("var") @@ -416,8 +426,13 @@ public: virtual void accept(ASTVisitor& _visitor) override; ASTString const& getName() const { return *m_name; } + void setReferencedObject(ASTNode& _referencedObject) { m_referencedObject = &_referencedObject; } + ASTNode* getReferencedVariable() { return m_referencedObject; } private: ptr<ASTString> m_name; + + //! Node the name refers to. Has to be a declaration of some sort. + ASTNode* m_referencedObject; }; class ElementaryTypeNameExpression : public PrimaryExpression diff --git a/ASTForward.h b/ASTForward.h index b930a223..963e3d47 100644 --- a/ASTForward.h +++ b/ASTForward.h @@ -36,6 +36,7 @@ class FunctionCall; class MemberAccess; class IndexAccess; class PrimaryExpression; +class Identifier; class ElementaryTypeNameExpression; class Literal; diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp index a5fcf959..12969621 100644 --- a/ASTPrinter.cpp +++ b/ASTPrinter.cpp @@ -202,6 +202,13 @@ bool ASTPrinter::visit(PrimaryExpression& _node) return goDeeper(); } +bool ASTPrinter::visit(Identifier& _node) +{ + writeLine(std::string("Identifier ") + _node.getName()); + printSourcePart(_node); + return goDeeper(); +} + bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) { writeLine(std::string("ElementaryTypeNameExpression ") + Token::String(_node.getType())); @@ -356,6 +363,11 @@ void ASTPrinter::endVisit(PrimaryExpression&) m_indentation--; } +void ASTPrinter::endVisit(Identifier&) +{ + m_indentation--; +} + void ASTPrinter::endVisit(ElementaryTypeNameExpression&) { m_indentation--; diff --git a/ASTPrinter.h b/ASTPrinter.h index d3cad11c..8e908a84 100644 --- a/ASTPrinter.h +++ b/ASTPrinter.h @@ -15,64 +15,66 @@ public: /// Output the string representation of the AST to _stream. void print(std::ostream& _stream); - bool visit(ContractDefinition& _node); - bool visit(StructDefinition& _node); - bool visit(ParameterList& _node); - bool visit(FunctionDefinition& _node); - bool visit(VariableDeclaration& _node); - bool visit(TypeName& _node); - bool visit(ElementaryTypeName& _node); - bool visit(UserDefinedTypeName& _node); - bool visit(Mapping& _node); - bool visit(Statement& _node); - bool visit(Block& _node); - bool visit(IfStatement& _node); - bool visit(BreakableStatement& _node); - bool visit(WhileStatement& _node); - bool visit(Continue& _node); - bool visit(Break& _node); - bool visit(Return& _node); - bool visit(VariableDefinition& _node); - bool visit(Expression& _node); - bool visit(Assignment& _node); - bool visit(UnaryOperation& _node); - bool visit(BinaryOperation& _node); - bool visit(FunctionCall& _node); - bool visit(MemberAccess& _node); - bool visit(IndexAccess& _node); - bool visit(PrimaryExpression& _node); - bool visit(ElementaryTypeNameExpression& _node); - bool visit(Literal& _node); + 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(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; - void endVisit(ASTNode & _node); - void endVisit(ContractDefinition&); - void endVisit(StructDefinition&); - void endVisit(ParameterList&); - void endVisit(FunctionDefinition&); - void endVisit(VariableDeclaration&); - void endVisit(TypeName&); - void endVisit(ElementaryTypeName&); - void endVisit(UserDefinedTypeName&); - void endVisit(Mapping&); - void endVisit(Statement&); - void endVisit(Block&); - void endVisit(IfStatement&); - void endVisit(BreakableStatement&); - void endVisit(WhileStatement&); - void endVisit(Continue&); - void endVisit(Break&); - void endVisit(Return&); - void endVisit(VariableDefinition&); - void endVisit(Expression&); - void endVisit(Assignment&); - void endVisit(UnaryOperation&); - void endVisit(BinaryOperation&); - void endVisit(FunctionCall&); - void endVisit(MemberAccess&); - void endVisit(IndexAccess&); - void endVisit(PrimaryExpression&); - void endVisit(ElementaryTypeNameExpression&); - void endVisit(Literal&); + 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(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; private: void printSourcePart(ASTNode const& _node); diff --git a/ASTVisitor.h b/ASTVisitor.h index a68d76ae..f3ae3be7 100644 --- a/ASTVisitor.h +++ b/ASTVisitor.h @@ -39,6 +39,7 @@ public: virtual bool visit(MemberAccess&) { return true; } virtual bool visit(IndexAccess&) { return true; } virtual bool visit(PrimaryExpression&) { return true; } + virtual bool visit(Identifier&) { return true; } virtual bool visit(ElementaryTypeNameExpression&) { return true; } virtual bool visit(Literal&) { return true; } @@ -69,6 +70,7 @@ public: virtual void endVisit(MemberAccess&) { } virtual void endVisit(IndexAccess&) { } virtual void endVisit(PrimaryExpression&) { } + virtual void endVisit(Identifier&) { } virtual void endVisit(ElementaryTypeNameExpression&) { } virtual void endVisit(Literal&) { } }; diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp new file mode 100644 index 00000000..c4f0612b --- /dev/null +++ b/NameAndTypeResolver.cpp @@ -0,0 +1,142 @@ +#include <libsolidity/NameAndTypeResolver.h> + +#include <libsolidity/AST.h> +#include <boost/assert.hpp> + +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<VariableDeclaration> const& variable : _contract.getStateVariables()) + registerName(variable->getName(), *variable); + // @todo structs + + for (ptr<FunctionDefinition> 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<VariableDeclaration> const& variable : _function.getParameters()) + registerName(variable->getName(), *variable); + if (_function.hasReturnParameters()) + for (ptr<VariableDeclaration> 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(); +} + +} } diff --git a/NameAndTypeResolver.h b/NameAndTypeResolver.h new file mode 100644 index 00000000..ca714ac2 --- /dev/null +++ b/NameAndTypeResolver.h @@ -0,0 +1,40 @@ +#pragma once + +#include <map> + +#include <libsolidity/Scope.h> +#include <libsolidity/ASTVisitor.h> + +namespace dev { +namespace solidity { + +class NameAndTypeResolver +{ +public: + NameAndTypeResolver(); + + void resolveNamesAndTypes(ContractDefinition& _contract); +private: + class ScopeHelper; //< RIIA helper to open and close scopes + + void reset(); + + void handleContract(ContractDefinition& _contract); + void handleFunction(FunctionDefinition& _function); + void handleFunctionBody(Block& _functionBody); + void registerVariablesInFunction(Block& _functionBody); + void resolveReferencesInFunction(Block& _functionBody); + + void registerName(ASTString const& _name, ASTNode& _declaration); + ASTNode* getNameFromCurrentScope(ASTString const& _name, bool _recursive = true); + + void enterNewSubScope(ASTNode& _node); + void closeCurrentScope(); + + Scope m_globalScope; // not part of the map + std::map<ASTNode*, Scope> m_scopes; + + Scope* m_currentScope; +}; + +} } @@ -28,7 +28,7 @@ namespace dev { namespace solidity { -ptr<ASTNode> Parser::parse(std::shared_ptr<Scanner> const& _scanner) +ptr<ContractDefinition> Parser::parse(std::shared_ptr<Scanner> const& _scanner) { m_scanner = _scanner; @@ -132,8 +132,9 @@ ptr<FunctionDefinition> Parser::parseFunctionDefinition(bool _isPublic) } ptr<ParameterList> returnParameters; if (m_scanner->getCurrentToken() == Token::RETURNS) { + const bool permitEmptyParameterList = false; m_scanner->next(); - returnParameters = parseParameterList(); + returnParameters = parseParameterList(permitEmptyParameterList); } ptr<Block> block = parseBlock(); nodeFactory.setEndPositionFromNode(block); @@ -212,13 +213,13 @@ ptr<Mapping> Parser::parseMapping() return nodeFactory.createNode<Mapping>(keyType, valueType); } -ptr<ParameterList> Parser::parseParameterList() +ptr<ParameterList> Parser::parseParameterList(bool _permitEmpty) { ASTNodeFactory nodeFactory(*this); vecptr<VariableDeclaration> parameters; expectToken(Token::LPAREN); - if (m_scanner->getCurrentToken() != Token::RPAREN) { + if (!_permitEmpty || m_scanner->getCurrentToken() != Token::RPAREN) { parameters.push_back(parseVariableDeclaration()); while (m_scanner->getCurrentToken() != Token::RPAREN) { expectToken(Token::COMMA); @@ -32,7 +32,7 @@ class Scanner; class Parser { public: - ptr<ASTNode> parse(std::shared_ptr<Scanner> const& _scanner); + ptr<ContractDefinition> parse(std::shared_ptr<Scanner> const& _scanner); private: class ASTNodeFactory; @@ -50,7 +50,7 @@ private: ptr<VariableDeclaration> parseVariableDeclaration(); ptr<TypeName> parseTypeName(); ptr<Mapping> parseMapping(); - ptr<ParameterList> parseParameterList(); + ptr<ParameterList> parseParameterList(bool _permitEmpty = true); ptr<Block> parseBlock(); ptr<Statement> parseStatement(); ptr<IfStatement> parseIfStatement(); diff --git a/Scope.h b/Scope.h new file mode 100644 index 00000000..c0aede94 --- /dev/null +++ b/Scope.h @@ -0,0 +1,39 @@ +#pragma once + +#include <map> + +#include <libsolidity/ASTForward.h> + +namespace dev { +namespace solidity { + +class Scope +{ +public: + explicit Scope(Scope* _outerScope = nullptr) : m_outerScope(_outerScope) {} + /// Registers the name _name in the scope unless it is already declared. Returns true iff + /// it was not yet declared. + bool registerName(ASTString const& _name, ASTNode& _declaration) + { + if (m_declaredNames.find(_name) != m_declaredNames.end()) + return false; + m_declaredNames[_name] = &_declaration; + return true; + } + ASTNode* resolveName(ASTString const& _name, bool _recursive = false) const + { + auto result = m_declaredNames.find(_name); + if (result != m_declaredNames.end()) + return result->second; + if (_recursive && m_outerScope != nullptr) + return m_outerScope->resolveName(_name, true); + return nullptr; + } + Scope* getOuterScope() const { return m_outerScope; } + +private: + Scope* m_outerScope; + std::map<ASTString, ASTNode*> m_declaredNames; +}; + +} } |