Name resolution.

This commit is contained in:
Christian 2014-10-13 15:07:21 +02:00
parent 98bdd74299
commit 4f79117964
10 changed files with 318 additions and 64 deletions

17
AST.h
View File

@ -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

View File

@ -36,6 +36,7 @@ class FunctionCall;
class MemberAccess;
class IndexAccess;
class PrimaryExpression;
class Identifier;
class ElementaryTypeNameExpression;
class Literal;

View File

@ -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--;

View File

@ -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);

View File

@ -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&) { }
};

142
NameAndTypeResolver.cpp Normal file
View File

@ -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();
}
} }

40
NameAndTypeResolver.h Normal file
View File

@ -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;
};
} }

View File

@ -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);

View File

@ -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();

39
Scope.h Normal file
View File

@ -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;
};
} }