From 98bdd7429974521946a1aa3bffa038fc515f745c Mon Sep 17 00:00:00 2001 From: Christian Date: Fri, 10 Oct 2014 16:37:54 +0200 Subject: [PATCH] AST printer and command line tool, some fixes. --- AST.cpp | 232 +++++++++++++++++++++++++++++ AST.h | 118 ++++++++++----- ASTForward.h | 53 +++++++ ASTPrinter.cpp | 388 +++++++++++++++++++++++++++++++++++++++++++++++++ ASTPrinter.h | 88 +++++++++++ ASTVisitor.h | 76 ++++++++++ Parser.cpp | 52 ++++--- Parser.h | 3 +- 8 files changed, 955 insertions(+), 55 deletions(-) create mode 100644 ASTForward.h create mode 100644 ASTPrinter.cpp create mode 100644 ASTPrinter.h create mode 100644 ASTVisitor.h diff --git a/AST.cpp b/AST.cpp index 76e1ff444..e0775c6ce 100644 --- a/AST.cpp +++ b/AST.cpp @@ -21,3 +21,235 @@ */ #include +#include + +namespace dev { +namespace solidity { + +void ContractDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + listAccept(m_definedStructs, _visitor); + listAccept(m_stateVariables, _visitor); + listAccept(m_definedFunctions, _visitor); + } + _visitor.endVisit(*this); +} + +void StructDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + listAccept(m_members, _visitor); + } + _visitor.endVisit(*this); +} + +void ParameterList::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + listAccept(m_parameters, _visitor); + } + _visitor.endVisit(*this); +} + +void FunctionDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_parameters->accept(_visitor); + if (m_returnParameters) + m_returnParameters->accept(_visitor); + m_body->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void VariableDeclaration::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + if (m_type) + m_type->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void TypeName::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void ElementaryTypeName::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void UserDefinedTypeName::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Mapping::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_keyType->accept(_visitor); + m_valueType->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Statement::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Block::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + listAccept(m_statements, _visitor); + } + _visitor.endVisit(*this); +} + +void IfStatement::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_condition->accept(_visitor); + m_trueBody->accept(_visitor); + if (m_falseBody) + m_falseBody->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void BreakableStatement::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void WhileStatement::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_condition->accept(_visitor); + m_body->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Continue::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Break::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Return::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + if (m_expression) + m_expression->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void VariableDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_variable->accept(_visitor); + if (m_value) + m_value->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void Expression::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Assignment::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_leftHandSide->accept(_visitor); + m_rightHandSide->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void UnaryOperation::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_subExpression->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void BinaryOperation::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_left->accept(_visitor); + m_right->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void FunctionCall::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_expression->accept(_visitor); + listAccept(m_arguments, _visitor); + } + _visitor.endVisit(*this); +} + +void MemberAccess::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_expression->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void IndexAccess::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) { + m_base->accept(_visitor); + m_index->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void PrimaryExpression::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Identifier::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void ElementaryTypeNameExpression::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +void Literal::accept(ASTVisitor& _visitor) +{ + _visitor.visit(*this); + _visitor.endVisit(*this); +} + +} } diff --git a/AST.h b/AST.h index 9a4b95215..bedb5f106 100644 --- a/AST.h +++ b/AST.h @@ -26,26 +26,14 @@ #include #include +#include #include #include namespace dev { namespace solidity { -// Used as pointers to AST nodes, to be replaced by more clever pointers, e.g. pointers which do -// not do reference counting but point to a special memory area that is completely released -// explicitly. -template -using ptr = std::shared_ptr; -template -using vecptr = std::vector>; - -class VariableDeclaration; -class StructDefinition; -class FunctionDefinition; -class TypeName; -class Block; -class Expression; +class ASTVisitor; class ASTNode { @@ -56,7 +44,13 @@ public: virtual ~ASTNode() {} - Location getLocation() const { return m_location; } + virtual void accept(ASTVisitor& _visitor) = 0; + template + static void listAccept(vecptr& _list, ASTVisitor& _visitor) { + for (ptr& element : _list) element->accept(_visitor); + } + + Location const& getLocation() const { return m_location; } private: Location m_location; }; @@ -65,7 +59,7 @@ class ContractDefinition : public ASTNode { public: ContractDefinition(Location const& _location, - std::string const& _name, + ptr const& _name, vecptr const& _definedStructs, vecptr const& _stateVariables, vecptr const& _definedFunctions) @@ -75,8 +69,11 @@ public: m_definedFunctions(_definedFunctions) {} + virtual void accept(ASTVisitor& _visitor) override; + + const ASTString& getName() const { return *m_name; } private: - std::string m_name; + ptr m_name; vecptr m_definedStructs; vecptr m_stateVariables; vecptr m_definedFunctions; @@ -86,12 +83,15 @@ class StructDefinition : public ASTNode { public: StructDefinition(Location const& _location, - std::string const& _name, + ptr const& _name, vecptr const& _members) : ASTNode(_location), m_name(_name), m_members(_members) {} + virtual void accept(ASTVisitor& _visitor) override; + + const ASTString& getName() const { return *m_name; } private: - std::string m_name; + ptr m_name; vecptr m_members; }; @@ -104,6 +104,7 @@ public: ParameterList(Location const& _location, vecptr const& _parameters) : ASTNode(_location), m_parameters(_parameters) {} + virtual void accept(ASTVisitor& _visitor) override; private: vecptr m_parameters; }; @@ -111,7 +112,7 @@ private: class FunctionDefinition : public ASTNode { public: - FunctionDefinition(Location const& _location, std::string const& _name, bool _isPublic, + FunctionDefinition(Location const& _location, ptr const& _name, bool _isPublic, ptr const& _parameters, bool _isDeclaredConst, ptr const& _returnParameters, @@ -120,8 +121,13 @@ public: m_isDeclaredConst(_isDeclaredConst), m_returnParameters(_returnParameters), m_body(_body) {} + virtual void accept(ASTVisitor& _visitor) override; + + const ASTString& getName() const { return *m_name; } + bool isPublic() const { return m_isPublic; } + bool isDeclaredConst() const { return m_isDeclaredConst; } private: - std::string m_name; + ptr m_name; bool m_isPublic; ptr m_parameters; bool m_isDeclaredConst; @@ -134,12 +140,15 @@ class VariableDeclaration : public ASTNode public: VariableDeclaration(Location const& _location, ptr const& _type, - std::string const& _name) + ptr const& _name) : ASTNode(_location), m_type(_type), m_name(_name) {} + virtual void accept(ASTVisitor& _visitor) override; + + const ASTString& getName() const { return *m_name; } private: ptr m_type; ///< can be empty ("var") - std::string m_name; + ptr m_name; }; /// types @@ -149,6 +158,7 @@ class TypeName : public ASTNode { public: explicit TypeName(Location const& _location) : ASTNode(_location) {} + virtual void accept(ASTVisitor& _visitor) override; }; /// any pre-defined type that is not a mapping @@ -158,6 +168,9 @@ public: explicit ElementaryTypeName(Location const& _location, Token::Value _type) : TypeName(_location), m_type(_type) {} + virtual void accept(ASTVisitor& _visitor) override; + + Token::Value getType() const { return m_type; } private: Token::Value m_type; }; @@ -165,11 +178,14 @@ private: class UserDefinedTypeName : public TypeName { public: - UserDefinedTypeName(Location const& _location, std::string const& _name) + UserDefinedTypeName(Location const& _location, ptr const& _name) : TypeName(_location), m_name(_name) {} + virtual void accept(ASTVisitor& _visitor) override; + + const ASTString& getName() const { return *m_name; } private: - std::string m_name; + ptr m_name; }; class Mapping : public TypeName @@ -179,6 +195,7 @@ public: ptr const& _valueType) : TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {} + virtual void accept(ASTVisitor& _visitor) override; private: ptr m_keyType; ptr m_valueType; @@ -193,6 +210,7 @@ class Statement : public ASTNode { public: explicit Statement(Location const& _location) : ASTNode(_location) {} + virtual void accept(ASTVisitor& _visitor) override; }; class Block : public Statement @@ -201,6 +219,7 @@ public: Block(Location const& _location, vecptr const& _statements) : Statement(_location), m_statements(_statements) {} + virtual void accept(ASTVisitor& _visitor) override; private: vecptr m_statements; }; @@ -213,16 +232,18 @@ public: : Statement(_location), m_condition(_condition), m_trueBody(_trueBody), m_falseBody(_falseBody) {} + virtual void accept(ASTVisitor& _visitor) override; private: ptr m_condition; ptr m_trueBody; - ptr m_falseBody; + ptr m_falseBody; //< "else" part, optional }; class BreakableStatement : public Statement { public: BreakableStatement(Location const& _location) : Statement(_location) {} + virtual void accept(ASTVisitor& _visitor) override; }; class WhileStatement : public BreakableStatement @@ -232,6 +253,7 @@ public: ptr const& _body) : BreakableStatement(_location), m_condition(_condition), m_body(_body) {} + virtual void accept(ASTVisitor& _visitor) override; private: ptr m_condition; ptr m_body; @@ -241,12 +263,14 @@ class Continue : public Statement { public: Continue(Location const& _location) : Statement(_location) {} + virtual void accept(ASTVisitor& _visitor) override; }; class Break : public Statement { public: Break(Location const& _location) : Statement(_location) {} + virtual void accept(ASTVisitor& _visitor) override; }; class Return : public Statement @@ -255,8 +279,9 @@ public: Return(Location const& _location, ptr _expression) : Statement(_location), m_expression(_expression) {} + virtual void accept(ASTVisitor& _visitor) override; private: - ptr m_expression; + ptr m_expression; //< value to return, optional }; class VariableDefinition : public Statement @@ -266,6 +291,7 @@ public: ptr _value) : Statement(_location), m_variable(_variable), m_value(_value) {} + virtual void accept(ASTVisitor& _visitor) override; private: ptr m_variable; ptr m_value; ///< can be missing @@ -275,6 +301,7 @@ class Expression : public Statement { public: Expression(Location const& _location) : Statement(_location) {} + virtual void accept(ASTVisitor& _visitor) override; }; /// @} @@ -290,6 +317,9 @@ public: : Expression(_location), m_leftHandSide(_leftHandSide), m_assigmentOperator(_assignmentOperator), m_rightHandSide(_rightHandSide) {} + virtual void accept(ASTVisitor& _visitor) override; + + Token::Value getAssignmentOperator() const { return m_assigmentOperator; } private: ptr m_leftHandSide; Token::Value m_assigmentOperator; @@ -304,7 +334,10 @@ public: : Expression(_location), m_operator(_operator), m_subExpression(_subExpression), m_isPrefix(_isPrefix) {} + virtual void accept(ASTVisitor& _visitor) override; + Token::Value getOperator() const { return m_operator; } + bool isPrefixOperation() const { return m_isPrefix; } private: Token::Value m_operator; ptr m_subExpression; @@ -318,6 +351,9 @@ public: Token::Value _operator, ptr const& _right) : Expression(_location), m_left(_left), m_operator(_operator), m_right(_right) {} + virtual void accept(ASTVisitor& _visitor) override; + + Token::Value getOperator() const { return m_operator; } private: ptr m_left; Token::Value m_operator; @@ -332,6 +368,7 @@ public: vecptr const& _arguments) : Expression(_location), m_expression(_expression), m_arguments(_arguments) {} + virtual void accept(ASTVisitor& _visitor) override; private: ptr m_expression; vecptr m_arguments; @@ -341,12 +378,14 @@ class MemberAccess : public Expression { public: MemberAccess(Location const& _location, ptr _expression, - std::string const& _memberName) + ptr const& _memberName) : Expression(_location), m_expression(_expression), m_memberName(_memberName) {} + virtual void accept(ASTVisitor& _visitor) override; + const ASTString& getMemberName() const { return *m_memberName; } private: ptr m_expression; - std::string m_memberName; + ptr m_memberName; }; class IndexAccess : public Expression @@ -356,6 +395,7 @@ public: ptr const& _index) : Expression(_location), m_base(_base), m_index(_index) {} + virtual void accept(ASTVisitor& _visitor) override; private: ptr m_base; ptr m_index; @@ -365,15 +405,19 @@ class PrimaryExpression : public Expression { public: PrimaryExpression(Location const& _location) : Expression(_location) {} + virtual void accept(ASTVisitor& _visitor) override; }; class Identifier : public PrimaryExpression { public: - Identifier(Location const& _location, std::string const& _name) + Identifier(Location const& _location, ptr const& _name) : PrimaryExpression(_location), m_name(_name) {} + virtual void accept(ASTVisitor& _visitor) override; + + ASTString const& getName() const { return *m_name; } private: - std::string m_name; + ptr m_name; }; class ElementaryTypeNameExpression : public PrimaryExpression @@ -381,6 +425,9 @@ class ElementaryTypeNameExpression : public PrimaryExpression public: ElementaryTypeNameExpression(Location const& _location, Token::Value _type) : PrimaryExpression(_location), m_type(_type) {} + virtual void accept(ASTVisitor& _visitor) override; + + Token::Value getType() const { return m_type; } private: Token::Value m_type; }; @@ -388,15 +435,18 @@ private: class Literal : public PrimaryExpression { public: - Literal(Location const& _location, Token::Value _token, std::string const& _value) + Literal(Location const& _location, Token::Value _token, ptr const& _value) : PrimaryExpression(_location), m_token(_token), m_value(_value) {} + virtual void accept(ASTVisitor& _visitor) override; + + Token::Value getToken() const { return m_token; } + ASTString const& getValue() const { return *m_value; } private: Token::Value m_token; - std::string m_value; + ptr m_value; }; /// @} - } } diff --git a/ASTForward.h b/ASTForward.h new file mode 100644 index 000000000..b930a2238 --- /dev/null +++ b/ASTForward.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include + +// Forward-declare all AST node types + +namespace dev { +namespace solidity { + +class ASTNode; +class ContractDefinition; +class StructDefinition; +class ParameterList; +class FunctionDefinition; +class VariableDeclaration; +class TypeName; +class ElementaryTypeName; +class UserDefinedTypeName; +class Mapping; +class Statement; +class Block; +class IfStatement; +class BreakableStatement; +class WhileStatement; +class Continue; +class Break; +class Return; +class VariableDefinition; +class Expression; +class Assignment; +class UnaryOperation; +class BinaryOperation; +class FunctionCall; +class MemberAccess; +class IndexAccess; +class PrimaryExpression; +class ElementaryTypeNameExpression; +class Literal; + +// Used as pointers to AST nodes, to be replaced by more clever pointers, e.g. pointers which do +// not do reference counting but point to a special memory area that is completely released +// explicitly. +template +using ptr = std::shared_ptr; +template +using vecptr = std::vector>; + +using ASTString = std::string; + + +} } diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp new file mode 100644 index 000000000..a5fcf959f --- /dev/null +++ b/ASTPrinter.cpp @@ -0,0 +1,388 @@ +#include +#include + +namespace dev { +namespace solidity { + +ASTPrinter::ASTPrinter(ptr _ast, const std::string& _source) + : m_indentation(0), m_source(_source), m_ast(_ast) +{ +} + +void ASTPrinter::print(std::ostream& _stream) +{ + m_ostream = &_stream; + m_ast->accept(*this); + m_ostream = nullptr; +} + + +bool ASTPrinter::visit(ContractDefinition& _node) +{ + writeLine("ContractDefinition \"" + _node.getName() + "\""); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(StructDefinition& _node) +{ + writeLine("StructDefinition \"" + _node.getName() + "\""); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(ParameterList& _node) +{ + writeLine("ParameterList"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(FunctionDefinition& _node) +{ + writeLine("FunctionDefinition \"" + _node.getName() + "\"" + + (_node.isPublic() ? " - public" : "") + + (_node.isDeclaredConst() ? " - const" : "")); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(VariableDeclaration& _node) +{ + writeLine("VariableDeclaration \"" + _node.getName() + "\""); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(TypeName& _node) +{ + writeLine("TypeName"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(ElementaryTypeName& _node) +{ + writeLine(std::string("ElementaryTypeName ") + Token::String(_node.getType())); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(UserDefinedTypeName& _node) +{ + writeLine("UserDefinedTypeName \"" + _node.getName() + "\""); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Mapping& _node) +{ + writeLine("Mapping"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Statement& _node) +{ + writeLine("Statement"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Block& _node) +{ + writeLine("Block"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(IfStatement& _node) +{ + writeLine("IfStatement"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(BreakableStatement& _node) +{ + writeLine("BreakableStatement"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(WhileStatement& _node) +{ + writeLine("WhileStatement"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Continue& _node) +{ + writeLine("Continue"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Break& _node) +{ + writeLine("Break"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Return& _node) +{ + writeLine("Return"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(VariableDefinition& _node) +{ + writeLine("VariableDefinition"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Expression& _node) +{ + writeLine("Expression"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Assignment& _node) +{ + writeLine(std::string("Assignment using operator ") + Token::String(_node.getAssignmentOperator())); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(UnaryOperation& _node) +{ + writeLine(std::string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") + + ") " + Token::String(_node.getOperator())); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(BinaryOperation& _node) +{ + writeLine(std::string("BinaryOperation using operator ") + Token::String(_node.getOperator())); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(FunctionCall& _node) +{ + writeLine("FunctionCall"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(MemberAccess& _node) +{ + writeLine("MemberAccess to member " + _node.getMemberName()); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(IndexAccess& _node) +{ + writeLine("IndexAccess"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(PrimaryExpression& _node) +{ + writeLine("PrimaryExpression"); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(ElementaryTypeNameExpression& _node) +{ + writeLine(std::string("ElementaryTypeNameExpression ") + Token::String(_node.getType())); + printSourcePart(_node); + return goDeeper(); +} + +bool ASTPrinter::visit(Literal& _node) +{ + const char* tokenString = Token::String(_node.getToken()); + if (tokenString == nullptr) + tokenString = "----"; + writeLine(std::string("Literal, token: ") + tokenString + " value: " + _node.getValue()); + printSourcePart(_node); + return goDeeper(); +} + +void ASTPrinter::endVisit(ASTNode&) +{ + m_indentation--; +} + +// @todo instead of this, we could make the default implementation of endVisit call the +// superclass' endVisit +void ASTPrinter::endVisit(ContractDefinition&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(StructDefinition&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(ParameterList&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(FunctionDefinition&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(VariableDeclaration&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(TypeName&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(ElementaryTypeName&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(UserDefinedTypeName&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Mapping&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Statement&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Block&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(IfStatement&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(BreakableStatement&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(WhileStatement&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Continue&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Break&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Return&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(VariableDefinition&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Expression&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Assignment&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(UnaryOperation&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(BinaryOperation&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(FunctionCall&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(MemberAccess&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(IndexAccess&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(PrimaryExpression&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(ElementaryTypeNameExpression&) +{ + m_indentation--; +} + +void ASTPrinter::endVisit(Literal&) +{ + m_indentation--; +} + +void ASTPrinter::printSourcePart(ASTNode const& _node) +{ + if (!m_source.empty()) { + Location const& location(_node.getLocation()); + *m_ostream << getIndentation() << " Source: |" + << m_source.substr(location.start, location.end - location.start) << "|\n"; + } +} + +std::string ASTPrinter::getIndentation() const +{ + return std::string(m_indentation * 2, ' '); +} + +void ASTPrinter::writeLine(const std::string& _line) +{ + *m_ostream << getIndentation() << _line << '\n'; +} + +} } diff --git a/ASTPrinter.h b/ASTPrinter.h new file mode 100644 index 000000000..d3cad11c2 --- /dev/null +++ b/ASTPrinter.h @@ -0,0 +1,88 @@ +#pragma once + +#include +#include + +namespace dev { +namespace solidity { + +class ASTPrinter : public ASTVisitor +{ +public: + /// Create a printer for the given abstract syntax tree. If the source is specified, + /// the corresponding parts of the source are printed with each node. + ASTPrinter(ptr _ast, const std::string& _source = std::string()); + /// 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); + + 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&); + +private: + void printSourcePart(ASTNode const& _node); + std::string getIndentation() const; + void writeLine(std::string const& _line); + bool goDeeper() { m_indentation++; return true; } + int m_indentation; + std::string m_source; + ptr m_ast; + std::ostream* m_ostream; +}; + +} } diff --git a/ASTVisitor.h b/ASTVisitor.h new file mode 100644 index 000000000..a68d76aee --- /dev/null +++ b/ASTVisitor.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +namespace dev { +namespace solidity { + +class ASTVisitor { +public: + /// These functions are called after a call to ASTNode::accept, + /// first visit, then (if visit returns true) recursively for all + /// child nodes in document order (exception for contracts) and then + /// endVisit. + virtual bool visit(ASTNode&) { return true; } + virtual bool visit(ContractDefinition&) { return true; } + virtual bool visit(StructDefinition&) { return true; } + virtual bool visit(ParameterList&) { return true; } + virtual bool visit(FunctionDefinition&) { return true; } + virtual bool visit(VariableDeclaration&) { return true; } + virtual bool visit(TypeName&) { return true; } + virtual bool visit(ElementaryTypeName&) { return true; } + virtual bool visit(UserDefinedTypeName&) { return true; } + virtual bool visit(Mapping&) { return true; } + virtual bool visit(Statement&) { return true; } + virtual bool visit(Block&) { return true; } + virtual bool visit(IfStatement&) { return true; } + virtual bool visit(BreakableStatement&) { return true; } + virtual bool visit(WhileStatement&) { return true; } + virtual bool visit(Continue&) { return true; } + virtual bool visit(Break&) { return true; } + virtual bool visit(Return&) { return true; } + virtual bool visit(VariableDefinition&) { return true; } + virtual bool visit(Expression&) { return true; } + virtual bool visit(Assignment&) { return true; } + virtual bool visit(UnaryOperation&) { return true; } + virtual bool visit(BinaryOperation&) { return true; } + virtual bool visit(FunctionCall&) { return true; } + virtual bool visit(MemberAccess&) { return true; } + virtual bool visit(IndexAccess&) { return true; } + virtual bool visit(PrimaryExpression&) { return true; } + virtual bool visit(ElementaryTypeNameExpression&) { return true; } + virtual bool visit(Literal&) { return true; } + + virtual void endVisit(ASTNode&) { } + virtual void endVisit(ContractDefinition&) { } + virtual void endVisit(StructDefinition&) { } + virtual void endVisit(ParameterList&) { } + virtual void endVisit(FunctionDefinition&) { } + virtual void endVisit(VariableDeclaration&) { } + virtual void endVisit(TypeName&) { } + virtual void endVisit(ElementaryTypeName&) { } + virtual void endVisit(UserDefinedTypeName&) { } + virtual void endVisit(Mapping&) { } + virtual void endVisit(Statement&) { } + virtual void endVisit(Block&) { } + virtual void endVisit(IfStatement&) { } + virtual void endVisit(BreakableStatement&) { } + virtual void endVisit(WhileStatement&) { } + virtual void endVisit(Continue&) { } + virtual void endVisit(Break&) { } + virtual void endVisit(Return&) { } + virtual void endVisit(VariableDefinition&) { } + virtual void endVisit(Expression&) { } + virtual void endVisit(Assignment&) { } + virtual void endVisit(UnaryOperation&) { } + virtual void endVisit(BinaryOperation&) { } + virtual void endVisit(FunctionCall&) { } + virtual void endVisit(MemberAccess&) { } + virtual void endVisit(IndexAccess&) { } + virtual void endVisit(PrimaryExpression&) { } + virtual void endVisit(ElementaryTypeNameExpression&) { } + virtual void endVisit(Literal&) { } +}; + +} } diff --git a/Parser.cpp b/Parser.cpp index 24c8e599e..3ccd09300 100644 --- a/Parser.cpp +++ b/Parser.cpp @@ -57,7 +57,8 @@ public: template ptr createNode(Args&&... _args) { - if (m_location.end < 0) markEndPosition(); + if (m_location.end < 0) + markEndPosition(); return std::make_shared(m_location, std::forward(_args)...); } @@ -82,7 +83,7 @@ ptr Parser::parseContractDefinition() ASTNodeFactory nodeFactory(*this); expectToken(Token::CONTRACT); - std::string name = expectIdentifier(); + ptr name = expectIdentifierToken(); expectToken(Token::LBRACE); vecptr structs; @@ -111,7 +112,7 @@ ptr Parser::parseContractDefinition() } nodeFactory.markEndPosition(); - m_scanner->next(); + expectToken(Token::RBRACE); expectToken(Token::EOS); return nodeFactory.createNode(name, structs, stateVariables, functions); @@ -122,7 +123,7 @@ ptr Parser::parseFunctionDefinition(bool _isPublic) ASTNodeFactory nodeFactory(*this); expectToken(Token::FUNCTION); - std::string name(expectIdentifier()); + ptr name(expectIdentifierToken()); ptr parameters(parseParameterList()); bool isDeclaredConst = false; if (m_scanner->getCurrentToken() == Token::CONST) { @@ -145,7 +146,7 @@ ptr Parser::parseStructDefinition() ASTNodeFactory nodeFactory(*this); expectToken(Token::STRUCT); - std::string name = expectIdentifier(); + ptr name = expectIdentifierToken(); vecptr members; expectToken(Token::LBRACE); while (m_scanner->getCurrentToken() != Token::RBRACE) { @@ -164,8 +165,7 @@ ptr Parser::parseVariableDeclaration() ptr type = parseTypeName(); nodeFactory.markEndPosition(); - std::string name = expectIdentifier(); - return nodeFactory.createNode(type, name); + return nodeFactory.createNode(type, expectIdentifierToken()); } ptr Parser::parseTypeName() @@ -181,8 +181,9 @@ ptr Parser::parseTypeName() } else if (token == Token::MAPPING) { type = parseMapping(); } else if (token == Token::IDENTIFIER) { - type = ASTNodeFactory(*this).createNode(m_scanner->getCurrentLiteral()); - m_scanner->next(); + ASTNodeFactory nodeFactory(*this); + nodeFactory.markEndPosition(); + type = nodeFactory.createNode(expectIdentifierToken()); } else { throwExpectationError("Expected type name"); } @@ -410,8 +411,7 @@ ptr Parser::parseLeftHandSideExpression() { m_scanner->next(); nodeFactory.markEndPosition(); - std::string memberName = expectIdentifier(); - expression = nodeFactory.createNode(expression, memberName); + expression = nodeFactory.createNode(expression, expectIdentifierToken()); } break; case Token::LPAREN: @@ -431,19 +431,25 @@ ptr Parser::parseLeftHandSideExpression() ptr Parser::parsePrimaryExpression() { + ASTNodeFactory nodeFactory(*this); Token::Value token = m_scanner->getCurrentToken(); + ptr expression; + switch (token) { case Token::TRUE_LITERAL: case Token::FALSE_LITERAL: + expression = nodeFactory.createNode(token, ptr()); m_scanner->next(); - return ASTNodeFactory(*this).createNode(token, std::string()); + break; case Token::NUMBER: case Token::STRING_LITERAL: - m_scanner->next(); - return ASTNodeFactory(*this).createNode(token, m_scanner->getCurrentLiteral()); + nodeFactory.markEndPosition(); + expression = nodeFactory.createNode(token, getLiteralAndAdvance()); + break; case Token::IDENTIFIER: - m_scanner->next(); - return ASTNodeFactory(*this).createNode(m_scanner->getCurrentLiteral()); + nodeFactory.markEndPosition(); + expression = nodeFactory.createNode(getLiteralAndAdvance()); + break; case Token::LPAREN: { m_scanner->next(); @@ -454,13 +460,14 @@ ptr Parser::parsePrimaryExpression() default: if (Token::IsElementaryTypeName(token)) { // used for casts + expression = nodeFactory.createNode(token); m_scanner->next(); - return ASTNodeFactory(*this).createNode(token); } else { throwExpectationError("Expected primary expression."); return ptr(); // this is not reached } } + return expression; } vecptr Parser::parseFunctionCallArguments() @@ -492,14 +499,19 @@ Token::Value Parser::expectAssignmentOperator() return op; } -std::string Parser::expectIdentifier() +ptr Parser::expectIdentifierToken() { if (m_scanner->getCurrentToken() != Token::IDENTIFIER) throwExpectationError("Expected identifier"); - std::string literal = m_scanner->getCurrentLiteral(); + return getLiteralAndAdvance(); +} + +ptr Parser::getLiteralAndAdvance() +{ + ptr identifier = std::make_shared(m_scanner->getCurrentLiteral()); m_scanner->next(); - return literal; + return identifier; } void Parser::throwExpectationError(const std::string& _description) diff --git a/Parser.h b/Parser.h index 7036c3c20..f8940d1a6 100644 --- a/Parser.h +++ b/Parser.h @@ -69,7 +69,8 @@ private: /// If current token value is not _value, throw exception otherwise advance token. void expectToken(Token::Value _value); Token::Value expectAssignmentOperator(); - std::string expectIdentifier(); + ptr expectIdentifierToken(); + ptr getLiteralAndAdvance(); void throwExpectationError(const std::string& _description); /// @}