aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2014-10-13 21:07:21 +0800
committerChristian <c@ethdev.com>2014-10-13 23:02:21 +0800
commit4f791179640fdcfbbd62c4c7a2a5273081b7b742 (patch)
tree7c7576b991884befde24473b5f6370b8afa83b2f
parent98bdd7429974521946a1aa3bffa038fc515f745c (diff)
downloaddexon-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.h17
-rw-r--r--ASTForward.h1
-rw-r--r--ASTPrinter.cpp12
-rw-r--r--ASTPrinter.h116
-rw-r--r--ASTVisitor.h2
-rw-r--r--NameAndTypeResolver.cpp142
-rw-r--r--NameAndTypeResolver.h40
-rw-r--r--Parser.cpp9
-rw-r--r--Parser.h4
-rw-r--r--Scope.h39
10 files changed, 318 insertions, 64 deletions
diff --git a/AST.h b/AST.h
index bedb5f10..cbb78087 100644
--- a/AST.h
+++ b/AST.h
@@ -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;
+};
+
+} }
diff --git a/Parser.cpp b/Parser.cpp
index 3ccd0930..eb171cbc 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -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);
diff --git a/Parser.h b/Parser.h
index f8940d1a..88369052 100644
--- a/Parser.h
+++ b/Parser.h
@@ -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;
+};
+
+} }