mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Name resolution.
This commit is contained in:
parent
98bdd74299
commit
4f79117964
17
AST.h
17
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
|
||||
|
@ -36,6 +36,7 @@ class FunctionCall;
|
||||
class MemberAccess;
|
||||
class IndexAccess;
|
||||
class PrimaryExpression;
|
||||
class Identifier;
|
||||
class ElementaryTypeNameExpression;
|
||||
class Literal;
|
||||
|
||||
|
@ -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--;
|
||||
|
116
ASTPrinter.h
116
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);
|
||||
|
@ -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
142
NameAndTypeResolver.cpp
Normal 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
40
NameAndTypeResolver.h
Normal 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;
|
||||
};
|
||||
|
||||
} }
|
@ -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);
|
||||
|
4
Parser.h
4
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();
|
||||
|
39
Scope.h
Normal file
39
Scope.h
Normal 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;
|
||||
};
|
||||
|
||||
} }
|
Loading…
Reference in New Issue
Block a user