aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/ast
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-10-22 19:58:50 +0800
committerchriseth <c@ethdev.com>2015-10-22 19:58:50 +0800
commitcb8f6633b237dab7d54904e00fed111c176a812c (patch)
treeb2df13e7c4c16c01b6cdc7cd5c15932031185d95 /libsolidity/ast
parentd41f8b7ce702c3b25c48d27e2e895ccdcd04e4e0 (diff)
parente3dffb611fe1736e3ffa170e6d8dc4dee17366bd (diff)
downloaddexon-solidity-cb8f6633b237dab7d54904e00fed111c176a812c.tar
dexon-solidity-cb8f6633b237dab7d54904e00fed111c176a812c.tar.gz
dexon-solidity-cb8f6633b237dab7d54904e00fed111c176a812c.tar.bz2
dexon-solidity-cb8f6633b237dab7d54904e00fed111c176a812c.tar.lz
dexon-solidity-cb8f6633b237dab7d54904e00fed111c176a812c.tar.xz
dexon-solidity-cb8f6633b237dab7d54904e00fed111c176a812c.tar.zst
dexon-solidity-cb8f6633b237dab7d54904e00fed111c176a812c.zip
Merge pull request #163 from chriseth/fileReorg
File reorganisation.
Diffstat (limited to 'libsolidity/ast')
-rw-r--r--libsolidity/ast/AST.cpp365
-rw-r--r--libsolidity/ast/AST.h1354
-rw-r--r--libsolidity/ast/ASTAnnotations.cpp28
-rw-r--r--libsolidity/ast/ASTAnnotations.h140
-rw-r--r--libsolidity/ast/ASTForward.h96
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp470
-rw-r--r--libsolidity/ast/ASTJsonConverter.h136
-rw-r--r--libsolidity/ast/ASTPrinter.cpp569
-rw-r--r--libsolidity/ast/ASTPrinter.h145
-rw-r--r--libsolidity/ast/ASTUtils.cpp48
-rw-r--r--libsolidity/ast/ASTUtils.h54
-rw-r--r--libsolidity/ast/ASTVisitor.h294
-rw-r--r--libsolidity/ast/AST_accept.h721
-rw-r--r--libsolidity/ast/Types.cpp1921
-rw-r--r--libsolidity/ast/Types.h996
15 files changed, 7337 insertions, 0 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
new file mode 100644
index 00000000..71d80a36
--- /dev/null
+++ b/libsolidity/ast/AST.cpp
@@ -0,0 +1,365 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity abstract syntax tree.
+ */
+
+#include <algorithm>
+#include <functional>
+#include <libsolidity/interface/Utils.h>
+#include <libsolidity/ast/AST.h>
+#include <libsolidity/ast/ASTVisitor.h>
+#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/ast/AST_accept.h>
+
+#include <libdevcore/SHA3.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
+ASTNode::ASTNode(SourceLocation const& _location):
+ m_location(_location)
+{
+}
+
+ASTNode::~ASTNode()
+{
+ delete m_annotation;
+}
+
+ASTAnnotation& ASTNode::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new ASTAnnotation();
+ return *m_annotation;
+}
+
+Error ASTNode::createTypeError(string const& _description) const
+{
+ return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
+}
+
+map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const
+{
+ auto exportedFunctionList = interfaceFunctionList();
+
+ map<FixedHash<4>, FunctionTypePointer> exportedFunctions;
+ for (auto const& it: exportedFunctionList)
+ exportedFunctions.insert(it);
+
+ solAssert(
+ exportedFunctionList.size() == exportedFunctions.size(),
+ "Hash collision at Function Definition Hash calculation"
+ );
+
+ return exportedFunctions;
+}
+
+FunctionDefinition const* ContractDefinition::constructor() const
+{
+ for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions)
+ if (f->isConstructor())
+ return f.get();
+ return nullptr;
+}
+
+FunctionDefinition const* ContractDefinition::fallbackFunction() const
+{
+ for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
+ for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions())
+ if (f->name().empty())
+ return f.get();
+ return nullptr;
+}
+
+vector<ASTPointer<EventDefinition>> const& ContractDefinition::interfaceEvents() const
+{
+ if (!m_interfaceEvents)
+ {
+ set<string> eventsSeen;
+ m_interfaceEvents.reset(new vector<ASTPointer<EventDefinition>>());
+ for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
+ for (ASTPointer<EventDefinition> const& e: contract->events())
+ if (eventsSeen.count(e->name()) == 0)
+ {
+ eventsSeen.insert(e->name());
+ m_interfaceEvents->push_back(e);
+ }
+ }
+ return *m_interfaceEvents;
+}
+
+vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList() const
+{
+ if (!m_interfaceFunctionList)
+ {
+ set<string> functionsSeen;
+ set<string> signaturesSeen;
+ m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>());
+ for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
+ {
+ vector<FunctionTypePointer> functions;
+ for (ASTPointer<FunctionDefinition> const& f: contract->definedFunctions())
+ if (f->isPartOfExternalInterface())
+ functions.push_back(make_shared<FunctionType>(*f, false));
+ for (ASTPointer<VariableDeclaration> const& v: contract->stateVariables())
+ if (v->isPartOfExternalInterface())
+ functions.push_back(make_shared<FunctionType>(*v));
+ for (FunctionTypePointer const& fun: functions)
+ {
+ if (!fun->interfaceFunctionType())
+ // Fails hopefully because we already registered the error
+ continue;
+ string functionSignature = fun->externalSignature();
+ if (signaturesSeen.count(functionSignature) == 0)
+ {
+ signaturesSeen.insert(functionSignature);
+ FixedHash<4> hash(dev::sha3(functionSignature));
+ m_interfaceFunctionList->push_back(make_pair(hash, fun));
+ }
+ }
+ }
+ }
+ return *m_interfaceFunctionList;
+}
+
+string const& ContractDefinition::devDocumentation() const
+{
+ return m_devDocumentation;
+}
+
+string const& ContractDefinition::userDocumentation() const
+{
+ return m_userDocumentation;
+}
+
+void ContractDefinition::setDevDocumentation(string const& _devDocumentation)
+{
+ m_devDocumentation = _devDocumentation;
+}
+
+void ContractDefinition::setUserDocumentation(string const& _userDocumentation)
+{
+ m_userDocumentation = _userDocumentation;
+}
+
+
+vector<Declaration const*> const& ContractDefinition::inheritableMembers() const
+{
+ if (!m_inheritableMembers)
+ {
+ set<string> memberSeen;
+ m_inheritableMembers.reset(new vector<Declaration const*>());
+ auto addInheritableMember = [&](Declaration const* _decl)
+ {
+ if (memberSeen.count(_decl->name()) == 0 && _decl->isVisibleInDerivedContracts())
+ {
+ memberSeen.insert(_decl->name());
+ m_inheritableMembers->push_back(_decl);
+ }
+ };
+
+ for (ASTPointer<FunctionDefinition> const& f: definedFunctions())
+ addInheritableMember(f.get());
+
+ for (ASTPointer<VariableDeclaration> const& v: stateVariables())
+ addInheritableMember(v.get());
+
+ for (ASTPointer<StructDefinition> const& s: definedStructs())
+ addInheritableMember(s.get());
+ }
+ return *m_inheritableMembers;
+}
+
+TypePointer ContractDefinition::type(ContractDefinition const* m_currentContract) const
+{
+ return make_shared<TypeType>(make_shared<ContractType>(*this), m_currentContract);
+}
+
+ContractDefinitionAnnotation& ContractDefinition::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new ContractDefinitionAnnotation();
+ return static_cast<ContractDefinitionAnnotation&>(*m_annotation);
+}
+
+TypeNameAnnotation& TypeName::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new TypeNameAnnotation();
+ return static_cast<TypeNameAnnotation&>(*m_annotation);
+}
+
+TypePointer StructDefinition::type(ContractDefinition const*) const
+{
+ return make_shared<TypeType>(make_shared<StructType>(*this));
+}
+
+TypeDeclarationAnnotation& StructDefinition::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new TypeDeclarationAnnotation();
+ return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
+}
+
+TypePointer EnumValue::type(ContractDefinition const*) const
+{
+ auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
+ solAssert(parentDef, "Enclosing Scope of EnumValue was not set");
+ return make_shared<EnumType>(*parentDef);
+}
+
+TypePointer EnumDefinition::type(ContractDefinition const*) const
+{
+ return make_shared<TypeType>(make_shared<EnumType>(*this));
+}
+
+TypeDeclarationAnnotation& EnumDefinition::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new TypeDeclarationAnnotation();
+ return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
+}
+
+TypePointer FunctionDefinition::type(ContractDefinition const*) const
+{
+ return make_shared<FunctionType>(*this);
+}
+
+string FunctionDefinition::externalSignature() const
+{
+ return FunctionType(*this).externalSignature();
+}
+
+TypePointer ModifierDefinition::type(ContractDefinition const*) const
+{
+ return make_shared<ModifierType>(*this);
+}
+
+TypePointer EventDefinition::type(ContractDefinition const*) const
+{
+ return make_shared<FunctionType>(*this);
+}
+
+UserDefinedTypeNameAnnotation& UserDefinedTypeName::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new UserDefinedTypeNameAnnotation();
+ return static_cast<UserDefinedTypeNameAnnotation&>(*m_annotation);
+}
+
+bool VariableDeclaration::isLValue() const
+{
+ // External function parameters and constant declared variables are Read-Only
+ return !isExternalCallableParameter() && !m_isConstant;
+}
+
+bool VariableDeclaration::isCallableParameter() const
+{
+ auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
+ if (!callable)
+ return false;
+ for (auto const& variable: callable->parameters())
+ if (variable.get() == this)
+ return true;
+ if (callable->returnParameterList())
+ for (auto const& variable: callable->returnParameterList()->parameters())
+ if (variable.get() == this)
+ return true;
+ return false;
+}
+
+bool VariableDeclaration::isExternalCallableParameter() const
+{
+ auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
+ if (!callable || callable->visibility() != Declaration::Visibility::External)
+ return false;
+ for (auto const& variable: callable->parameters())
+ if (variable.get() == this)
+ return true;
+ return false;
+}
+
+bool VariableDeclaration::canHaveAutoType() const
+{
+ auto const* callable = dynamic_cast<CallableDeclaration const*>(scope());
+ return (!!callable && !isCallableParameter());
+}
+
+TypePointer VariableDeclaration::type(ContractDefinition const*) const
+{
+ return annotation().type;
+}
+
+VariableDeclarationAnnotation& VariableDeclaration::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new VariableDeclarationAnnotation();
+ return static_cast<VariableDeclarationAnnotation&>(*m_annotation);
+}
+
+ReturnAnnotation& Return::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new ReturnAnnotation();
+ return static_cast<ReturnAnnotation&>(*m_annotation);
+}
+
+VariableDeclarationStatementAnnotation& VariableDeclarationStatement::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new VariableDeclarationStatementAnnotation();
+ return static_cast<VariableDeclarationStatementAnnotation&>(*m_annotation);
+}
+
+ExpressionAnnotation& Expression::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new ExpressionAnnotation();
+ return static_cast<ExpressionAnnotation&>(*m_annotation);
+}
+
+MemberAccessAnnotation& MemberAccess::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new MemberAccessAnnotation();
+ return static_cast<MemberAccessAnnotation&>(*m_annotation);
+}
+
+BinaryOperationAnnotation& BinaryOperation::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new BinaryOperationAnnotation();
+ return static_cast<BinaryOperationAnnotation&>(*m_annotation);
+}
+
+FunctionCallAnnotation& FunctionCall::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new FunctionCallAnnotation();
+ return static_cast<FunctionCallAnnotation&>(*m_annotation);
+}
+
+IdentifierAnnotation& Identifier::annotation() const
+{
+ if (!m_annotation)
+ m_annotation = new IdentifierAnnotation();
+ return static_cast<IdentifierAnnotation&>(*m_annotation);
+}
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
new file mode 100644
index 00000000..3fe447eb
--- /dev/null
+++ b/libsolidity/ast/AST.h
@@ -0,0 +1,1354 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity abstract syntax tree.
+ */
+
+#pragma once
+
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <boost/noncopyable.hpp>
+#include <libevmasm/SourceLocation.h>
+#include <libsolidity/interface/Utils.h>
+#include <libsolidity/ast/ASTForward.h>
+#include <libsolidity/parsing/Token.h>
+#include <libsolidity/ast/Types.h>
+#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/ast/ASTAnnotations.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+class ASTVisitor;
+class ASTConstVisitor;
+
+
+/**
+ * The root (abstract) class of the AST inheritance tree.
+ * It is possible to traverse all direct and indirect children of an AST node by calling
+ * accept, providing an ASTVisitor.
+ */
+class ASTNode: private boost::noncopyable
+{
+public:
+ explicit ASTNode(SourceLocation const& _location);
+ virtual ~ASTNode();
+
+ virtual void accept(ASTVisitor& _visitor) = 0;
+ virtual void accept(ASTConstVisitor& _visitor) const = 0;
+ template <class T>
+ static void listAccept(std::vector<ASTPointer<T>>& _list, ASTVisitor& _visitor)
+ {
+ for (ASTPointer<T>& element: _list)
+ element->accept(_visitor);
+ }
+ template <class T>
+ static void listAccept(std::vector<ASTPointer<T>> const& _list, ASTConstVisitor& _visitor)
+ {
+ for (ASTPointer<T> const& element: _list)
+ element->accept(_visitor);
+ }
+
+ /// Returns the source code location of this node.
+ SourceLocation const& location() const { return m_location; }
+
+ /// Creates a @ref TypeError exception and decorates it with the location of the node and
+ /// the given description
+ Error createTypeError(std::string const& _description) const;
+
+ ///@todo make this const-safe by providing a different way to access the annotation
+ virtual ASTAnnotation& annotation() const;
+
+ ///@{
+ ///@name equality operators
+ /// Equality relies on the fact that nodes cannot be copied.
+ bool operator==(ASTNode const& _other) const { return this == &_other; }
+ bool operator!=(ASTNode const& _other) const { return !operator==(_other); }
+ ///@}
+
+protected:
+ /// Annotation - is specialised in derived classes, is created upon request (because of polymorphism).
+ mutable ASTAnnotation* m_annotation = nullptr;
+
+private:
+ SourceLocation m_location;
+};
+
+/**
+ * Source unit containing import directives and contract definitions.
+ */
+class SourceUnit: public ASTNode
+{
+public:
+ SourceUnit(SourceLocation const& _location, std::vector<ASTPointer<ASTNode>> const& _nodes):
+ ASTNode(_location), m_nodes(_nodes) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ std::vector<ASTPointer<ASTNode>> nodes() const { return m_nodes; }
+
+private:
+ std::vector<ASTPointer<ASTNode>> m_nodes;
+};
+
+/**
+ * Import directive for referencing other files / source objects.
+ * Example: import "abc.sol"
+ * Source objects are identified by a string which can be a file name but does not have to be.
+ */
+class ImportDirective: public ASTNode
+{
+public:
+ ImportDirective(SourceLocation const& _location, ASTPointer<ASTString> const& _identifier):
+ ASTNode(_location), m_identifier(_identifier) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ ASTString const& identifier() const { return *m_identifier; }
+
+private:
+ ASTPointer<ASTString> m_identifier;
+};
+
+/**
+ * Abstract AST class for a declaration (contract, function, struct, variable).
+ */
+class Declaration: public ASTNode
+{
+public:
+ /// Visibility ordered from restricted to unrestricted.
+ enum class Visibility { Default, Private, Internal, Public, External };
+
+ Declaration(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ Visibility _visibility = Visibility::Default
+ ):
+ ASTNode(_location), m_name(_name), m_visibility(_visibility), m_scope(nullptr) {}
+
+ /// @returns the declared name.
+ ASTString const& name() const { return *m_name; }
+ Visibility visibility() const { return m_visibility == Visibility::Default ? defaultVisibility() : m_visibility; }
+ bool isPublic() const { return visibility() >= Visibility::Public; }
+ virtual bool isVisibleInContract() const { return visibility() != Visibility::External; }
+ bool isVisibleInDerivedContracts() const { return isVisibleInContract() && visibility() >= Visibility::Internal; }
+
+ /// @returns the scope this declaration resides in. Can be nullptr if it is the global scope.
+ /// Available only after name and type resolution step.
+ Declaration const* scope() const { return m_scope; }
+ void setScope(Declaration const* _scope) { m_scope = _scope; }
+
+ virtual bool isLValue() const { return false; }
+ virtual bool isPartOfExternalInterface() const { return false; }
+
+ /// @returns the type of expressions referencing this declaration.
+ /// The current contract has to be given since this context can change the type, especially of
+ /// contract types.
+ /// This can only be called once types of variable declarations have already been resolved.
+ virtual TypePointer type(ContractDefinition const* m_currentContract = nullptr) const = 0;
+
+protected:
+ virtual Visibility defaultVisibility() const { return Visibility::Public; }
+
+private:
+ ASTPointer<ASTString> m_name;
+ Visibility m_visibility;
+ Declaration const* m_scope;
+};
+
+/**
+ * Abstract class that is added to each AST node that can store local variables.
+ */
+class VariableScope
+{
+public:
+ void addLocalVariable(VariableDeclaration const& _localVariable) { m_localVariables.push_back(&_localVariable); }
+ std::vector<VariableDeclaration const*> const& localVariables() const { return m_localVariables; }
+
+private:
+ std::vector<VariableDeclaration const*> m_localVariables;
+};
+
+/**
+ * Abstract class that is added to each AST node that can receive documentation.
+ */
+class Documented
+{
+public:
+ explicit Documented(ASTPointer<ASTString> const& _documentation): m_documentation(_documentation) {}
+
+ /// @return A shared pointer of an ASTString.
+ /// Can contain a nullptr in which case indicates absence of documentation
+ ASTPointer<ASTString> const& documentation() const { return m_documentation; }
+
+protected:
+ ASTPointer<ASTString> m_documentation;
+};
+
+/**
+ * Abstract class that is added to AST nodes that can be marked as not being fully implemented
+ */
+class ImplementationOptional
+{
+public:
+ explicit ImplementationOptional(bool _implemented): m_implemented(_implemented) {}
+
+ /// @return whether this node is fully implemented or not
+ bool isImplemented() const { return m_implemented; }
+
+protected:
+ bool m_implemented;
+};
+
+/// @}
+
+/**
+ * Definition of a contract or library. This is the only AST nodes where child nodes are not visited in
+ * document order. It first visits all struct declarations, then all variable declarations and
+ * finally all function declarations.
+ */
+class ContractDefinition: public Declaration, public Documented
+{
+public:
+ ContractDefinition(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ ASTPointer<ASTString> const& _documentation,
+ std::vector<ASTPointer<InheritanceSpecifier>> const& _baseContracts,
+ std::vector<ASTPointer<StructDefinition>> const& _definedStructs,
+ std::vector<ASTPointer<EnumDefinition>> const& _definedEnums,
+ std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables,
+ std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions,
+ std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers,
+ std::vector<ASTPointer<EventDefinition>> const& _events,
+ bool _isLibrary
+ ):
+ Declaration(_location, _name),
+ Documented(_documentation),
+ m_baseContracts(_baseContracts),
+ m_definedStructs(_definedStructs),
+ m_definedEnums(_definedEnums),
+ m_stateVariables(_stateVariables),
+ m_definedFunctions(_definedFunctions),
+ m_functionModifiers(_functionModifiers),
+ m_events(_events),
+ m_isLibrary(_isLibrary)
+ {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ std::vector<ASTPointer<InheritanceSpecifier>> const& baseContracts() const { return m_baseContracts; }
+ std::vector<ASTPointer<StructDefinition>> const& definedStructs() const { return m_definedStructs; }
+ std::vector<ASTPointer<EnumDefinition>> const& definedEnums() const { return m_definedEnums; }
+ std::vector<ASTPointer<VariableDeclaration>> const& stateVariables() const { return m_stateVariables; }
+ std::vector<ASTPointer<ModifierDefinition>> const& functionModifiers() const { return m_functionModifiers; }
+ std::vector<ASTPointer<FunctionDefinition>> const& definedFunctions() const { return m_definedFunctions; }
+ std::vector<ASTPointer<EventDefinition>> const& events() const { return m_events; }
+ std::vector<ASTPointer<EventDefinition>> const& interfaceEvents() const;
+ bool isLibrary() const { return m_isLibrary; }
+
+ /// @returns a map of canonical function signatures to FunctionDefinitions
+ /// as intended for use by the ABI.
+ std::map<FixedHash<4>, FunctionTypePointer> interfaceFunctions() const;
+ std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList() const;
+
+ /// @returns a list of the inheritable members of this contract
+ std::vector<Declaration const*> const& inheritableMembers() const;
+
+ /// Returns the constructor or nullptr if no constructor was specified.
+ FunctionDefinition const* constructor() const;
+ /// Returns the fallback function or nullptr if no fallback function was specified.
+ FunctionDefinition const* fallbackFunction() const;
+
+ std::string const& userDocumentation() const;
+ void setUserDocumentation(std::string const& _userDocumentation);
+
+ std::string const& devDocumentation() const;
+ void setDevDocumentation(std::string const& _devDocumentation);
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
+ virtual ContractDefinitionAnnotation& annotation() const override;
+
+private:
+ std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts;
+ std::vector<ASTPointer<StructDefinition>> m_definedStructs;
+ std::vector<ASTPointer<EnumDefinition>> m_definedEnums;
+ std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
+ std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions;
+ std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers;
+ std::vector<ASTPointer<EventDefinition>> m_events;
+ bool m_isLibrary;
+
+ // parsed Natspec documentation of the contract.
+ std::string m_userDocumentation;
+ std::string m_devDocumentation;
+
+ std::vector<ContractDefinition const*> m_linearizedBaseContracts;
+ mutable std::unique_ptr<std::vector<std::pair<FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList;
+ mutable std::unique_ptr<std::vector<ASTPointer<EventDefinition>>> m_interfaceEvents;
+ mutable std::unique_ptr<std::vector<Declaration const*>> m_inheritableMembers;
+};
+
+class InheritanceSpecifier: public ASTNode
+{
+public:
+ InheritanceSpecifier(
+ SourceLocation const& _location,
+ ASTPointer<Identifier> const& _baseName,
+ std::vector<ASTPointer<Expression>> _arguments
+ ):
+ ASTNode(_location), m_baseName(_baseName), m_arguments(_arguments) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Identifier const& name() const { return *m_baseName; }
+ std::vector<ASTPointer<Expression>> const& arguments() const { return m_arguments; }
+
+private:
+ ASTPointer<Identifier> m_baseName;
+ std::vector<ASTPointer<Expression>> m_arguments;
+};
+
+class StructDefinition: public Declaration
+{
+public:
+ StructDefinition(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ std::vector<ASTPointer<VariableDeclaration>> const& _members
+ ):
+ Declaration(_location, _name), m_members(_members) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; }
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
+ virtual TypeDeclarationAnnotation& annotation() const override;
+
+private:
+ std::vector<ASTPointer<VariableDeclaration>> m_members;
+};
+
+class EnumDefinition: public Declaration
+{
+public:
+ EnumDefinition(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ std::vector<ASTPointer<EnumValue>> const& _members
+ ):
+ Declaration(_location, _name), m_members(_members) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ std::vector<ASTPointer<EnumValue>> const& members() const { return m_members; }
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
+ virtual TypeDeclarationAnnotation& annotation() const override;
+
+private:
+ std::vector<ASTPointer<EnumValue>> m_members;
+};
+
+/**
+ * Declaration of an Enum Value
+ */
+class EnumValue: public Declaration
+{
+public:
+ EnumValue(SourceLocation const& _location, ASTPointer<ASTString> const& _name):
+ Declaration(_location, _name) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+};
+
+/**
+ * Parameter list, used as function parameter list and return list.
+ * None of the parameters is allowed to contain mappings (not even recursively
+ * inside structs).
+ */
+class ParameterList: public ASTNode
+{
+public:
+ ParameterList(
+ SourceLocation const& _location,
+ std::vector<ASTPointer<VariableDeclaration>> const& _parameters
+ ):
+ ASTNode(_location), m_parameters(_parameters) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ std::vector<ASTPointer<VariableDeclaration>> const& parameters() const { return m_parameters; }
+
+private:
+ std::vector<ASTPointer<VariableDeclaration>> m_parameters;
+};
+
+/**
+ * Base class for all nodes that define function-like objects, i.e. FunctionDefinition,
+ * EventDefinition and ModifierDefinition.
+ */
+class CallableDeclaration: public Declaration, public VariableScope
+{
+public:
+ CallableDeclaration(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ Declaration::Visibility _visibility,
+ ASTPointer<ParameterList> const& _parameters,
+ ASTPointer<ParameterList> const& _returnParameters = ASTPointer<ParameterList>()
+ ):
+ Declaration(_location, _name, _visibility),
+ m_parameters(_parameters),
+ m_returnParameters(_returnParameters)
+ {
+ }
+
+ std::vector<ASTPointer<VariableDeclaration>> const& parameters() const { return m_parameters->parameters(); }
+ ParameterList const& parameterList() const { return *m_parameters; }
+ ASTPointer<ParameterList> const& returnParameterList() const { return m_returnParameters; }
+
+protected:
+ ASTPointer<ParameterList> m_parameters;
+ ASTPointer<ParameterList> m_returnParameters;
+};
+
+class FunctionDefinition: public CallableDeclaration, public Documented, public ImplementationOptional
+{
+public:
+ FunctionDefinition(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ Declaration::Visibility _visibility,
+ bool _isConstructor,
+ ASTPointer<ASTString> const& _documentation,
+ ASTPointer<ParameterList> const& _parameters,
+ bool _isDeclaredConst,
+ std::vector<ASTPointer<ModifierInvocation>> const& _modifiers,
+ ASTPointer<ParameterList> const& _returnParameters,
+ ASTPointer<Block> const& _body
+ ):
+ CallableDeclaration(_location, _name, _visibility, _parameters, _returnParameters),
+ Documented(_documentation),
+ ImplementationOptional(_body != nullptr),
+ m_isConstructor(_isConstructor),
+ m_isDeclaredConst(_isDeclaredConst),
+ m_functionModifiers(_modifiers),
+ m_body(_body)
+ {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ bool isConstructor() const { return m_isConstructor; }
+ bool isDeclaredConst() const { return m_isDeclaredConst; }
+ std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
+ std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); }
+ Block const& body() const { return *m_body; }
+
+ virtual bool isVisibleInContract() const override
+ {
+ return Declaration::isVisibleInContract() && !isConstructor() && !name().empty();
+ }
+ virtual bool isPartOfExternalInterface() const override { return isPublic() && !m_isConstructor && !name().empty(); }
+
+ /// @returns the external signature of the function
+ /// That consists of the name of the function followed by the types of the
+ /// arguments separated by commas all enclosed in parentheses without any spaces.
+ std::string externalSignature() const;
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
+private:
+ bool m_isConstructor;
+ bool m_isDeclaredConst;
+ std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
+ ASTPointer<Block> m_body;
+};
+
+/**
+ * Declaration of a variable. This can be used in various places, e.g. in function parameter
+ * lists, struct definitions and even function bodys.
+ */
+class VariableDeclaration: public Declaration
+{
+public:
+ enum Location { Default, Storage, Memory };
+
+ VariableDeclaration(
+ SourceLocation const& _sourceLocation,
+ ASTPointer<TypeName> const& _type,
+ ASTPointer<ASTString> const& _name,
+ ASTPointer<Expression> _value,
+ Visibility _visibility,
+ bool _isStateVar = false,
+ bool _isIndexed = false,
+ bool _isConstant = false,
+ Location _referenceLocation = Location::Default
+ ):
+ Declaration(_sourceLocation, _name, _visibility),
+ m_typeName(_type),
+ m_value(_value),
+ m_isStateVariable(_isStateVar),
+ m_isIndexed(_isIndexed),
+ m_isConstant(_isConstant),
+ m_location(_referenceLocation) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ TypeName* typeName() const { return m_typeName.get(); }
+ ASTPointer<Expression> const& value() const { return m_value; }
+
+ virtual bool isLValue() const override;
+ virtual bool isPartOfExternalInterface() const override { return isPublic(); }
+
+ bool isLocalVariable() const { return !!dynamic_cast<FunctionDefinition const*>(scope()); }
+ /// @returns true if this variable is a parameter or return parameter of a function.
+ bool isCallableParameter() const;
+ /// @returns true if this variable is a parameter (not return parameter) of an external function.
+ bool isExternalCallableParameter() const;
+ /// @returns true if the type of the variable does not need to be specified, i.e. it is declared
+ /// in the body of a function or modifier.
+ bool canHaveAutoType() const;
+ bool isStateVariable() const { return m_isStateVariable; }
+ bool isIndexed() const { return m_isIndexed; }
+ bool isConstant() const { return m_isConstant; }
+ Location referenceLocation() const { return m_location; }
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
+ virtual VariableDeclarationAnnotation& annotation() const override;
+
+protected:
+ Visibility defaultVisibility() const override { return Visibility::Internal; }
+
+private:
+ ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
+ /// Initially assigned value, can be missing. For local variables, this is stored inside
+ /// VariableDeclarationStatement and not here.
+ ASTPointer<Expression> m_value;
+ bool m_isStateVariable; ///< Whether or not this is a contract state variable
+ bool m_isIndexed; ///< Whether this is an indexed variable (used by events).
+ bool m_isConstant; ///< Whether the variable is a compile-time constant.
+ Location m_location; ///< Location of the variable if it is of reference type.
+};
+
+/**
+ * Definition of a function modifier.
+ */
+class ModifierDefinition: public CallableDeclaration, public Documented
+{
+public:
+ ModifierDefinition(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ ASTPointer<ASTString> const& _documentation,
+ ASTPointer<ParameterList> const& _parameters,
+ ASTPointer<Block> const& _body
+ ):
+ CallableDeclaration(_location, _name, Visibility::Default, _parameters),
+ Documented(_documentation),
+ m_body(_body)
+ {
+ }
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Block const& body() const { return *m_body; }
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
+private:
+ ASTPointer<Block> m_body;
+};
+
+/**
+ * Invocation/usage of a modifier in a function header or a base constructor call.
+ */
+class ModifierInvocation: public ASTNode
+{
+public:
+ ModifierInvocation(
+ SourceLocation const& _location,
+ ASTPointer<Identifier> const& _name,
+ std::vector<ASTPointer<Expression>> _arguments
+ ):
+ ASTNode(_location), m_modifierName(_name), m_arguments(_arguments) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ ASTPointer<Identifier> const& name() const { return m_modifierName; }
+ std::vector<ASTPointer<Expression>> const& arguments() const { return m_arguments; }
+
+private:
+ ASTPointer<Identifier> m_modifierName;
+ std::vector<ASTPointer<Expression>> m_arguments;
+};
+
+/**
+ * Definition of a (loggable) event.
+ */
+class EventDefinition: public CallableDeclaration, public Documented
+{
+public:
+ EventDefinition(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name,
+ ASTPointer<ASTString> const& _documentation,
+ ASTPointer<ParameterList> const& _parameters,
+ bool _anonymous = false
+ ):
+ CallableDeclaration(_location, _name, Visibility::Default, _parameters),
+ Documented(_documentation),
+ m_anonymous(_anonymous)
+ {
+ }
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ bool isAnonymous() const { return m_anonymous; }
+
+ virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
+
+private:
+ bool m_anonymous = false;
+};
+
+/**
+ * Pseudo AST node that is used as declaration for "this", "msg", "tx", "block" and the global
+ * functions when such an identifier is encountered. Will never have a valid location in the source code.
+ */
+class MagicVariableDeclaration: public Declaration
+{
+public:
+ MagicVariableDeclaration(ASTString const& _name, std::shared_ptr<Type const> const& _type):
+ Declaration(SourceLocation(), std::make_shared<ASTString>(_name)), m_type(_type) {}
+ virtual void accept(ASTVisitor&) override
+ {
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST."));
+ }
+ virtual void accept(ASTConstVisitor&) const override
+ {
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("MagicVariableDeclaration used inside real AST."));
+ }
+
+ virtual TypePointer type(ContractDefinition const*) const override { return m_type; }
+
+private:
+ std::shared_ptr<Type const> m_type;
+};
+
+/// Types
+/// @{
+
+/**
+ * Abstract base class of a type name, can be any built-in or user-defined type.
+ */
+class TypeName: public ASTNode
+{
+public:
+ explicit TypeName(SourceLocation const& _location): ASTNode(_location) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ virtual TypeNameAnnotation& annotation() const override;
+};
+
+/**
+ * Any pre-defined type name represented by a single keyword, i.e. it excludes mappings,
+ * contracts, functions, etc.
+ */
+class ElementaryTypeName: public TypeName
+{
+public:
+ ElementaryTypeName(SourceLocation const& _location, Token::Value _type):
+ TypeName(_location), m_type(_type)
+ {
+ solAssert(Token::isElementaryTypeName(_type), "");
+ }
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Token::Value typeName() const { return m_type; }
+
+private:
+ Token::Value m_type;
+};
+
+/**
+ * Name referring to a user-defined type (i.e. a struct, contract, etc.).
+ */
+class UserDefinedTypeName: public TypeName
+{
+public:
+ UserDefinedTypeName(SourceLocation const& _location, std::vector<ASTString> const& _namePath):
+ TypeName(_location), m_namePath(_namePath) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ std::vector<ASTString> const& namePath() const { return m_namePath; }
+
+ virtual UserDefinedTypeNameAnnotation& annotation() const override;
+
+private:
+ std::vector<ASTString> m_namePath;
+};
+
+/**
+ * A mapping type. Its source form is "mapping('keyType' => 'valueType')"
+ */
+class Mapping: public TypeName
+{
+public:
+ Mapping(
+ SourceLocation const& _location,
+ ASTPointer<ElementaryTypeName> const& _keyType,
+ ASTPointer<TypeName> const& _valueType
+ ):
+ TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ ElementaryTypeName const& keyType() const { return *m_keyType; }
+ TypeName const& valueType() const { return *m_valueType; }
+
+private:
+ ASTPointer<ElementaryTypeName> m_keyType;
+ ASTPointer<TypeName> m_valueType;
+};
+
+/**
+ * An array type, can be "typename[]" or "typename[<expression>]".
+ */
+class ArrayTypeName: public TypeName
+{
+public:
+ ArrayTypeName(
+ SourceLocation const& _location,
+ ASTPointer<TypeName> const& _baseType,
+ ASTPointer<Expression> const& _length
+ ):
+ TypeName(_location), m_baseType(_baseType), m_length(_length) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ TypeName const& baseType() const { return *m_baseType; }
+ Expression const* length() const { return m_length.get(); }
+
+private:
+ ASTPointer<TypeName> m_baseType;
+ ASTPointer<Expression> m_length; ///< Length of the array, might be empty.
+};
+
+/// @}
+
+/// Statements
+/// @{
+
+
+/**
+ * Abstract base class for statements.
+ */
+class Statement: public ASTNode
+{
+public:
+ explicit Statement(SourceLocation const& _location): ASTNode(_location) {}
+};
+
+/**
+ * Brace-enclosed block containing zero or more statements.
+ */
+class Block: public Statement
+{
+public:
+ Block(
+ SourceLocation const& _location,
+ std::vector<ASTPointer<Statement>> const& _statements
+ ):
+ Statement(_location), m_statements(_statements) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+private:
+ std::vector<ASTPointer<Statement>> m_statements;
+};
+
+/**
+ * Special placeholder statement denoted by "_" used in function modifiers. This is replaced by
+ * the original function when the modifier is applied.
+ */
+class PlaceholderStatement: public Statement
+{
+public:
+ explicit PlaceholderStatement(SourceLocation const& _location): Statement(_location) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+};
+
+/**
+ * If-statement with an optional "else" part. Note that "else if" is modeled by having a new
+ * if-statement as the false (else) body.
+ */
+class IfStatement: public Statement
+{
+public:
+ IfStatement(
+ SourceLocation const& _location,
+ ASTPointer<Expression> const& _condition,
+ ASTPointer<Statement> const& _trueBody,
+ ASTPointer<Statement> const& _falseBody
+ ):
+ Statement(_location),
+ m_condition(_condition),
+ m_trueBody(_trueBody),
+ m_falseBody(_falseBody)
+ {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const& condition() const { return *m_condition; }
+ Statement const& trueStatement() const { return *m_trueBody; }
+ /// @returns the "else" part of the if statement or nullptr if there is no "else" part.
+ Statement const* falseStatement() const { return m_falseBody.get(); }
+
+private:
+ ASTPointer<Expression> m_condition;
+ ASTPointer<Statement> m_trueBody;
+ ASTPointer<Statement> m_falseBody; ///< "else" part, optional
+};
+
+/**
+ * Statement in which a break statement is legal (abstract class).
+ */
+class BreakableStatement: public Statement
+{
+public:
+ explicit BreakableStatement(SourceLocation const& _location): Statement(_location) {}
+};
+
+class WhileStatement: public BreakableStatement
+{
+public:
+ WhileStatement(
+ SourceLocation const& _location,
+ ASTPointer<Expression> const& _condition,
+ ASTPointer<Statement> const& _body
+ ):
+ BreakableStatement(_location), m_condition(_condition), m_body(_body) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const& condition() const { return *m_condition; }
+ Statement const& body() const { return *m_body; }
+
+private:
+ ASTPointer<Expression> m_condition;
+ ASTPointer<Statement> m_body;
+};
+
+/**
+ * For loop statement
+ */
+class ForStatement: public BreakableStatement
+{
+public:
+ ForStatement(
+ SourceLocation const& _location,
+ ASTPointer<Statement> const& _initExpression,
+ ASTPointer<Expression> const& _conditionExpression,
+ ASTPointer<ExpressionStatement> const& _loopExpression,
+ ASTPointer<Statement> const& _body
+ ):
+ BreakableStatement(_location),
+ m_initExpression(_initExpression),
+ m_condExpression(_conditionExpression),
+ m_loopExpression(_loopExpression),
+ m_body(_body)
+ {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Statement const* initializationExpression() const { return m_initExpression.get(); }
+ Expression const* condition() const { return m_condExpression.get(); }
+ ExpressionStatement const* loopExpression() const { return m_loopExpression.get(); }
+ Statement const& body() const { return *m_body; }
+
+private:
+ /// For statement's initialization expresion. for(XXX; ; ). Can be empty
+ ASTPointer<Statement> m_initExpression;
+ /// For statement's condition expresion. for(; XXX ; ). Can be empty
+ ASTPointer<Expression> m_condExpression;
+ /// For statement's loop expresion. for(;;XXX). Can be empty
+ ASTPointer<ExpressionStatement> m_loopExpression;
+ /// The body of the loop
+ ASTPointer<Statement> m_body;
+};
+
+class Continue: public Statement
+{
+public:
+ explicit Continue(SourceLocation const& _location): Statement(_location) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+};
+
+class Break: public Statement
+{
+public:
+ explicit Break(SourceLocation const& _location): Statement(_location) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+};
+
+class Return: public Statement
+{
+public:
+ Return(SourceLocation const& _location, ASTPointer<Expression> _expression):
+ Statement(_location), m_expression(_expression) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const* expression() const { return m_expression.get(); }
+
+ virtual ReturnAnnotation& annotation() const override;
+
+private:
+ ASTPointer<Expression> m_expression; ///< value to return, optional
+};
+
+/**
+ * @brief The Throw statement to throw that triggers a solidity exception(jump to ErrorTag)
+ */
+class Throw: public Statement
+{
+public:
+ explicit Throw(SourceLocation const& _location): Statement(_location) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+};
+
+/**
+ * Definition of a variable as a statement inside a function. It requires a type name (which can
+ * also be "var") but the actual assignment can be missing.
+ * Examples: var a = 2; uint256 a;
+ * As a second form, multiple variables can be declared, cannot have a type and must be assigned
+ * right away. If the first or last component is unnamed, it can "consume" an arbitrary number
+ * of components.
+ * Examples: var (a, b) = f(); var (a,,,c) = g(); var (a,) = d();
+ */
+class VariableDeclarationStatement: public Statement
+{
+public:
+ VariableDeclarationStatement(
+ SourceLocation const& _location,
+ std::vector<ASTPointer<VariableDeclaration>> const& _variables,
+ ASTPointer<Expression> const& _initialValue
+ ):
+ Statement(_location), m_variables(_variables), m_initialValue(_initialValue) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ VariableDeclarationStatementAnnotation& annotation() const override;
+
+ std::vector<ASTPointer<VariableDeclaration>> const& declarations() const { return m_variables; }
+ Expression const* initialValue() const { return m_initialValue.get(); }
+
+private:
+ /// List of variables, some of which can be empty pointers (unnamed components).
+ std::vector<ASTPointer<VariableDeclaration>> m_variables;
+ /// The assigned expression / initial value.
+ ASTPointer<Expression> m_initialValue;
+};
+
+/**
+ * A statement that contains only an expression (i.e. an assignment, function call, ...).
+ */
+class ExpressionStatement: public Statement
+{
+public:
+ ExpressionStatement(
+ SourceLocation const& _location,
+ ASTPointer<Expression> _expression
+ ):
+ Statement(_location), m_expression(_expression) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const& expression() const { return *m_expression; }
+
+private:
+ ASTPointer<Expression> m_expression;
+};
+
+/// @}
+
+/// Expressions
+/// @{
+
+/**
+ * An expression, i.e. something that has a value (which can also be of type "void" in case
+ * of some function calls).
+ * @abstract
+ */
+class Expression: public ASTNode
+{
+public:
+ explicit Expression(SourceLocation const& _location): ASTNode(_location) {}
+
+ ExpressionAnnotation& annotation() const override;
+};
+
+/// Assignment, can also be a compound assignment.
+/// Examples: (a = 7 + 8) or (a *= 2)
+class Assignment: public Expression
+{
+public:
+ Assignment(
+ SourceLocation const& _location,
+ ASTPointer<Expression> const& _leftHandSide,
+ Token::Value _assignmentOperator,
+ ASTPointer<Expression> const& _rightHandSide
+ ):
+ Expression(_location),
+ m_leftHandSide(_leftHandSide),
+ m_assigmentOperator(_assignmentOperator),
+ m_rightHandSide(_rightHandSide)
+ {
+ solAssert(Token::isAssignmentOp(_assignmentOperator), "");
+ }
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const& leftHandSide() const { return *m_leftHandSide; }
+ Token::Value assignmentOperator() const { return m_assigmentOperator; }
+ Expression const& rightHandSide() const { return *m_rightHandSide; }
+
+private:
+ ASTPointer<Expression> m_leftHandSide;
+ Token::Value m_assigmentOperator;
+ ASTPointer<Expression> m_rightHandSide;
+};
+
+/**
+ * Tuple or just parenthesized expression.
+ * Examples: (1, 2), (x,), (x), ()
+ * Individual components might be empty shared pointers (as in the second example).
+ * The respective types in lvalue context are: 2-tuple, 2-tuple (with wildcard), type of x, 0-tuple
+ * Not in lvalue context: 2-tuple, _1_-tuple, type of x, 0-tuple.
+ */
+class TupleExpression: public Expression
+{
+public:
+ TupleExpression(
+ SourceLocation const& _location,
+ std::vector<ASTPointer<Expression>> const& _components
+ ):
+ Expression(_location), m_components(_components) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ std::vector<ASTPointer<Expression>> const& components() const { return m_components; }
+
+private:
+ std::vector<ASTPointer<Expression>> m_components;
+};
+
+/**
+ * Operation involving a unary operator, pre- or postfix.
+ * Examples: ++i, delete x or !true
+ */
+class UnaryOperation: public Expression
+{
+public:
+ UnaryOperation(
+ SourceLocation const& _location,
+ Token::Value _operator,
+ ASTPointer<Expression> const& _subExpression,
+ bool _isPrefix
+ ):
+ Expression(_location),
+ m_operator(_operator),
+ m_subExpression(_subExpression),
+ m_isPrefix(_isPrefix)
+ {
+ solAssert(Token::isUnaryOp(_operator), "");
+ }
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Token::Value getOperator() const { return m_operator; }
+ bool isPrefixOperation() const { return m_isPrefix; }
+ Expression const& subExpression() const { return *m_subExpression; }
+
+private:
+ Token::Value m_operator;
+ ASTPointer<Expression> m_subExpression;
+ bool m_isPrefix;
+};
+
+/**
+ * Operation involving a binary operator.
+ * Examples: 1 + 2, true && false or 1 <= 4
+ */
+class BinaryOperation: public Expression
+{
+public:
+ BinaryOperation(
+ SourceLocation const& _location,
+ ASTPointer<Expression> const& _left,
+ Token::Value _operator,
+ ASTPointer<Expression> const& _right
+ ):
+ Expression(_location), m_left(_left), m_operator(_operator), m_right(_right)
+ {
+ solAssert(Token::isBinaryOp(_operator) || Token::isCompareOp(_operator), "");
+ }
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const& leftExpression() const { return *m_left; }
+ Expression const& rightExpression() const { return *m_right; }
+ Token::Value getOperator() const { return m_operator; }
+
+ BinaryOperationAnnotation& annotation() const override;
+
+private:
+ ASTPointer<Expression> m_left;
+ Token::Value m_operator;
+ ASTPointer<Expression> m_right;
+};
+
+/**
+ * Can be ordinary function call, type cast or struct construction.
+ */
+class FunctionCall: public Expression
+{
+public:
+ FunctionCall(
+ SourceLocation const& _location,
+ ASTPointer<Expression> const& _expression,
+ std::vector<ASTPointer<Expression>> const& _arguments,
+ std::vector<ASTPointer<ASTString>> const& _names
+ ):
+ Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const& expression() const { return *m_expression; }
+ std::vector<ASTPointer<Expression const>> arguments() const { return {m_arguments.begin(), m_arguments.end()}; }
+ std::vector<ASTPointer<ASTString>> const& names() const { return m_names; }
+
+ virtual FunctionCallAnnotation& annotation() const override;
+
+private:
+ ASTPointer<Expression> m_expression;
+ std::vector<ASTPointer<Expression>> m_arguments;
+ std::vector<ASTPointer<ASTString>> m_names;
+};
+
+/**
+ * Expression that creates a new contract, e.g. the "new SomeContract" part in "new SomeContract(1, 2)".
+ */
+class NewExpression: public Expression
+{
+public:
+ NewExpression(
+ SourceLocation const& _location,
+ ASTPointer<Identifier> const& _contractName
+ ):
+ Expression(_location), m_contractName(_contractName) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Identifier const& contractName() const { return *m_contractName; }
+
+private:
+ ASTPointer<Identifier> m_contractName;
+};
+
+/**
+ * Access to a member of an object. Example: x.name
+ */
+class MemberAccess: public Expression
+{
+public:
+ MemberAccess(
+ SourceLocation const& _location,
+ ASTPointer<Expression> _expression,
+ ASTPointer<ASTString> const& _memberName
+ ):
+ Expression(_location), m_expression(_expression), m_memberName(_memberName) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+ Expression const& expression() const { return *m_expression; }
+ ASTString const& memberName() const { return *m_memberName; }
+
+ virtual MemberAccessAnnotation& annotation() const override;
+
+private:
+ ASTPointer<Expression> m_expression;
+ ASTPointer<ASTString> m_memberName;
+};
+
+/**
+ * Index access to an array. Example: a[2]
+ */
+class IndexAccess: public Expression
+{
+public:
+ IndexAccess(
+ SourceLocation const& _location,
+ ASTPointer<Expression> const& _base,
+ ASTPointer<Expression> const& _index
+ ):
+ Expression(_location), m_base(_base), m_index(_index) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Expression const& baseExpression() const { return *m_base; }
+ Expression const* indexExpression() const { return m_index.get(); }
+
+private:
+ ASTPointer<Expression> m_base;
+ ASTPointer<Expression> m_index;
+};
+
+/**
+ * Primary expression, i.e. an expression that cannot be divided any further. Examples are literals
+ * or variable references.
+ */
+class PrimaryExpression: public Expression
+{
+public:
+ PrimaryExpression(SourceLocation const& _location): Expression(_location) {}
+};
+
+/**
+ * An identifier, i.e. a reference to a declaration by name like a variable or function.
+ */
+class Identifier: public PrimaryExpression
+{
+public:
+ Identifier(
+ SourceLocation const& _location,
+ ASTPointer<ASTString> const& _name
+ ):
+ PrimaryExpression(_location), m_name(_name) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ ASTString const& name() const { return *m_name; }
+
+ virtual IdentifierAnnotation& annotation() const override;
+
+private:
+ ASTPointer<ASTString> m_name;
+};
+
+/**
+ * An elementary type name expression is used in expressions like "a = uint32(2)" to change the
+ * type of an expression explicitly. Here, "uint32" is the elementary type name expression and
+ * "uint32(2)" is a @ref FunctionCall.
+ */
+class ElementaryTypeNameExpression: public PrimaryExpression
+{
+public:
+ ElementaryTypeNameExpression(SourceLocation const& _location, Token::Value _typeToken):
+ PrimaryExpression(_location), m_typeToken(_typeToken)
+ {
+ solAssert(Token::isElementaryTypeName(_typeToken), "");
+ }
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Token::Value typeToken() const { return m_typeToken; }
+
+private:
+ Token::Value m_typeToken;
+};
+
+/**
+ * A literal string or number. @see ExpressionCompiler::endVisit() is used to actually parse its value.
+ */
+class Literal: public PrimaryExpression
+{
+public:
+ enum class SubDenomination
+ {
+ None = Token::Illegal,
+ Wei = Token::SubWei,
+ Szabo = Token::SubSzabo,
+ Finney = Token::SubFinney,
+ Ether = Token::SubEther,
+ Second = Token::SubSecond,
+ Minute = Token::SubMinute,
+ Hour = Token::SubHour,
+ Day = Token::SubDay,
+ Week = Token::SubWeek,
+ Year = Token::SubYear
+ };
+ Literal(
+ SourceLocation const& _location,
+ Token::Value _token,
+ ASTPointer<ASTString> const& _value,
+ SubDenomination _sub = SubDenomination::None
+ ):
+ PrimaryExpression(_location), m_token(_token), m_value(_value), m_subDenomination(_sub) {}
+ virtual void accept(ASTVisitor& _visitor) override;
+ virtual void accept(ASTConstVisitor& _visitor) const override;
+
+ Token::Value token() const { return m_token; }
+ /// @returns the non-parsed value of the literal
+ ASTString const& value() const { return *m_value; }
+
+ SubDenomination subDenomination() const { return m_subDenomination; }
+
+private:
+ Token::Value m_token;
+ ASTPointer<ASTString> m_value;
+ SubDenomination m_subDenomination;
+};
+
+/// @}
+
+
+}
+}
diff --git a/libsolidity/ast/ASTAnnotations.cpp b/libsolidity/ast/ASTAnnotations.cpp
new file mode 100644
index 00000000..416e6b44
--- /dev/null
+++ b/libsolidity/ast/ASTAnnotations.cpp
@@ -0,0 +1,28 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Object containing the type and other annotations for the AST nodes.
+ */
+
+#include <libsolidity/ast/ASTAnnotations.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h
new file mode 100644
index 00000000..d112b1ef
--- /dev/null
+++ b/libsolidity/ast/ASTAnnotations.h
@@ -0,0 +1,140 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Object containing the type and other annotations for the AST nodes.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <vector>
+#include <set>
+#include <libsolidity/ast/ASTForward.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+class Type;
+using TypePointer = std::shared_ptr<Type const>;
+
+struct ASTAnnotation
+{
+ virtual ~ASTAnnotation() {}
+};
+
+struct TypeDeclarationAnnotation: ASTAnnotation
+{
+ /// The name of this type, prefixed by proper namespaces if globally accessible.
+ std::string canonicalName;
+};
+
+struct ContractDefinitionAnnotation: TypeDeclarationAnnotation
+{
+ /// Whether all functions are implemented.
+ bool isFullyImplemented = true;
+ /// List of all (direct and indirect) base contracts in order from derived to
+ /// base, including the contract itself.
+ std::vector<ContractDefinition const*> linearizedBaseContracts;
+ /// List of contracts this contract creates, i.e. which need to be compiled first.
+ /// Also includes all contracts from @a linearizedBaseContracts.
+ std::set<ContractDefinition const*> contractDependencies;
+};
+
+struct VariableDeclarationAnnotation: ASTAnnotation
+{
+ /// Type of variable (type of identifier referencing this variable).
+ TypePointer type;
+};
+
+struct ReturnAnnotation: ASTAnnotation
+{
+ /// Reference to the return parameters of the function.
+ ParameterList const* functionReturnParameters = nullptr;
+};
+
+struct TypeNameAnnotation: ASTAnnotation
+{
+ /// Type declared by this type name, i.e. type of a variable where this type name is used.
+ /// Set during reference resolution stage.
+ TypePointer type;
+};
+
+struct UserDefinedTypeNameAnnotation: TypeNameAnnotation
+{
+ /// Referenced declaration, set during reference resolution stage.
+ Declaration const* referencedDeclaration = nullptr;
+};
+
+struct VariableDeclarationStatementAnnotation: ASTAnnotation
+{
+ /// Information about which component of the value is assigned to which variable.
+ /// The pointer can be null to signify that the component is discarded.
+ std::vector<VariableDeclaration const*> assignments;
+};
+
+struct ExpressionAnnotation: ASTAnnotation
+{
+ /// Inferred type of the expression.
+ TypePointer type;
+ /// Whether it is an LValue (i.e. something that can be assigned to).
+ bool isLValue = false;
+ /// Whether the expression is used in a context where the LValue is actually required.
+ bool lValueRequested = false;
+ /// Types of arguments if the expression is a function that is called - used
+ /// for overload resolution.
+ std::shared_ptr<std::vector<TypePointer>> argumentTypes;
+};
+
+struct IdentifierAnnotation: ExpressionAnnotation
+{
+ /// Stores a reference to the current contract.
+ /// This is needed because types of base contracts change depending on the context.
+ ContractDefinition const* contractScope = nullptr;
+ /// Referenced declaration, set at latest during overload resolution stage.
+ Declaration const* referencedDeclaration = nullptr;
+ /// List of possible declarations it could refer to.
+ std::vector<Declaration const*> overloadedDeclarations;
+};
+
+struct MemberAccessAnnotation: ExpressionAnnotation
+{
+ /// Referenced declaration, set at latest during overload resolution stage.
+ Declaration const* referencedDeclaration = nullptr;
+};
+
+struct BinaryOperationAnnotation: ExpressionAnnotation
+{
+ /// The common type that is used for the operation, not necessarily the result type (which
+ /// e.g. for comparisons is bool).
+ TypePointer commonType;
+};
+
+struct FunctionCallAnnotation: ExpressionAnnotation
+{
+ /// Whether this is an explicit type conversion.
+ bool isTypeConversion = false;
+ /// Whether this is a struct constructor call.
+ bool isStructConstructorCall = false;
+};
+
+}
+}
diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h
new file mode 100644
index 00000000..02dd054a
--- /dev/null
+++ b/libsolidity/ast/ASTForward.h
@@ -0,0 +1,96 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Forward-declarations of AST classes.
+ */
+
+#pragma once
+
+#include <string>
+#include <memory>
+#include <vector>
+
+// Forward-declare all AST node types
+
+namespace dev
+{
+namespace solidity
+{
+
+class ASTNode;
+class SourceUnit;
+class ImportDirective;
+class Declaration;
+class ContractDefinition;
+class InheritanceSpecifier;
+class StructDefinition;
+class EnumDefinition;
+class EnumValue;
+class ParameterList;
+class FunctionDefinition;
+class VariableDeclaration;
+class ModifierDefinition;
+class ModifierInvocation;
+class EventDefinition;
+class MagicVariableDeclaration;
+class TypeName;
+class ElementaryTypeName;
+class UserDefinedTypeName;
+class Mapping;
+class ArrayTypeName;
+class Statement;
+class Block;
+class PlaceholderStatement;
+class IfStatement;
+class BreakableStatement;
+class WhileStatement;
+class ForStatement;
+class Continue;
+class Break;
+class Return;
+class Throw;
+class VariableDeclarationStatement;
+class ExpressionStatement;
+class Expression;
+class Assignment;
+class TupleExpression;
+class UnaryOperation;
+class BinaryOperation;
+class FunctionCall;
+class NewExpression;
+class MemberAccess;
+class IndexAccess;
+class PrimaryExpression;
+class Identifier;
+class ElementaryTypeNameExpression;
+class Literal;
+
+class VariableScope;
+
+// 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 <class T>
+using ASTPointer = std::shared_ptr<T>;
+
+using ASTString = std::string;
+
+
+}
+}
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
new file mode 100644
index 00000000..f208c3c9
--- /dev/null
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -0,0 +1,470 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Lefteris <lefteris@ethdev.com>
+ * @date 2015
+ * Converts the AST into json format
+ */
+
+#include <libsolidity/ast/ASTJsonConverter.h>
+#include <boost/algorithm/string/join.hpp>
+#include <libsolidity/ast/AST.h>
+
+using namespace std;
+
+namespace dev
+{
+namespace solidity
+{
+
+void ASTJsonConverter::addKeyValue(Json::Value& _obj, string const& _key, string const& _val)
+{
+ // special handling for booleans
+ if (_key == "const" || _key == "public" || _key == "local" ||
+ _key == "lvalue" || _key == "local_lvalue" || _key == "prefix")
+ _obj[_key] = (_val == "1") ? true : false;
+ else
+ // else simply add it as a string
+ _obj[_key] = _val;
+}
+
+void ASTJsonConverter::addJsonNode(string const& _nodeName,
+ initializer_list<pair<string const, string const>> _list,
+ bool _hasChildren = false)
+{
+ Json::Value node;
+
+ node["name"] = _nodeName;
+ if (_list.size() != 0)
+ {
+ Json::Value attrs;
+ for (auto& e: _list)
+ addKeyValue(attrs, e.first, e.second);
+ node["attributes"] = attrs;
+ }
+
+ m_jsonNodePtrs.top()->append(node);
+
+ if (_hasChildren)
+ {
+ Json::Value& addedNode = (*m_jsonNodePtrs.top())[m_jsonNodePtrs.top()->size() - 1];
+ Json::Value children(Json::arrayValue);
+ addedNode["children"] = children;
+ m_jsonNodePtrs.push(&addedNode["children"]);
+ }
+}
+
+ASTJsonConverter::ASTJsonConverter(ASTNode const& _ast): m_ast(&_ast)
+{
+ Json::Value children(Json::arrayValue);
+
+ m_astJson["name"] = "root";
+ m_astJson["children"] = children;
+ m_jsonNodePtrs.push(&m_astJson["children"]);
+}
+
+void ASTJsonConverter::print(ostream& _stream)
+{
+ process();
+ _stream << m_astJson;
+}
+
+Json::Value const& ASTJsonConverter::json()
+{
+ process();
+ return m_astJson;
+}
+
+bool ASTJsonConverter::visit(ImportDirective const& _node)
+{
+ addJsonNode("Import", { make_pair("file", _node.identifier())});
+ return true;
+}
+
+bool ASTJsonConverter::visit(ContractDefinition const& _node)
+{
+ addJsonNode("Contract", { make_pair("name", _node.name()) }, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(StructDefinition const& _node)
+{
+ addJsonNode("Struct", { make_pair("name", _node.name()) }, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(ParameterList const&)
+{
+ addJsonNode("ParameterList", {}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(FunctionDefinition const& _node)
+{
+ addJsonNode("Function",
+ { make_pair("name", _node.name()),
+ make_pair("public", boost::lexical_cast<std::string>(_node.isPublic())),
+ make_pair("const", boost::lexical_cast<std::string>(_node.isDeclaredConst())) },
+ true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(VariableDeclaration const& _node)
+{
+ addJsonNode("VariableDeclaration", {
+ make_pair("name", _node.name()),
+ make_pair("name", _node.name()),
+ }, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(TypeName const&)
+{
+ return true;
+}
+
+bool ASTJsonConverter::visit(ElementaryTypeName const& _node)
+{
+ addJsonNode("ElementaryTypeName", { make_pair("name", Token::toString(_node.typeName())) });
+ return true;
+}
+
+bool ASTJsonConverter::visit(UserDefinedTypeName const& _node)
+{
+ addJsonNode("UserDefinedTypeName", {
+ make_pair("name", boost::algorithm::join(_node.namePath(), "."))
+ });
+ return true;
+}
+
+bool ASTJsonConverter::visit(Mapping const&)
+{
+ addJsonNode("Mapping", {}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(Block const&)
+{
+ addJsonNode("Block", {}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(IfStatement const&)
+{
+ addJsonNode("IfStatement", {}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(WhileStatement const&)
+{
+ addJsonNode("WhileStatement", {}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(ForStatement const&)
+{
+ addJsonNode("ForStatement", {}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(Continue const&)
+{
+ addJsonNode("Continue", {});
+ return true;
+}
+
+bool ASTJsonConverter::visit(Break const&)
+{
+ addJsonNode("Break", {});
+ return true;
+}
+
+bool ASTJsonConverter::visit(Return const&)
+{
+ addJsonNode("Return", {}, true);;
+ return true;
+}
+
+bool ASTJsonConverter::visit(Throw const&)
+{
+ addJsonNode("Throw", {}, true);;
+ return true;
+}
+
+bool ASTJsonConverter::visit(VariableDeclarationStatement const&)
+{
+ addJsonNode("VariableDefinition", {}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(ExpressionStatement const&)
+{
+ addJsonNode("ExpressionStatement", {}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(Assignment const& _node)
+{
+ addJsonNode("Assignment",
+ { make_pair("operator", Token::toString(_node.assignmentOperator())),
+ make_pair("type", type(_node)) },
+ true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(TupleExpression const&)
+{
+ addJsonNode("TupleExpression",{}, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(UnaryOperation const& _node)
+{
+ addJsonNode("UnaryOperation",
+ { make_pair("prefix", boost::lexical_cast<std::string>(_node.isPrefixOperation())),
+ make_pair("operator", Token::toString(_node.getOperator())),
+ make_pair("type", type(_node)) },
+ true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(BinaryOperation const& _node)
+{
+ addJsonNode("BinaryOperation", {
+ make_pair("operator", Token::toString(_node.getOperator())),
+ make_pair("type", type(_node))
+ }, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(FunctionCall const& _node)
+{
+ addJsonNode("FunctionCall", {
+ make_pair("type_conversion", boost::lexical_cast<std::string>(_node.annotation().isTypeConversion)),
+ make_pair("type", type(_node))
+ }, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(NewExpression const& _node)
+{
+ addJsonNode("NewExpression", { make_pair("type", type(_node)) }, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(MemberAccess const& _node)
+{
+ addJsonNode("MemberAccess",
+ { make_pair("member_name", _node.memberName()),
+ make_pair("type", type(_node)) },
+ true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(IndexAccess const& _node)
+{
+ addJsonNode("IndexAccess", { make_pair("type", type(_node)) }, true);
+ return true;
+}
+
+bool ASTJsonConverter::visit(Identifier const& _node)
+{
+ addJsonNode("Identifier",
+ { make_pair("value", _node.name()), make_pair("type", type(_node)) });
+ return true;
+}
+
+bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node)
+{
+ addJsonNode("ElementaryTypenameExpression",
+ { make_pair("value", Token::toString(_node.typeToken())), make_pair("type", type(_node)) });
+ return true;
+}
+
+bool ASTJsonConverter::visit(Literal const& _node)
+{
+ char const* tokenString = Token::toString(_node.token());
+ addJsonNode("Literal",
+ { make_pair("string", (tokenString) ? tokenString : "null"),
+ make_pair("value", _node.value()),
+ make_pair("type", type(_node)) });
+ return true;
+}
+
+void ASTJsonConverter::endVisit(ImportDirective const&)
+{
+}
+
+void ASTJsonConverter::endVisit(ContractDefinition const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(StructDefinition const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(ParameterList const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(FunctionDefinition const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(VariableDeclaration const&)
+{
+}
+
+void ASTJsonConverter::endVisit(TypeName const&)
+{
+}
+
+void ASTJsonConverter::endVisit(ElementaryTypeName const&)
+{
+}
+
+void ASTJsonConverter::endVisit(UserDefinedTypeName const&)
+{
+}
+
+void ASTJsonConverter::endVisit(Mapping const&)
+{
+}
+
+void ASTJsonConverter::endVisit(Block const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(IfStatement const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(WhileStatement const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(ForStatement const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(Continue const&)
+{
+}
+
+void ASTJsonConverter::endVisit(Break const&)
+{
+}
+
+void ASTJsonConverter::endVisit(Return const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(Throw const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(VariableDeclarationStatement const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(ExpressionStatement const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(Assignment const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(TupleExpression const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(UnaryOperation const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(BinaryOperation const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(FunctionCall const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(NewExpression const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(MemberAccess const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(IndexAccess const&)
+{
+ goUp();
+}
+
+void ASTJsonConverter::endVisit(Identifier const&)
+{
+}
+
+void ASTJsonConverter::endVisit(ElementaryTypeNameExpression const&)
+{
+}
+
+void ASTJsonConverter::endVisit(Literal const&)
+{
+}
+
+void ASTJsonConverter::process()
+{
+ if (!processed)
+ m_ast->accept(*this);
+ processed = true;
+}
+
+string ASTJsonConverter::type(Expression const& _expression)
+{
+ return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown";
+}
+
+string ASTJsonConverter::type(VariableDeclaration const& _varDecl)
+{
+ return _varDecl.annotation().type ? _varDecl.annotation().type->toString() : "Unknown";
+}
+
+}
+}
diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h
new file mode 100644
index 00000000..de891cc6
--- /dev/null
+++ b/libsolidity/ast/ASTJsonConverter.h
@@ -0,0 +1,136 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Lefteris <lefteris@ethdev.com>
+ * @date 2015
+ * Converts the AST into json format
+ */
+
+#pragma once
+
+#include <ostream>
+#include <stack>
+#include <libsolidity/ast/ASTVisitor.h>
+#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/interface/Utils.h>
+#include <libsolidity/ast/ASTAnnotations.h>
+#include <json/json.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+/**
+ * Converter of the AST into JSON format
+ */
+class ASTJsonConverter: public ASTConstVisitor
+{
+public:
+ /// Create a converter to JSON for the given abstract syntax tree.
+ explicit ASTJsonConverter(ASTNode const& _ast);
+ /// Output the json representation of the AST to _stream.
+ void print(std::ostream& _stream);
+ Json::Value const& json();
+
+ bool visit(ImportDirective const& _node) override;
+ bool visit(ContractDefinition const& _node) override;
+ bool visit(StructDefinition const& _node) override;
+ bool visit(ParameterList const& _node) override;
+ bool visit(FunctionDefinition const& _node) override;
+ bool visit(VariableDeclaration const& _node) override;
+ bool visit(TypeName const& _node) override;
+ bool visit(ElementaryTypeName const& _node) override;
+ bool visit(UserDefinedTypeName const& _node) override;
+ bool visit(Mapping const& _node) override;
+ bool visit(Block const& _node) override;
+ bool visit(IfStatement const& _node) override;
+ bool visit(WhileStatement const& _node) override;
+ bool visit(ForStatement const& _node) override;
+ bool visit(Continue const& _node) override;
+ bool visit(Break const& _node) override;
+ bool visit(Return const& _node) override;
+ bool visit(Throw const& _node) override;
+ bool visit(VariableDeclarationStatement const& _node) override;
+ bool visit(ExpressionStatement const& _node) override;
+ bool visit(Assignment const& _node) override;
+ bool visit(TupleExpression const& _node) override;
+ bool visit(UnaryOperation const& _node) override;
+ bool visit(BinaryOperation const& _node) override;
+ bool visit(FunctionCall const& _node) override;
+ bool visit(NewExpression const& _node) override;
+ bool visit(MemberAccess const& _node) override;
+ bool visit(IndexAccess const& _node) override;
+ bool visit(Identifier const& _node) override;
+ bool visit(ElementaryTypeNameExpression const& _node) override;
+ bool visit(Literal const& _node) override;
+
+ void endVisit(ImportDirective const&) override;
+ void endVisit(ContractDefinition const&) override;
+ void endVisit(StructDefinition const&) override;
+ void endVisit(ParameterList const&) override;
+ void endVisit(FunctionDefinition const&) override;
+ void endVisit(VariableDeclaration const&) override;
+ void endVisit(TypeName const&) override;
+ void endVisit(ElementaryTypeName const&) override;
+ void endVisit(UserDefinedTypeName const&) override;
+ void endVisit(Mapping const&) override;
+ void endVisit(Block const&) override;
+ void endVisit(IfStatement const&) override;
+ void endVisit(WhileStatement const&) override;
+ void endVisit(ForStatement const&) override;
+ void endVisit(Continue const&) override;
+ void endVisit(Break const&) override;
+ void endVisit(Return const&) override;
+ void endVisit(Throw const&) override;
+ void endVisit(VariableDeclarationStatement const&) override;
+ void endVisit(ExpressionStatement const&) override;
+ void endVisit(Assignment const&) override;
+ void endVisit(TupleExpression const&) override;
+ void endVisit(UnaryOperation const&) override;
+ void endVisit(BinaryOperation const&) override;
+ void endVisit(FunctionCall const&) override;
+ void endVisit(NewExpression const&) override;
+ void endVisit(MemberAccess const&) override;
+ void endVisit(IndexAccess const&) override;
+ void endVisit(Identifier const&) override;
+ void endVisit(ElementaryTypeNameExpression const&) override;
+ void endVisit(Literal const&) override;
+
+private:
+ void process();
+ void addKeyValue(Json::Value& _obj, std::string const& _key, std::string const& _val);
+ void addJsonNode(std::string const& _nodeName,
+ std::initializer_list<std::pair<std::string const, std::string const>> _list,
+ bool _hasChildren);
+ std::string type(Expression const& _expression);
+ std::string type(VariableDeclaration const& _varDecl);
+ inline void goUp()
+ {
+ solAssert(!m_jsonNodePtrs.empty(), "Uneven json nodes stack. Internal error.");
+ m_jsonNodePtrs.pop();
+ }
+
+ bool processed = false;
+ Json::Value m_astJson;
+ std::stack<Json::Value*> m_jsonNodePtrs;
+ std::string m_source;
+ ASTNode const* m_ast;
+};
+
+}
+}
diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp
new file mode 100644
index 00000000..9253e0bf
--- /dev/null
+++ b/libsolidity/ast/ASTPrinter.cpp
@@ -0,0 +1,569 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Pretty-printer for the abstract syntax tree (the "pretty" is arguable), used for debugging.
+ */
+
+#include <libsolidity/ast/ASTPrinter.h>
+#include <boost/algorithm/string/join.hpp>
+#include <libsolidity/ast/AST.h>
+
+using namespace std;
+
+namespace dev
+{
+namespace solidity
+{
+
+ASTPrinter::ASTPrinter(
+ ASTNode const& _ast,
+ string const& _source,
+ GasEstimator::ASTGasConsumption const& _gasCosts
+): m_indentation(0), m_source(_source), m_ast(&_ast), m_gasCosts(_gasCosts)
+{
+}
+
+void ASTPrinter::print(ostream& _stream)
+{
+ m_ostream = &_stream;
+ m_ast->accept(*this);
+ m_ostream = nullptr;
+}
+
+
+bool ASTPrinter::visit(ImportDirective const& _node)
+{
+ writeLine("ImportDirective \"" + _node.identifier() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ContractDefinition const& _node)
+{
+ writeLine("ContractDefinition \"" + _node.name() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(InheritanceSpecifier const& _node)
+{
+ writeLine("InheritanceSpecifier \"" + _node.name().name() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(StructDefinition const& _node)
+{
+ writeLine("StructDefinition \"" + _node.name() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(EnumDefinition const& _node)
+{
+ writeLine("EnumDefinition \"" + _node.name() + "\"");
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(EnumValue const& _node)
+{
+ writeLine("EnumValue \"" + _node.name() + "\"");
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ParameterList const& _node)
+{
+ writeLine("ParameterList");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(FunctionDefinition const& _node)
+{
+ writeLine("FunctionDefinition \"" + _node.name() + "\"" +
+ (_node.isPublic() ? " - public" : "") +
+ (_node.isDeclaredConst() ? " - const" : ""));
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(VariableDeclaration const& _node)
+{
+ writeLine("VariableDeclaration \"" + _node.name() + "\"");
+ *m_ostream << indentation() << (
+ _node.annotation().type ?
+ string(" Type: ") + _node.annotation().type->toString() :
+ string(" Type unknown.")
+ ) << "\n";
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ModifierDefinition const& _node)
+{
+ writeLine("ModifierDefinition \"" + _node.name() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ModifierInvocation const& _node)
+{
+ writeLine("ModifierInvocation \"" + _node.name()->name() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(EventDefinition const& _node)
+{
+ writeLine("EventDefinition \"" + _node.name() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(TypeName const& _node)
+{
+ writeLine("TypeName");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ElementaryTypeName const& _node)
+{
+ writeLine(string("ElementaryTypeName ") + Token::toString(_node.typeName()));
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(UserDefinedTypeName const& _node)
+{
+ writeLine("UserDefinedTypeName \"" + boost::algorithm::join(_node.namePath(), ".") + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Mapping const& _node)
+{
+ writeLine("Mapping");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ArrayTypeName const& _node)
+{
+ writeLine("ArrayTypeName");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Block const& _node)
+{
+ writeLine("Block");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(PlaceholderStatement const& _node)
+{
+ writeLine("PlaceholderStatement");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(IfStatement const& _node)
+{
+ writeLine("IfStatement");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(WhileStatement const& _node)
+{
+ writeLine("WhileStatement");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ForStatement const& _node)
+{
+ writeLine("ForStatement");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Continue const& _node)
+{
+ writeLine("Continue");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Break const& _node)
+{
+ writeLine("Break");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Return const& _node)
+{
+ writeLine("Return");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Throw const& _node)
+{
+ writeLine("Throw");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(VariableDeclarationStatement const& _node)
+{
+ writeLine("VariableDeclarationStatement");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ExpressionStatement const& _node)
+{
+ writeLine("ExpressionStatement");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Assignment const& _node)
+{
+ writeLine(string("Assignment using operator ") + Token::toString(_node.assignmentOperator()));
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(TupleExpression const& _node)
+{
+ writeLine(string("TupleExpression"));
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(UnaryOperation const& _node)
+{
+ writeLine(string("UnaryOperation (") + (_node.isPrefixOperation() ? "prefix" : "postfix") +
+ ") " + Token::toString(_node.getOperator()));
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(BinaryOperation const& _node)
+{
+ writeLine(string("BinaryOperation using operator ") + Token::toString(_node.getOperator()));
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(FunctionCall const& _node)
+{
+ writeLine("FunctionCall");
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(NewExpression const& _node)
+{
+ writeLine("NewExpression");
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(MemberAccess const& _node)
+{
+ writeLine("MemberAccess to member " + _node.memberName());
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(IndexAccess const& _node)
+{
+ writeLine("IndexAccess");
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Identifier const& _node)
+{
+ writeLine(string("Identifier ") + _node.name());
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(ElementaryTypeNameExpression const& _node)
+{
+ writeLine(string("ElementaryTypeNameExpression ") + Token::toString(_node.typeToken()));
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+bool ASTPrinter::visit(Literal const& _node)
+{
+ char const* tokenString = Token::toString(_node.token());
+ if (!tokenString)
+ tokenString = "[no token]";
+ writeLine(string("Literal, token: ") + tokenString + " value: " + _node.value());
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
+void ASTPrinter::endVisit(ImportDirective const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ContractDefinition const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(InheritanceSpecifier const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(StructDefinition const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(EnumDefinition const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(EnumValue const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ParameterList const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(FunctionDefinition const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(VariableDeclaration const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ModifierDefinition const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ModifierInvocation const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(EventDefinition const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(TypeName const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ElementaryTypeName const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(UserDefinedTypeName const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Mapping const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ArrayTypeName const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Block const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(PlaceholderStatement const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(IfStatement const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(WhileStatement const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ForStatement const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Continue const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Break const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Return const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Throw const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(VariableDeclarationStatement const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ExpressionStatement const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Assignment const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(TupleExpression const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(UnaryOperation const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(BinaryOperation const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(FunctionCall const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(NewExpression const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(MemberAccess const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(IndexAccess const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Identifier const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(ElementaryTypeNameExpression const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::endVisit(Literal const&)
+{
+ m_indentation--;
+}
+
+void ASTPrinter::printSourcePart(ASTNode const& _node)
+{
+ if (m_gasCosts.count(&_node))
+ *m_ostream << indentation() << " Gas costs: " << m_gasCosts.at(&_node) << endl;
+ if (!m_source.empty())
+ {
+ SourceLocation const& location(_node.location());
+ *m_ostream << indentation() << " Source: "
+ << escaped(m_source.substr(location.start, location.end - location.start), false) << endl;
+ }
+}
+
+void ASTPrinter::printType(Expression const& _expression)
+{
+ if (_expression.annotation().type)
+ *m_ostream << indentation() << " Type: " << _expression.annotation().type->toString() << "\n";
+ else
+ *m_ostream << indentation() << " Type unknown.\n";
+}
+
+string ASTPrinter::indentation() const
+{
+ return string(m_indentation * 2, ' ');
+}
+
+void ASTPrinter::writeLine(string const& _line)
+{
+ *m_ostream << indentation() << _line << endl;
+}
+
+}
+}
diff --git a/libsolidity/ast/ASTPrinter.h b/libsolidity/ast/ASTPrinter.h
new file mode 100644
index 00000000..d9b5e252
--- /dev/null
+++ b/libsolidity/ast/ASTPrinter.h
@@ -0,0 +1,145 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Pretty-printer for the abstract syntax tree (the "pretty" is arguable), used for debugging.
+ */
+
+#pragma once
+
+#include <ostream>
+#include <libsolidity/ast/ASTVisitor.h>
+#include <libsolidity/interface/GasEstimator.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+/**
+ * Pretty-printer for the abstract syntax tree (the "pretty" is arguable) for debugging purposes.
+ */
+class ASTPrinter: public ASTConstVisitor
+{
+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(
+ ASTNode const& _ast,
+ std::string const& _source = std::string(),
+ GasEstimator::ASTGasConsumption const& _gasCosts = GasEstimator::ASTGasConsumption()
+ );
+ /// Output the string representation of the AST to _stream.
+ void print(std::ostream& _stream);
+
+ bool visit(ImportDirective const& _node) override;
+ bool visit(ContractDefinition const& _node) override;
+ bool visit(InheritanceSpecifier const& _node) override;
+ bool visit(StructDefinition const& _node) override;
+ bool visit(EnumDefinition const& _node) override;
+ bool visit(EnumValue const& _node) override;
+ bool visit(ParameterList const& _node) override;
+ bool visit(FunctionDefinition const& _node) override;
+ bool visit(VariableDeclaration const& _node) override;
+ bool visit(ModifierDefinition const& _node) override;
+ bool visit(ModifierInvocation const& _node) override;
+ bool visit(EventDefinition const& _node) override;
+ bool visit(TypeName const& _node) override;
+ bool visit(ElementaryTypeName const& _node) override;
+ bool visit(UserDefinedTypeName const& _node) override;
+ bool visit(Mapping const& _node) override;
+ bool visit(ArrayTypeName const& _node) override;
+ bool visit(Block const& _node) override;
+ bool visit(PlaceholderStatement const& _node) override;
+ bool visit(IfStatement const& _node) override;
+ bool visit(WhileStatement const& _node) override;
+ bool visit(ForStatement const& _node) override;
+ bool visit(Continue const& _node) override;
+ bool visit(Break const& _node) override;
+ bool visit(Return const& _node) override;
+ bool visit(Throw const& _node) override;
+ bool visit(VariableDeclarationStatement const& _node) override;
+ bool visit(ExpressionStatement const& _node) override;
+ bool visit(Assignment const& _node) override;
+ bool visit(TupleExpression const& _node) override;
+ bool visit(UnaryOperation const& _node) override;
+ bool visit(BinaryOperation const& _node) override;
+ bool visit(FunctionCall const& _node) override;
+ bool visit(NewExpression const& _node) override;
+ bool visit(MemberAccess const& _node) override;
+ bool visit(IndexAccess const& _node) override;
+ bool visit(Identifier const& _node) override;
+ bool visit(ElementaryTypeNameExpression const& _node) override;
+ bool visit(Literal const& _node) override;
+
+ void endVisit(ImportDirective const&) override;
+ void endVisit(ContractDefinition const&) override;
+ void endVisit(InheritanceSpecifier const&) override;
+ void endVisit(StructDefinition const&) override;
+ void endVisit(EnumDefinition const&) override;
+ void endVisit(EnumValue const&) override;
+ void endVisit(ParameterList const&) override;
+ void endVisit(FunctionDefinition const&) override;
+ void endVisit(VariableDeclaration const&) override;
+ void endVisit(ModifierDefinition const&) override;
+ void endVisit(ModifierInvocation const&) override;
+ void endVisit(EventDefinition const&) override;
+ void endVisit(TypeName const&) override;
+ void endVisit(ElementaryTypeName const&) override;
+ void endVisit(UserDefinedTypeName const&) override;
+ void endVisit(Mapping const&) override;
+ void endVisit(ArrayTypeName const&) override;
+ void endVisit(Block const&) override;
+ void endVisit(PlaceholderStatement const&) override;
+ void endVisit(IfStatement const&) override;
+ void endVisit(WhileStatement const&) override;
+ void endVisit(ForStatement const&) override;
+ void endVisit(Continue const&) override;
+ void endVisit(Break const&) override;
+ void endVisit(Return const&) override;
+ void endVisit(Throw const&) override;
+ void endVisit(VariableDeclarationStatement const&) override;
+ void endVisit(ExpressionStatement const&) override;
+ void endVisit(Assignment const&) override;
+ void endVisit(TupleExpression const&) override;
+ void endVisit(UnaryOperation const&) override;
+ void endVisit(BinaryOperation const&) override;
+ void endVisit(FunctionCall const&) override;
+ void endVisit(NewExpression const&) override;
+ void endVisit(MemberAccess const&) override;
+ void endVisit(IndexAccess const&) override;
+ void endVisit(Identifier const&) override;
+ void endVisit(ElementaryTypeNameExpression const&) override;
+ void endVisit(Literal const&) override;
+
+private:
+ void printSourcePart(ASTNode const& _node);
+ void printType(Expression const& _expression);
+ std::string indentation() const;
+ void writeLine(std::string const& _line);
+ bool goDeeper() { m_indentation++; return true; }
+
+ int m_indentation;
+ std::string m_source;
+ ASTNode const* m_ast;
+ GasEstimator::ASTGasConsumption m_gasCosts;
+ std::ostream* m_ostream;
+};
+
+}
+}
diff --git a/libsolidity/ast/ASTUtils.cpp b/libsolidity/ast/ASTUtils.cpp
new file mode 100644
index 00000000..e9b70b62
--- /dev/null
+++ b/libsolidity/ast/ASTUtils.cpp
@@ -0,0 +1,48 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Utilities to work with the AST.
+ */
+
+#include <libsolidity/ast/ASTUtils.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
+
+
+ASTNode const* LocationFinder::leastUpperBound()
+{
+ m_bestMatch = nullptr;
+ for (ASTNode const* rootNode: m_rootNodes)
+ rootNode->accept(*this);
+
+ return m_bestMatch;
+}
+
+bool LocationFinder::visitNode(const ASTNode& _node)
+{
+ if (_node.location().contains(m_location))
+ {
+ m_bestMatch = &_node;
+ return true;
+ }
+ return false;
+}
diff --git a/libsolidity/ast/ASTUtils.h b/libsolidity/ast/ASTUtils.h
new file mode 100644
index 00000000..237537ec
--- /dev/null
+++ b/libsolidity/ast/ASTUtils.h
@@ -0,0 +1,54 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2015
+ * Utilities to work with the AST.
+ */
+
+#pragma once
+
+#include <libevmasm/SourceLocation.h>
+#include <libsolidity/ast/ASTVisitor.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+class LocationFinder: private ASTConstVisitor
+{
+public:
+ LocationFinder(SourceLocation const& _location, std::vector<ASTNode const*> _rootNodes):
+ m_rootNodes(_rootNodes), m_location(_location)
+ {
+ }
+
+ /// @returns the "closest" (in the sense of most-leafward) AST node which is a descendant of
+ /// _node and whose source location contains _location.
+ ASTNode const* leastUpperBound();
+
+private:
+ bool visitNode(ASTNode const& _node);
+
+ std::vector<ASTNode const*> m_rootNodes;
+ SourceLocation m_location;
+ ASTNode const* m_bestMatch = nullptr;
+};
+
+}
+}
diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h
new file mode 100644
index 00000000..14c09fb4
--- /dev/null
+++ b/libsolidity/ast/ASTVisitor.h
@@ -0,0 +1,294 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * AST visitor base class.
+ */
+
+#pragma once
+
+#include <string>
+#include <functional>
+#include <vector>
+#include <libsolidity/ast/AST.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+/**
+ * Visitor interface for the abstract syntax tree. This class is tightly bound to the
+ * implementation of @ref ASTNode::accept and its overrides. After a call to
+ * @ref ASTNode::accept, the function visit for the appropriate parameter is called and then
+ * (if it returns true) this continues recursively for all child nodes in document order
+ * (there is an exception for contracts). After all child nodes have been visited, endVisit is
+ * called for the node.
+ */
+class ASTVisitor
+{
+public:
+ virtual bool visit(SourceUnit& _node) { return visitNode(_node); }
+ virtual bool visit(ImportDirective& _node) { return visitNode(_node); }
+ virtual bool visit(ContractDefinition& _node) { return visitNode(_node); }
+ virtual bool visit(InheritanceSpecifier& _node) { return visitNode(_node); }
+ virtual bool visit(StructDefinition& _node) { return visitNode(_node); }
+ virtual bool visit(EnumDefinition& _node) { return visitNode(_node); }
+ virtual bool visit(EnumValue& _node) { return visitNode(_node); }
+ virtual bool visit(ParameterList& _node) { return visitNode(_node); }
+ virtual bool visit(FunctionDefinition& _node) { return visitNode(_node); }
+ virtual bool visit(VariableDeclaration& _node) { return visitNode(_node); }
+ virtual bool visit(ModifierDefinition& _node) { return visitNode(_node); }
+ virtual bool visit(ModifierInvocation& _node) { return visitNode(_node); }
+ virtual bool visit(EventDefinition& _node) { return visitNode(_node); }
+ virtual bool visit(TypeName& _node) { return visitNode(_node); }
+ virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); }
+ virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); }
+ virtual bool visit(Mapping& _node) { return visitNode(_node); }
+ virtual bool visit(ArrayTypeName& _node) { return visitNode(_node); }
+ virtual bool visit(Block& _node) { return visitNode(_node); }
+ virtual bool visit(PlaceholderStatement& _node) { return visitNode(_node); }
+ virtual bool visit(IfStatement& _node) { return visitNode(_node); }
+ virtual bool visit(WhileStatement& _node) { return visitNode(_node); }
+ virtual bool visit(ForStatement& _node) { return visitNode(_node); }
+ virtual bool visit(Continue& _node) { return visitNode(_node); }
+ virtual bool visit(Break& _node) { return visitNode(_node); }
+ virtual bool visit(Return& _node) { return visitNode(_node); }
+ virtual bool visit(Throw& _node) { return visitNode(_node); }
+ virtual bool visit(VariableDeclarationStatement& _node) { return visitNode(_node); }
+ virtual bool visit(ExpressionStatement& _node) { return visitNode(_node); }
+ virtual bool visit(Assignment& _node) { return visitNode(_node); }
+ virtual bool visit(TupleExpression& _node) { return visitNode(_node); }
+ virtual bool visit(UnaryOperation& _node) { return visitNode(_node); }
+ virtual bool visit(BinaryOperation& _node) { return visitNode(_node); }
+ virtual bool visit(FunctionCall& _node) { return visitNode(_node); }
+ virtual bool visit(NewExpression& _node) { return visitNode(_node); }
+ virtual bool visit(MemberAccess& _node) { return visitNode(_node); }
+ virtual bool visit(IndexAccess& _node) { return visitNode(_node); }
+ virtual bool visit(Identifier& _node) { return visitNode(_node); }
+ virtual bool visit(ElementaryTypeNameExpression& _node) { return visitNode(_node); }
+ virtual bool visit(Literal& _node) { return visitNode(_node); }
+
+ virtual void endVisit(SourceUnit& _node) { endVisitNode(_node); }
+ virtual void endVisit(ImportDirective& _node) { endVisitNode(_node); }
+ virtual void endVisit(ContractDefinition& _node) { endVisitNode(_node); }
+ virtual void endVisit(InheritanceSpecifier& _node) { endVisitNode(_node); }
+ virtual void endVisit(StructDefinition& _node) { endVisitNode(_node); }
+ virtual void endVisit(EnumDefinition& _node) { endVisitNode(_node); }
+ virtual void endVisit(EnumValue& _node) { endVisitNode(_node); }
+ virtual void endVisit(ParameterList& _node) { endVisitNode(_node); }
+ virtual void endVisit(FunctionDefinition& _node) { endVisitNode(_node); }
+ virtual void endVisit(VariableDeclaration& _node) { endVisitNode(_node); }
+ virtual void endVisit(ModifierDefinition& _node) { endVisitNode(_node); }
+ virtual void endVisit(ModifierInvocation& _node) { endVisitNode(_node); }
+ virtual void endVisit(EventDefinition& _node) { endVisitNode(_node); }
+ virtual void endVisit(TypeName& _node) { endVisitNode(_node); }
+ virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); }
+ virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); }
+ virtual void endVisit(Mapping& _node) { endVisitNode(_node); }
+ virtual void endVisit(ArrayTypeName& _node) { endVisitNode(_node); }
+ virtual void endVisit(Block& _node) { endVisitNode(_node); }
+ virtual void endVisit(PlaceholderStatement& _node) { endVisitNode(_node); }
+ virtual void endVisit(IfStatement& _node) { endVisitNode(_node); }
+ virtual void endVisit(WhileStatement& _node) { endVisitNode(_node); }
+ virtual void endVisit(ForStatement& _node) { endVisitNode(_node); }
+ virtual void endVisit(Continue& _node) { endVisitNode(_node); }
+ virtual void endVisit(Break& _node) { endVisitNode(_node); }
+ virtual void endVisit(Return& _node) { endVisitNode(_node); }
+ virtual void endVisit(Throw& _node) { endVisitNode(_node); }
+ virtual void endVisit(VariableDeclarationStatement& _node) { endVisitNode(_node); }
+ virtual void endVisit(ExpressionStatement& _node) { endVisitNode(_node); }
+ virtual void endVisit(Assignment& _node) { endVisitNode(_node); }
+ virtual void endVisit(TupleExpression& _node) { endVisitNode(_node); }
+ virtual void endVisit(UnaryOperation& _node) { endVisitNode(_node); }
+ virtual void endVisit(BinaryOperation& _node) { endVisitNode(_node); }
+ virtual void endVisit(FunctionCall& _node) { endVisitNode(_node); }
+ virtual void endVisit(NewExpression& _node) { endVisitNode(_node); }
+ virtual void endVisit(MemberAccess& _node) { endVisitNode(_node); }
+ virtual void endVisit(IndexAccess& _node) { endVisitNode(_node); }
+ virtual void endVisit(Identifier& _node) { endVisitNode(_node); }
+ virtual void endVisit(ElementaryTypeNameExpression& _node) { endVisitNode(_node); }
+ virtual void endVisit(Literal& _node) { endVisitNode(_node); }
+
+protected:
+ /// Generic function called by default for each node, to be overridden by derived classes
+ /// if behaviour unspecific to a node type is desired.
+ virtual bool visitNode(ASTNode&) { return true; }
+ /// Generic function called by default for each node, to be overridden by derived classes
+ /// if behaviour unspecific to a node type is desired.
+ virtual void endVisitNode(ASTNode&) { }
+};
+
+class ASTConstVisitor
+{
+public:
+ virtual bool visit(SourceUnit const& _node) { return visitNode(_node); }
+ virtual bool visit(ImportDirective const& _node) { return visitNode(_node); }
+ virtual bool visit(ContractDefinition const& _node) { return visitNode(_node); }
+ virtual bool visit(InheritanceSpecifier const& _node) { return visitNode(_node); }
+ virtual bool visit(StructDefinition const& _node) { return visitNode(_node); }
+ virtual bool visit(EnumDefinition const& _node) { return visitNode(_node); }
+ virtual bool visit(EnumValue const& _node) { return visitNode(_node); }
+ virtual bool visit(ParameterList const& _node) { return visitNode(_node); }
+ virtual bool visit(FunctionDefinition const& _node) { return visitNode(_node); }
+ virtual bool visit(VariableDeclaration const& _node) { return visitNode(_node); }
+ virtual bool visit(ModifierDefinition const& _node) { return visitNode(_node); }
+ virtual bool visit(ModifierInvocation const& _node) { return visitNode(_node); }
+ virtual bool visit(EventDefinition const& _node) { return visitNode(_node); }
+ virtual bool visit(TypeName const& _node) { return visitNode(_node); }
+ virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); }
+ virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); }
+ virtual bool visit(Mapping const& _node) { return visitNode(_node); }
+ virtual bool visit(ArrayTypeName const& _node) { return visitNode(_node); }
+ virtual bool visit(Block const& _node) { return visitNode(_node); }
+ virtual bool visit(PlaceholderStatement const& _node) { return visitNode(_node); }
+ virtual bool visit(IfStatement const& _node) { return visitNode(_node); }
+ virtual bool visit(WhileStatement const& _node) { return visitNode(_node); }
+ virtual bool visit(ForStatement const& _node) { return visitNode(_node); }
+ virtual bool visit(Continue const& _node) { return visitNode(_node); }
+ virtual bool visit(Break const& _node) { return visitNode(_node); }
+ virtual bool visit(Return const& _node) { return visitNode(_node); }
+ virtual bool visit(Throw const& _node) { return visitNode(_node); }
+ virtual bool visit(VariableDeclarationStatement const& _node) { return visitNode(_node); }
+ virtual bool visit(ExpressionStatement const& _node) { return visitNode(_node); }
+ virtual bool visit(Assignment const& _node) { return visitNode(_node); }
+ virtual bool visit(TupleExpression const& _node) { return visitNode(_node); }
+ virtual bool visit(UnaryOperation const& _node) { return visitNode(_node); }
+ virtual bool visit(BinaryOperation const& _node) { return visitNode(_node); }
+ virtual bool visit(FunctionCall const& _node) { return visitNode(_node); }
+ virtual bool visit(NewExpression const& _node) { return visitNode(_node); }
+ virtual bool visit(MemberAccess const& _node) { return visitNode(_node); }
+ virtual bool visit(IndexAccess const& _node) { return visitNode(_node); }
+ virtual bool visit(Identifier const& _node) { return visitNode(_node); }
+ virtual bool visit(ElementaryTypeNameExpression const& _node) { return visitNode(_node); }
+ virtual bool visit(Literal const& _node) { return visitNode(_node); }
+
+ virtual void endVisit(SourceUnit const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ImportDirective const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ContractDefinition const& _node) { endVisitNode(_node); }
+ virtual void endVisit(InheritanceSpecifier const& _node) { endVisitNode(_node); }
+ virtual void endVisit(StructDefinition const& _node) { endVisitNode(_node); }
+ virtual void endVisit(EnumDefinition const& _node) { endVisitNode(_node); }
+ virtual void endVisit(EnumValue const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ParameterList const& _node) { endVisitNode(_node); }
+ virtual void endVisit(FunctionDefinition const& _node) { endVisitNode(_node); }
+ virtual void endVisit(VariableDeclaration const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ModifierDefinition const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ModifierInvocation const& _node) { endVisitNode(_node); }
+ virtual void endVisit(EventDefinition const& _node) { endVisitNode(_node); }
+ virtual void endVisit(TypeName const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); }
+ virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Mapping const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ArrayTypeName const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Block const& _node) { endVisitNode(_node); }
+ virtual void endVisit(PlaceholderStatement const& _node) { endVisitNode(_node); }
+ virtual void endVisit(IfStatement const& _node) { endVisitNode(_node); }
+ virtual void endVisit(WhileStatement const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ForStatement const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Continue const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Break const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Return const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Throw const& _node) { endVisitNode(_node); }
+ virtual void endVisit(VariableDeclarationStatement const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ExpressionStatement const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Assignment const& _node) { endVisitNode(_node); }
+ virtual void endVisit(TupleExpression const& _node) { endVisitNode(_node); }
+ virtual void endVisit(UnaryOperation const& _node) { endVisitNode(_node); }
+ virtual void endVisit(BinaryOperation const& _node) { endVisitNode(_node); }
+ virtual void endVisit(FunctionCall const& _node) { endVisitNode(_node); }
+ virtual void endVisit(NewExpression const& _node) { endVisitNode(_node); }
+ virtual void endVisit(MemberAccess const& _node) { endVisitNode(_node); }
+ virtual void endVisit(IndexAccess const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Identifier const& _node) { endVisitNode(_node); }
+ virtual void endVisit(ElementaryTypeNameExpression const& _node) { endVisitNode(_node); }
+ virtual void endVisit(Literal const& _node) { endVisitNode(_node); }
+
+protected:
+ /// Generic function called by default for each node, to be overridden by derived classes
+ /// if behaviour unspecific to a node type is desired.
+ virtual bool visitNode(ASTNode const&) { return true; }
+ /// Generic function called by default for each node, to be overridden by derived classes
+ /// if behaviour unspecific to a node type is desired.
+ virtual void endVisitNode(ASTNode const&) { }
+};
+
+/**
+ * Utility class that accepts std::functions and calls them for visitNode and endVisitNode.
+ */
+class SimpleASTVisitor: public ASTConstVisitor
+{
+public:
+ SimpleASTVisitor(
+ std::function<bool(ASTNode const&)> _onVisit,
+ std::function<void(ASTNode const&)> _onEndVisit
+ ): m_onVisit(_onVisit), m_onEndVisit(_onEndVisit) {}
+
+protected:
+ virtual bool visitNode(ASTNode const& _n) override { return m_onVisit ? m_onVisit(_n) : true; }
+ virtual void endVisitNode(ASTNode const& _n) override { m_onEndVisit(_n); }
+
+private:
+ std::function<bool(ASTNode const&)> m_onVisit;
+ std::function<void(ASTNode const&)> m_onEndVisit;
+};
+
+/**
+ * Utility class that visits the AST in depth-first order and calls a function on each node and each edge.
+ * Child nodes are only visited if the node callback of the parent returns true.
+ * The node callback of a parent is called before any edge or node callback involving the children.
+ * The edge callbacks of all children are called before the edge callback of the parent.
+ * This way, the node callback can be used as an initializing callback and the edge callbacks can be
+ * used to compute a "reduce" function.
+ */
+class ASTReduce: public ASTConstVisitor
+{
+public:
+ /**
+ * Constructs a new ASTReduce object with the given callback functions.
+ * @param _onNode called for each node, before its child edges and nodes, should return true to descend deeper
+ * @param _onEdge called for each edge with (parent, child)
+ */
+ ASTReduce(
+ std::function<bool(ASTNode const&)> _onNode,
+ std::function<void(ASTNode const&, ASTNode const&)> _onEdge
+ ): m_onNode(_onNode), m_onEdge(_onEdge)
+ {
+ }
+
+protected:
+ bool visitNode(ASTNode const& _node) override
+ {
+ m_parents.push_back(&_node);
+ return m_onNode(_node);
+ }
+ void endVisitNode(ASTNode const& _node) override
+ {
+ m_parents.pop_back();
+ if (!m_parents.empty())
+ m_onEdge(*m_parents.back(), _node);
+ }
+
+private:
+ std::vector<ASTNode const*> m_parents;
+ std::function<bool(ASTNode const&)> m_onNode;
+ std::function<void(ASTNode const&, ASTNode const&)> m_onEdge;
+};
+
+}
+}
diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h
new file mode 100644
index 00000000..12a26ea7
--- /dev/null
+++ b/libsolidity/ast/AST_accept.h
@@ -0,0 +1,721 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Implementation of the accept functions of AST nodes, included by AST.cpp to not clutter that
+ * file with these mechanical implementations.
+ */
+
+#pragma once
+
+#include <libsolidity/ast/AST.h>
+#include <libsolidity/ast/ASTVisitor.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+void SourceUnit::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ listAccept(m_nodes, _visitor);
+ _visitor.endVisit(*this);
+}
+
+void SourceUnit::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ listAccept(m_nodes, _visitor);
+ _visitor.endVisit(*this);
+}
+
+void ImportDirective::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void ImportDirective::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void ContractDefinition::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ listAccept(m_baseContracts, _visitor);
+ listAccept(m_definedStructs, _visitor);
+ listAccept(m_definedEnums, _visitor);
+ listAccept(m_stateVariables, _visitor);
+ listAccept(m_events, _visitor);
+ listAccept(m_functionModifiers, _visitor);
+ listAccept(m_definedFunctions, _visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ContractDefinition::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ listAccept(m_baseContracts, _visitor);
+ listAccept(m_definedStructs, _visitor);
+ listAccept(m_definedEnums, _visitor);
+ listAccept(m_stateVariables, _visitor);
+ listAccept(m_events, _visitor);
+ listAccept(m_functionModifiers, _visitor);
+ listAccept(m_definedFunctions, _visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void InheritanceSpecifier::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ m_baseName->accept(_visitor);
+ listAccept(m_arguments, _visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void InheritanceSpecifier::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_baseName->accept(_visitor);
+ listAccept(m_arguments, _visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void EnumDefinition::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ listAccept(m_members, _visitor);
+ _visitor.endVisit(*this);
+}
+
+void EnumDefinition::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ listAccept(m_members, _visitor);
+ _visitor.endVisit(*this);
+}
+
+void EnumValue::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void EnumValue::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void StructDefinition::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ listAccept(m_members, _visitor);
+ _visitor.endVisit(*this);
+}
+
+void StructDefinition::accept(ASTConstVisitor& _visitor) const
+{
+ 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 ParameterList::accept(ASTConstVisitor& _visitor) const
+{
+ 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);
+ listAccept(m_functionModifiers, _visitor);
+ if (m_body)
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void FunctionDefinition::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_parameters->accept(_visitor);
+ if (m_returnParameters)
+ m_returnParameters->accept(_visitor);
+ listAccept(m_functionModifiers, _visitor);
+ if (m_body)
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void VariableDeclaration::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ if (m_typeName)
+ m_typeName->accept(_visitor);
+ if (m_value)
+ m_value->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void VariableDeclaration::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ if (m_typeName)
+ m_typeName->accept(_visitor);
+ if (m_value)
+ m_value->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ModifierDefinition::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ m_parameters->accept(_visitor);
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ModifierDefinition::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_parameters->accept(_visitor);
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ModifierInvocation::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ m_modifierName->accept(_visitor);
+ listAccept(m_arguments, _visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ModifierInvocation::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_modifierName->accept(_visitor);
+ listAccept(m_arguments, _visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void EventDefinition::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ m_parameters->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void EventDefinition::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ m_parameters->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void TypeName::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void TypeName::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void ElementaryTypeName::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void ElementaryTypeName::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void UserDefinedTypeName::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void UserDefinedTypeName::accept(ASTConstVisitor& _visitor) const
+{
+ _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 Mapping::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_keyType->accept(_visitor);
+ m_valueType->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ArrayTypeName::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ m_baseType->accept(_visitor);
+ if (m_length)
+ m_length->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ArrayTypeName::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_baseType->accept(_visitor);
+ if (m_length)
+ m_length->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void Block::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ listAccept(m_statements, _visitor);
+ _visitor.endVisit(*this);
+}
+
+void Block::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ listAccept(m_statements, _visitor);
+ _visitor.endVisit(*this);
+}
+
+void PlaceholderStatement::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void PlaceholderStatement::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _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 IfStatement::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_condition->accept(_visitor);
+ m_trueBody->accept(_visitor);
+ if (m_falseBody)
+ m_falseBody->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void WhileStatement::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ m_condition->accept(_visitor);
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void WhileStatement::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_condition->accept(_visitor);
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ForStatement::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ if (m_initExpression)
+ m_initExpression->accept(_visitor);
+ if (m_condExpression)
+ m_condExpression->accept(_visitor);
+ if (m_loopExpression)
+ m_loopExpression->accept(_visitor);
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void ForStatement::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ if (m_initExpression)
+ m_initExpression->accept(_visitor);
+ if (m_condExpression)
+ m_condExpression->accept(_visitor);
+ if (m_loopExpression)
+ m_loopExpression->accept(_visitor);
+ m_body->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void Continue::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void Continue::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void Break::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void Break::accept(ASTConstVisitor& _visitor) const
+{
+ _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 Return::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ if (m_expression)
+ m_expression->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void Throw::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void Throw::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void ExpressionStatement::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ if (m_expression)
+ m_expression->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void ExpressionStatement::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ if (m_expression)
+ m_expression->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void VariableDeclarationStatement::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ for (ASTPointer<VariableDeclaration> const& var: m_variables)
+ if (var)
+ var->accept(_visitor);
+ if (m_initialValue)
+ m_initialValue->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void VariableDeclarationStatement::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ for (ASTPointer<VariableDeclaration> const& var: m_variables)
+ if (var)
+ var->accept(_visitor);
+ if (m_initialValue)
+ m_initialValue->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void Assignment::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ m_leftHandSide->accept(_visitor);
+ m_rightHandSide->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void Assignment::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_leftHandSide->accept(_visitor);
+ m_rightHandSide->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void TupleExpression::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ for (auto const& component: m_components)
+ if (component)
+ component->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void TupleExpression::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ for (auto const& component: m_components)
+ if (component)
+ component->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void UnaryOperation::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ m_subExpression->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void UnaryOperation::accept(ASTConstVisitor& _visitor) const
+{
+ 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 BinaryOperation::accept(ASTConstVisitor& _visitor) const
+{
+ 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 FunctionCall::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_expression->accept(_visitor);
+ listAccept(m_arguments, _visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void NewExpression::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ m_contractName->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void NewExpression::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ m_contractName->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void MemberAccess::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ m_expression->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void MemberAccess::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ m_expression->accept(_visitor);
+ _visitor.endVisit(*this);
+}
+
+void IndexAccess::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ {
+ m_base->accept(_visitor);
+ if (m_index)
+ m_index->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void IndexAccess::accept(ASTConstVisitor& _visitor) const
+{
+ if (_visitor.visit(*this))
+ {
+ m_base->accept(_visitor);
+ if (m_index)
+ m_index->accept(_visitor);
+ }
+ _visitor.endVisit(*this);
+}
+
+void Identifier::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void Identifier::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void ElementaryTypeNameExpression::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void ElementaryTypeNameExpression::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void Literal::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+void Literal::accept(ASTConstVisitor& _visitor) const
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
+}
+}
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
new file mode 100644
index 00000000..0253e843
--- /dev/null
+++ b/libsolidity/ast/Types.cpp
@@ -0,0 +1,1921 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity data types
+ */
+
+#include <libsolidity/ast/Types.h>
+#include <limits>
+#include <boost/range/adaptor/reversed.hpp>
+#include <libdevcore/CommonIO.h>
+#include <libdevcore/CommonData.h>
+#include <libdevcore/SHA3.h>
+#include <libsolidity/interface/Utils.h>
+#include <libsolidity/ast/AST.h>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+
+void StorageOffsets::computeOffsets(TypePointers const& _types)
+{
+ bigint slotOffset = 0;
+ unsigned byteOffset = 0;
+ map<size_t, pair<u256, unsigned>> offsets;
+ for (size_t i = 0; i < _types.size(); ++i)
+ {
+ TypePointer const& type = _types[i];
+ if (!type->canBeStored())
+ continue;
+ if (byteOffset + type->storageBytes() > 32)
+ {
+ // would overflow, go to next slot
+ ++slotOffset;
+ byteOffset = 0;
+ }
+ if (slotOffset >= bigint(1) << 256)
+ BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Object too large for storage."));
+ offsets[i] = make_pair(u256(slotOffset), byteOffset);
+ solAssert(type->storageSize() >= 1, "Invalid storage size.");
+ if (type->storageSize() == 1 && byteOffset + type->storageBytes() <= 32)
+ byteOffset += type->storageBytes();
+ else
+ {
+ slotOffset += type->storageSize();
+ byteOffset = 0;
+ }
+ }
+ if (byteOffset > 0)
+ ++slotOffset;
+ if (slotOffset >= bigint(1) << 256)
+ BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Object too large for storage."));
+ m_storageSize = u256(slotOffset);
+ swap(m_offsets, offsets);
+}
+
+pair<u256, unsigned> const* StorageOffsets::offset(size_t _index) const
+{
+ if (m_offsets.count(_index))
+ return &m_offsets.at(_index);
+ else
+ return nullptr;
+}
+
+MemberList& MemberList::operator=(MemberList&& _other)
+{
+ assert(&_other != this);
+
+ m_memberTypes = std::move(_other.m_memberTypes);
+ m_storageOffsets = std::move(_other.m_storageOffsets);
+ return *this;
+}
+
+std::pair<u256, unsigned> const* MemberList::memberStorageOffset(string const& _name) const
+{
+ if (!m_storageOffsets)
+ {
+ TypePointers memberTypes;
+ memberTypes.reserve(m_memberTypes.size());
+ for (auto const& member: m_memberTypes)
+ memberTypes.push_back(member.type);
+ m_storageOffsets.reset(new StorageOffsets());
+ m_storageOffsets->computeOffsets(memberTypes);
+ }
+ for (size_t index = 0; index < m_memberTypes.size(); ++index)
+ if (m_memberTypes[index].name == _name)
+ return m_storageOffsets->offset(index);
+ return nullptr;
+}
+
+u256 const& MemberList::storageSize() const
+{
+ // trigger lazy computation
+ memberStorageOffset("");
+ return m_storageOffsets->storageSize();
+}
+
+TypePointer Type::fromElementaryTypeName(Token::Value _typeToken)
+{
+ char const* tokenCstr = Token::toString(_typeToken);
+ solAssert(Token::isElementaryTypeName(_typeToken),
+ "Expected an elementary type name but got " + ((tokenCstr) ? std::string(Token::toString(_typeToken)) : ""));
+
+ if (Token::Int <= _typeToken && _typeToken <= Token::Bytes32)
+ {
+ int offset = _typeToken - Token::Int;
+ int bytes = offset % 33;
+ if (bytes == 0 && _typeToken != Token::Bytes1)
+ bytes = 32;
+ int modifier = offset / 33;
+ switch(modifier)
+ {
+ case 0:
+ return make_shared<IntegerType>(bytes * 8, IntegerType::Modifier::Signed);
+ case 1:
+ return make_shared<IntegerType>(bytes * 8, IntegerType::Modifier::Unsigned);
+ case 2:
+ return make_shared<FixedBytesType>(bytes + 1);
+ default:
+ solAssert(false, "Unexpected modifier value. Should never happen");
+ return TypePointer();
+ }
+ }
+ else if (_typeToken == Token::Byte)
+ return make_shared<FixedBytesType>(1);
+ else if (_typeToken == Token::Address)
+ return make_shared<IntegerType>(0, IntegerType::Modifier::Address);
+ else if (_typeToken == Token::Bool)
+ return make_shared<BoolType>();
+ else if (_typeToken == Token::Bytes)
+ return make_shared<ArrayType>(DataLocation::Storage);
+ else if (_typeToken == Token::String)
+ return make_shared<ArrayType>(DataLocation::Storage, true);
+ else
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment(
+ "Unable to convert elementary typename " + std::string(Token::toString(_typeToken)) + " to type."
+ ));
+}
+
+TypePointer Type::fromElementaryTypeName(string const& _name)
+{
+ return fromElementaryTypeName(Token::fromIdentifierOrKeyword(_name));
+}
+
+TypePointer Type::forLiteral(Literal const& _literal)
+{
+ switch (_literal.token())
+ {
+ case Token::TrueLiteral:
+ case Token::FalseLiteral:
+ return make_shared<BoolType>();
+ case Token::Number:
+ if (!IntegerConstantType::isValidLiteral(_literal))
+ return TypePointer();
+ return make_shared<IntegerConstantType>(_literal);
+ case Token::StringLiteral:
+ return make_shared<StringLiteralType>(_literal);
+ default:
+ return shared_ptr<Type>();
+ }
+}
+
+TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
+{
+ if (_b->isImplicitlyConvertibleTo(*_a))
+ return _a;
+ else if (_a->isImplicitlyConvertibleTo(*_b))
+ return _b;
+ else
+ return TypePointer();
+}
+
+const MemberList Type::EmptyMemberList;
+
+IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
+ m_bits(_bits), m_modifier(_modifier)
+{
+ if (isAddress())
+ m_bits = 160;
+ solAssert(m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
+ "Invalid bit number for integer type: " + dev::toString(_bits));
+}
+
+bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ if (_convertTo.category() != category())
+ return false;
+ IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
+ if (convertTo.m_bits < m_bits)
+ return false;
+ if (isAddress())
+ return convertTo.isAddress();
+ else if (isSigned())
+ return convertTo.isSigned();
+ else
+ return !convertTo.isSigned() || convertTo.m_bits > m_bits;
+}
+
+bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ return _convertTo.category() == category() ||
+ _convertTo.category() == Category::Contract ||
+ _convertTo.category() == Category::Enum ||
+ _convertTo.category() == Category::FixedBytes;
+}
+
+TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
+{
+ // "delete" is ok for all integer types
+ if (_operator == Token::Delete)
+ return make_shared<TupleType>();
+ // no further unary operators for addresses
+ else if (isAddress())
+ return TypePointer();
+ // for non-address integers, we allow +, -, ++ and --
+ else if (_operator == Token::Add || _operator == Token::Sub ||
+ _operator == Token::Inc || _operator == Token::Dec ||
+ _operator == Token::After || _operator == Token::BitNot)
+ return shared_from_this();
+ else
+ return TypePointer();
+}
+
+bool IntegerType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ IntegerType const& other = dynamic_cast<IntegerType const&>(_other);
+ return other.m_bits == m_bits && other.m_modifier == m_modifier;
+}
+
+string IntegerType::toString(bool) const
+{
+ if (isAddress())
+ return "address";
+ string prefix = isSigned() ? "int" : "uint";
+ return prefix + dev::toString(m_bits);
+}
+
+TypePointer IntegerType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+{
+ if (_other->category() != Category::IntegerConstant && _other->category() != category())
+ return TypePointer();
+ auto commonType = dynamic_pointer_cast<IntegerType const>(Type::commonType(shared_from_this(), _other));
+
+ if (!commonType)
+ return TypePointer();
+
+ // All integer types can be compared
+ if (Token::isCompareOp(_operator))
+ return commonType;
+ if (Token::isBooleanOp(_operator))
+ return TypePointer();
+ // Nothing else can be done with addresses
+ if (commonType->isAddress())
+ return TypePointer();
+
+ return commonType;
+}
+
+const MemberList IntegerType::AddressMemberList({
+ {"balance", make_shared<IntegerType >(256)},
+ {"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::Bare, true)},
+ {"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Location::BareCallCode, true)},
+ {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Location::Send)}
+});
+
+bool IntegerConstantType::isValidLiteral(const Literal& _literal)
+{
+ try
+ {
+ bigint x(_literal.value());
+ }
+ catch (...)
+ {
+ return false;
+ }
+ return true;
+}
+
+IntegerConstantType::IntegerConstantType(Literal const& _literal)
+{
+ m_value = bigint(_literal.value());
+
+ switch (_literal.subDenomination())
+ {
+ case Literal::SubDenomination::Wei:
+ case Literal::SubDenomination::Second:
+ case Literal::SubDenomination::None:
+ break;
+ case Literal::SubDenomination::Szabo:
+ m_value *= bigint("1000000000000");
+ break;
+ case Literal::SubDenomination::Finney:
+ m_value *= bigint("1000000000000000");
+ break;
+ case Literal::SubDenomination::Ether:
+ m_value *= bigint("1000000000000000000");
+ break;
+ case Literal::SubDenomination::Minute:
+ m_value *= bigint("60");
+ break;
+ case Literal::SubDenomination::Hour:
+ m_value *= bigint("3600");
+ break;
+ case Literal::SubDenomination::Day:
+ m_value *= bigint("86400");
+ break;
+ case Literal::SubDenomination::Week:
+ m_value *= bigint("604800");
+ break;
+ case Literal::SubDenomination::Year:
+ m_value *= bigint("31536000");
+ break;
+ }
+}
+
+bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ if (auto targetType = dynamic_cast<IntegerType const*>(&_convertTo))
+ {
+ if (m_value == 0)
+ return true;
+ int forSignBit = (targetType->isSigned() ? 1 : 0);
+ if (m_value > 0)
+ {
+ if (m_value <= (u256(-1) >> (256 - targetType->numBits() + forSignBit)))
+ return true;
+ }
+ else if (targetType->isSigned() && -m_value <= (u256(1) << (targetType->numBits() - forSignBit)))
+ return true;
+ return false;
+ }
+ else if (_convertTo.category() == Category::FixedBytes)
+ {
+ FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo);
+ return fixedBytes.numBytes() * 8 >= integerType()->numBits();
+ }
+ else
+ return false;
+}
+
+bool IntegerConstantType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ TypePointer intType = integerType();
+ return intType && intType->isExplicitlyConvertibleTo(_convertTo);
+}
+
+TypePointer IntegerConstantType::unaryOperatorResult(Token::Value _operator) const
+{
+ bigint value;
+ switch (_operator)
+ {
+ case Token::BitNot:
+ value = ~m_value;
+ break;
+ case Token::Add:
+ value = m_value;
+ break;
+ case Token::Sub:
+ value = -m_value;
+ break;
+ case Token::After:
+ return shared_from_this();
+ default:
+ return TypePointer();
+ }
+ return make_shared<IntegerConstantType>(value);
+}
+
+TypePointer IntegerConstantType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+{
+ if (_other->category() == Category::Integer)
+ {
+ shared_ptr<IntegerType const> intType = integerType();
+ if (!intType)
+ return TypePointer();
+ return intType->binaryOperatorResult(_operator, _other);
+ }
+ else if (_other->category() != category())
+ return TypePointer();
+
+ IntegerConstantType const& other = dynamic_cast<IntegerConstantType const&>(*_other);
+ if (Token::isCompareOp(_operator))
+ {
+ shared_ptr<IntegerType const> thisIntegerType = integerType();
+ shared_ptr<IntegerType const> otherIntegerType = other.integerType();
+ if (!thisIntegerType || !otherIntegerType)
+ return TypePointer();
+ return thisIntegerType->binaryOperatorResult(_operator, otherIntegerType);
+ }
+ else
+ {
+ bigint value;
+ switch (_operator)
+ {
+ case Token::BitOr:
+ value = m_value | other.m_value;
+ break;
+ case Token::BitXor:
+ value = m_value ^ other.m_value;
+ break;
+ case Token::BitAnd:
+ value = m_value & other.m_value;
+ break;
+ case Token::Add:
+ value = m_value + other.m_value;
+ break;
+ case Token::Sub:
+ value = m_value - other.m_value;
+ break;
+ case Token::Mul:
+ value = m_value * other.m_value;
+ break;
+ case Token::Div:
+ if (other.m_value == 0)
+ return TypePointer();
+ value = m_value / other.m_value;
+ break;
+ case Token::Mod:
+ if (other.m_value == 0)
+ return TypePointer();
+ value = m_value % other.m_value;
+ break;
+ case Token::Exp:
+ if (other.m_value < 0)
+ return TypePointer();
+ else if (other.m_value > std::numeric_limits<unsigned int>::max())
+ return TypePointer();
+ else
+ value = boost::multiprecision::pow(m_value, other.m_value.convert_to<unsigned int>());
+ break;
+ default:
+ return TypePointer();
+ }
+ return make_shared<IntegerConstantType>(value);
+ }
+}
+
+bool IntegerConstantType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ return m_value == dynamic_cast<IntegerConstantType const&>(_other).m_value;
+}
+
+string IntegerConstantType::toString(bool) const
+{
+ return "int_const " + m_value.str();
+}
+
+u256 IntegerConstantType::literalValue(Literal const*) const
+{
+ u256 value;
+ // we ignore the literal and hope that the type was correctly determined
+ solAssert(m_value <= u256(-1), "Integer constant too large.");
+ solAssert(m_value >= -(bigint(1) << 255), "Integer constant too small.");
+
+ if (m_value >= 0)
+ value = u256(m_value);
+ else
+ value = s2u(s256(m_value));
+
+ return value;
+}
+
+TypePointer IntegerConstantType::mobileType() const
+{
+ auto intType = integerType();
+ solAssert(!!intType, "mobileType called with invalid integer constant " + toString(false));
+ return intType;
+}
+
+shared_ptr<IntegerType const> IntegerConstantType::integerType() const
+{
+ bigint value = m_value;
+ bool negative = (value < 0);
+ if (negative) // convert to positive number of same bit requirements
+ value = ((-value) - 1) << 1;
+ if (value > u256(-1))
+ return shared_ptr<IntegerType const>();
+ else
+ return make_shared<IntegerType>(
+ max(bytesRequired(value), 1u) * 8,
+ negative ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned
+ );
+}
+
+StringLiteralType::StringLiteralType(Literal const& _literal):
+ m_value(_literal.value())
+{
+}
+
+bool StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
+ return size_t(fixedBytes->numBytes()) >= m_value.size();
+ else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo))
+ return
+ arrayType->isByteArray() &&
+ !(arrayType->dataStoredIn(DataLocation::Storage) && arrayType->isPointer());
+ else
+ return false;
+}
+
+bool StringLiteralType::operator==(const Type& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ return m_value == dynamic_cast<StringLiteralType const&>(_other).m_value;
+}
+
+TypePointer StringLiteralType::mobileType() const
+{
+ return make_shared<ArrayType>(DataLocation::Memory, true);
+}
+
+shared_ptr<FixedBytesType> FixedBytesType::smallestTypeForLiteral(string const& _literal)
+{
+ if (_literal.length() <= 32)
+ return make_shared<FixedBytesType>(_literal.length());
+ return shared_ptr<FixedBytesType>();
+}
+
+FixedBytesType::FixedBytesType(int _bytes): m_bytes(_bytes)
+{
+ solAssert(m_bytes >= 0 && m_bytes <= 32,
+ "Invalid byte number for fixed bytes type: " + dev::toString(m_bytes));
+}
+
+bool FixedBytesType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ if (_convertTo.category() != category())
+ return false;
+ FixedBytesType const& convertTo = dynamic_cast<FixedBytesType const&>(_convertTo);
+ return convertTo.m_bytes >= m_bytes;
+}
+
+bool FixedBytesType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ return _convertTo.category() == Category::Integer ||
+ _convertTo.category() == Category::Contract ||
+ _convertTo.category() == category();
+}
+
+TypePointer FixedBytesType::unaryOperatorResult(Token::Value _operator) const
+{
+ // "delete" and "~" is okay for FixedBytesType
+ if (_operator == Token::Delete)
+ return make_shared<TupleType>();
+ else if (_operator == Token::BitNot)
+ return shared_from_this();
+
+ return TypePointer();
+}
+
+TypePointer FixedBytesType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+{
+ auto commonType = dynamic_pointer_cast<FixedBytesType const>(Type::commonType(shared_from_this(), _other));
+ if (!commonType)
+ return TypePointer();
+
+ // FixedBytes can be compared and have bitwise operators applied to them
+ if (Token::isCompareOp(_operator) || Token::isBitOp(_operator))
+ return commonType;
+
+ return TypePointer();
+}
+
+bool FixedBytesType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ FixedBytesType const& other = dynamic_cast<FixedBytesType const&>(_other);
+ return other.m_bytes == m_bytes;
+}
+
+bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ // conversion to integer is fine, but not to address
+ // this is an example of explicit conversions being not transitive (though implicit should be)
+ if (_convertTo.category() == category())
+ {
+ IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
+ if (!convertTo.isAddress())
+ return true;
+ }
+ return isImplicitlyConvertibleTo(_convertTo);
+}
+
+u256 BoolType::literalValue(Literal const* _literal) const
+{
+ solAssert(_literal, "");
+ if (_literal->token() == Token::TrueLiteral)
+ return u256(1);
+ else if (_literal->token() == Token::FalseLiteral)
+ return u256(0);
+ else
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Bool type constructed from non-boolean literal."));
+}
+
+TypePointer BoolType::unaryOperatorResult(Token::Value _operator) const
+{
+ if (_operator == Token::Delete)
+ return make_shared<TupleType>();
+ return (_operator == Token::Not) ? shared_from_this() : TypePointer();
+}
+
+TypePointer BoolType::binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+{
+ if (category() != _other->category())
+ return TypePointer();
+ if (Token::isCompareOp(_operator) || _operator == Token::And || _operator == Token::Or)
+ return _other;
+ else
+ return TypePointer();
+}
+
+bool ContractType::isImplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ if (*this == _convertTo)
+ return true;
+ if (_convertTo.category() == Category::Integer)
+ return dynamic_cast<IntegerType const&>(_convertTo).isAddress();
+ if (_convertTo.category() == Category::Contract)
+ {
+ auto const& bases = contractDefinition().annotation().linearizedBaseContracts;
+ if (m_super && bases.size() <= 1)
+ return false;
+ return find(m_super ? ++bases.begin() : bases.begin(), bases.end(),
+ &dynamic_cast<ContractType const&>(_convertTo).contractDefinition()) != bases.end();
+ }
+ return false;
+}
+
+bool ContractType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ return
+ isImplicitlyConvertibleTo(_convertTo) ||
+ _convertTo.category() == Category::Integer ||
+ _convertTo.category() == Category::Contract;
+}
+
+TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const
+{
+ return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
+}
+
+TypePointer ReferenceType::unaryOperatorResult(Token::Value _operator) const
+{
+ if (_operator != Token::Delete)
+ return TypePointer();
+ // delete can be used on everything except calldata references or storage pointers
+ // (storage references are ok)
+ switch (location())
+ {
+ case DataLocation::CallData:
+ return TypePointer();
+ case DataLocation::Memory:
+ return make_shared<TupleType>();
+ case DataLocation::Storage:
+ return m_isPointer ? TypePointer() : make_shared<TupleType>();
+ default:
+ solAssert(false, "");
+ }
+ return TypePointer();
+}
+
+TypePointer ReferenceType::copyForLocationIfReference(DataLocation _location, TypePointer const& _type)
+{
+ if (auto type = dynamic_cast<ReferenceType const*>(_type.get()))
+ return type->copyForLocation(_location, false);
+ return _type;
+}
+
+TypePointer ReferenceType::copyForLocationIfReference(TypePointer const& _type) const
+{
+ return copyForLocationIfReference(m_location, _type);
+}
+
+string ReferenceType::stringForReferencePart() const
+{
+ switch (m_location)
+ {
+ case DataLocation::Storage:
+ return string("storage ") + (m_isPointer ? "pointer" : "ref");
+ case DataLocation::CallData:
+ return "calldata";
+ case DataLocation::Memory:
+ return "memory";
+ }
+ solAssert(false, "");
+ return "";
+}
+
+bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
+{
+ if (_convertTo.category() != category())
+ return false;
+ auto& convertTo = dynamic_cast<ArrayType const&>(_convertTo);
+ if (convertTo.isByteArray() != isByteArray() || convertTo.isString() != isString())
+ return false;
+ // memory/calldata to storage can be converted, but only to a direct storage reference
+ if (convertTo.location() == DataLocation::Storage && location() != DataLocation::Storage && convertTo.isPointer())
+ return false;
+ if (convertTo.location() == DataLocation::CallData && location() != convertTo.location())
+ return false;
+ if (convertTo.location() == DataLocation::Storage && !convertTo.isPointer())
+ {
+ // Less restrictive conversion, since we need to copy anyway.
+ if (!baseType()->isImplicitlyConvertibleTo(*convertTo.baseType()))
+ return false;
+ if (convertTo.isDynamicallySized())
+ return true;
+ return !isDynamicallySized() && convertTo.length() >= length();
+ }
+ else
+ {
+ // Conversion to storage pointer or to memory, we de not copy element-for-element here, so
+ // require that the base type is the same, not only convertible.
+ // This disallows assignment of nested dynamic arrays from storage to memory for now.
+ if (
+ *copyForLocationIfReference(location(), baseType()) !=
+ *copyForLocationIfReference(location(), convertTo.baseType())
+ )
+ return false;
+ if (isDynamicallySized() != convertTo.isDynamicallySized())
+ return false;
+ // We also require that the size is the same.
+ if (!isDynamicallySized() && length() != convertTo.length())
+ return false;
+ return true;
+ }
+}
+
+bool ArrayType::isExplicitlyConvertibleTo(const Type& _convertTo) const
+{
+ if (isImplicitlyConvertibleTo(_convertTo))
+ return true;
+ // allow conversion bytes <-> string
+ if (_convertTo.category() != category())
+ return false;
+ auto& convertTo = dynamic_cast<ArrayType const&>(_convertTo);
+ if (convertTo.location() != location())
+ return false;
+ if (!isByteArray() || !convertTo.isByteArray())
+ return false;
+ return true;
+}
+
+bool ArrayType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ ArrayType const& other = dynamic_cast<ArrayType const&>(_other);
+ if (
+ !ReferenceType::operator==(other) ||
+ other.isByteArray() != isByteArray() ||
+ other.isString() != isString() ||
+ other.isDynamicallySized() != isDynamicallySized()
+ )
+ return false;
+ return isDynamicallySized() || length() == other.length();
+}
+
+unsigned ArrayType::calldataEncodedSize(bool _padded) const
+{
+ if (isDynamicallySized())
+ return 0;
+ bigint size = bigint(length()) * (isByteArray() ? 1 : baseType()->calldataEncodedSize(_padded));
+ size = ((size + 31) / 32) * 32;
+ solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned.");
+ return unsigned(size);
+}
+
+u256 ArrayType::storageSize() const
+{
+ if (isDynamicallySized())
+ return 1;
+
+ bigint size;
+ unsigned baseBytes = baseType()->storageBytes();
+ if (baseBytes == 0)
+ size = 1;
+ else if (baseBytes < 32)
+ {
+ unsigned itemsPerSlot = 32 / baseBytes;
+ size = (bigint(length()) + (itemsPerSlot - 1)) / itemsPerSlot;
+ }
+ else
+ size = bigint(length()) * baseType()->storageSize();
+ if (size >= bigint(1) << 256)
+ BOOST_THROW_EXCEPTION(Error(Error::Type::TypeError) << errinfo_comment("Array too large for storage."));
+ return max<u256>(1, u256(size));
+}
+
+unsigned ArrayType::sizeOnStack() const
+{
+ if (m_location == DataLocation::CallData)
+ // offset [length] (stack top)
+ return 1 + (isDynamicallySized() ? 1 : 0);
+ else
+ // storage slot or memory offset
+ // byte offset inside storage value is omitted
+ return 1;
+}
+
+string ArrayType::toString(bool _short) const
+{
+ string ret;
+ if (isString())
+ ret = "string";
+ else if (isByteArray())
+ ret = "bytes";
+ else
+ {
+ ret = baseType()->toString(_short) + "[";
+ if (!isDynamicallySized())
+ ret += length().str();
+ ret += "]";
+ }
+ if (!_short)
+ ret += " " + stringForReferencePart();
+ return ret;
+}
+
+string ArrayType::canonicalName(bool _addDataLocation) const
+{
+ string ret;
+ if (isString())
+ ret = "string";
+ else if (isByteArray())
+ ret = "bytes";
+ else
+ {
+ ret = baseType()->canonicalName(false) + "[";
+ if (!isDynamicallySized())
+ ret += length().str();
+ ret += "]";
+ }
+ if (_addDataLocation && location() == DataLocation::Storage)
+ ret += " storage";
+ return ret;
+}
+
+MemberList const& ArrayType::members() const
+{
+ if (!m_members)
+ {
+ MemberList::MemberMap members;
+ if (!isString())
+ {
+ members.push_back({"length", make_shared<IntegerType>(256)});
+ if (isDynamicallySized() && location() == DataLocation::Storage)
+ members.push_back({"push", make_shared<FunctionType>(
+ TypePointers{baseType()},
+ TypePointers{make_shared<IntegerType>(256)},
+ strings{string()},
+ strings{string()},
+ isByteArray() ? FunctionType::Location::ByteArrayPush : FunctionType::Location::ArrayPush
+ )});
+ }
+ m_members.reset(new MemberList(members));
+ }
+ return *m_members;
+}
+
+TypePointer ArrayType::encodingType() const
+{
+ if (location() == DataLocation::Storage)
+ return make_shared<IntegerType>(256);
+ else
+ return this->copyForLocation(DataLocation::Memory, true);
+}
+
+TypePointer ArrayType::decodingType() const
+{
+ if (location() == DataLocation::Storage)
+ return make_shared<IntegerType>(256);
+ else
+ return shared_from_this();
+}
+
+TypePointer ArrayType::interfaceType(bool _inLibrary) const
+{
+ if (_inLibrary && location() == DataLocation::Storage)
+ return shared_from_this();
+
+ if (m_arrayKind != ArrayKind::Ordinary)
+ return this->copyForLocation(DataLocation::Memory, true);
+ TypePointer baseExt = m_baseType->interfaceType(_inLibrary);
+ if (!baseExt)
+ return TypePointer();
+ if (m_baseType->category() == Category::Array && m_baseType->isDynamicallySized())
+ return TypePointer();
+
+ if (isDynamicallySized())
+ return std::make_shared<ArrayType>(DataLocation::Memory, baseExt);
+ else
+ return std::make_shared<ArrayType>(DataLocation::Memory, baseExt, m_length);
+}
+
+u256 ArrayType::memorySize() const
+{
+ solAssert(!isDynamicallySized(), "");
+ solAssert(m_location == DataLocation::Memory, "");
+ bigint size = bigint(m_length) * m_baseType->memoryHeadSize();
+ solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit u256.");
+ return u256(size);
+}
+
+TypePointer ArrayType::copyForLocation(DataLocation _location, bool _isPointer) const
+{
+ auto copy = make_shared<ArrayType>(_location);
+ copy->m_isPointer = _isPointer;
+ copy->m_arrayKind = m_arrayKind;
+ copy->m_baseType = copy->copyForLocationIfReference(m_baseType);
+ copy->m_hasDynamicLength = m_hasDynamicLength;
+ copy->m_length = m_length;
+ return copy;
+}
+
+bool ContractType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ ContractType const& other = dynamic_cast<ContractType const&>(_other);
+ return other.m_contract == m_contract && other.m_super == m_super;
+}
+
+string ContractType::toString(bool) const
+{
+ return
+ string(m_contract.isLibrary() ? "library " : "contract ") +
+ string(m_super ? "super " : "") +
+ m_contract.name();
+}
+
+string ContractType::canonicalName(bool) const
+{
+ return m_contract.annotation().canonicalName;
+}
+
+MemberList const& ContractType::members() const
+{
+ // We need to lazy-initialize it because of recursive references.
+ if (!m_members)
+ {
+ // All address members and all interface functions
+ MemberList::MemberMap members(
+ IntegerType::AddressMemberList.begin(),
+ IntegerType::AddressMemberList.end()
+ );
+ if (m_super)
+ {
+ // add the most derived of all functions which are visible in derived contracts
+ for (ContractDefinition const* base: m_contract.annotation().linearizedBaseContracts)
+ for (ASTPointer<FunctionDefinition> const& function: base->definedFunctions())
+ {
+ if (!function->isVisibleInDerivedContracts())
+ continue;
+ auto functionType = make_shared<FunctionType>(*function, true);
+ bool functionWithEqualArgumentsFound = false;
+ for (auto const& member: members)
+ {
+ if (member.name != function->name())
+ continue;
+ auto memberType = dynamic_cast<FunctionType const*>(member.type.get());
+ solAssert(!!memberType, "Override changes type.");
+ if (!memberType->hasEqualArgumentTypes(*functionType))
+ continue;
+ functionWithEqualArgumentsFound = true;
+ break;
+ }
+ if (!functionWithEqualArgumentsFound)
+ members.push_back(MemberList::Member(
+ function->name(),
+ functionType,
+ function.get()
+ ));
+ }
+ }
+ else
+ for (auto const& it: m_contract.interfaceFunctions())
+ members.push_back(MemberList::Member(
+ it.second->declaration().name(),
+ it.second->asMemberFunction(m_contract.isLibrary()),
+ &it.second->declaration()
+ ));
+ m_members.reset(new MemberList(members));
+ }
+ return *m_members;
+}
+
+shared_ptr<FunctionType const> const& ContractType::constructorType() const
+{
+ if (!m_constructorType)
+ {
+ FunctionDefinition const* constructor = m_contract.constructor();
+ if (constructor)
+ m_constructorType = make_shared<FunctionType>(*constructor);
+ else
+ m_constructorType = make_shared<FunctionType>(TypePointers(), TypePointers());
+ }
+ return m_constructorType;
+}
+
+vector<tuple<VariableDeclaration const*, u256, unsigned>> ContractType::stateVariables() const
+{
+ vector<VariableDeclaration const*> variables;
+ for (ContractDefinition const* contract: boost::adaptors::reverse(m_contract.annotation().linearizedBaseContracts))
+ for (ASTPointer<VariableDeclaration> const& variable: contract->stateVariables())
+ if (!variable->isConstant())
+ variables.push_back(variable.get());
+ TypePointers types;
+ for (auto variable: variables)
+ types.push_back(variable->annotation().type);
+ StorageOffsets offsets;
+ offsets.computeOffsets(types);
+
+ vector<tuple<VariableDeclaration const*, u256, unsigned>> variablesAndOffsets;
+ for (size_t index = 0; index < variables.size(); ++index)
+ if (auto const* offset = offsets.offset(index))
+ variablesAndOffsets.push_back(make_tuple(variables[index], offset->first, offset->second));
+ return variablesAndOffsets;
+}
+
+bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const
+{
+ if (_convertTo.category() != category())
+ return false;
+ auto& convertTo = dynamic_cast<StructType const&>(_convertTo);
+ // memory/calldata to storage can be converted, but only to a direct storage reference
+ if (convertTo.location() == DataLocation::Storage && location() != DataLocation::Storage && convertTo.isPointer())
+ return false;
+ if (convertTo.location() == DataLocation::CallData && location() != convertTo.location())
+ return false;
+ return this->m_struct == convertTo.m_struct;
+}
+
+bool StructType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ StructType const& other = dynamic_cast<StructType const&>(_other);
+ return ReferenceType::operator==(other) && other.m_struct == m_struct;
+}
+
+unsigned StructType::calldataEncodedSize(bool _padded) const
+{
+ unsigned size = 0;
+ for (auto const& member: members())
+ if (!member.type->canLiveOutsideStorage())
+ return 0;
+ else
+ {
+ unsigned memberSize = member.type->calldataEncodedSize(_padded);
+ if (memberSize == 0)
+ return 0;
+ size += memberSize;
+ }
+ return size;
+}
+
+u256 StructType::memorySize() const
+{
+ u256 size;
+ for (auto const& member: members())
+ if (member.type->canLiveOutsideStorage())
+ size += member.type->memoryHeadSize();
+ return size;
+}
+
+u256 StructType::storageSize() const
+{
+ return max<u256>(1, members().storageSize());
+}
+
+string StructType::toString(bool _short) const
+{
+ string ret = "struct " + m_struct.name();
+ if (!_short)
+ ret += " " + stringForReferencePart();
+ return ret;
+}
+
+MemberList const& StructType::members() const
+{
+ // We need to lazy-initialize it because of recursive references.
+ if (!m_members)
+ {
+ MemberList::MemberMap members;
+ for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
+ {
+ TypePointer type = variable->annotation().type;
+ // Skip all mapping members if we are not in storage.
+ if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
+ continue;
+ members.push_back(MemberList::Member(
+ variable->name(),
+ copyForLocationIfReference(type),
+ variable.get())
+ );
+ }
+ m_members.reset(new MemberList(members));
+ }
+ return *m_members;
+}
+
+TypePointer StructType::interfaceType(bool _inLibrary) const
+{
+ if (_inLibrary && location() == DataLocation::Storage)
+ return shared_from_this();
+ else
+ return TypePointer();
+}
+
+TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const
+{
+ auto copy = make_shared<StructType>(m_struct, _location);
+ copy->m_isPointer = _isPointer;
+ return copy;
+}
+
+string StructType::canonicalName(bool _addDataLocation) const
+{
+ string ret = m_struct.annotation().canonicalName;
+ if (_addDataLocation && location() == DataLocation::Storage)
+ ret += " storage";
+ return ret;
+}
+
+FunctionTypePointer StructType::constructorType() const
+{
+ TypePointers paramTypes;
+ strings paramNames;
+ for (auto const& member: members())
+ {
+ if (!member.type->canLiveOutsideStorage())
+ continue;
+ paramNames.push_back(member.name);
+ paramTypes.push_back(copyForLocationIfReference(DataLocation::Memory, member.type));
+ }
+ return make_shared<FunctionType>(
+ paramTypes,
+ TypePointers{copyForLocation(DataLocation::Memory, false)},
+ paramNames,
+ strings(),
+ FunctionType::Location::Internal
+ );
+}
+
+pair<u256, unsigned> const& StructType::storageOffsetsOfMember(string const& _name) const
+{
+ auto const* offsets = members().memberStorageOffset(_name);
+ solAssert(offsets, "Storage offset of non-existing member requested.");
+ return *offsets;
+}
+
+u256 StructType::memoryOffsetOfMember(string const& _name) const
+{
+ u256 offset;
+ for (auto const& member: members())
+ if (member.name == _name)
+ return offset;
+ else
+ offset += member.type->memoryHeadSize();
+ solAssert(false, "Member not found in struct.");
+ return 0;
+}
+
+set<string> StructType::membersMissingInMemory() const
+{
+ set<string> missing;
+ for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
+ if (!variable->annotation().type->canLiveOutsideStorage())
+ missing.insert(variable->name());
+ return missing;
+}
+
+TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const
+{
+ return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
+}
+
+bool EnumType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ EnumType const& other = dynamic_cast<EnumType const&>(_other);
+ return other.m_enum == m_enum;
+}
+
+unsigned EnumType::storageBytes() const
+{
+ size_t elements = m_enum.members().size();
+ if (elements <= 1)
+ return 1;
+ else
+ return dev::bytesRequired(elements - 1);
+}
+
+string EnumType::toString(bool) const
+{
+ return string("enum ") + m_enum.name();
+}
+
+string EnumType::canonicalName(bool) const
+{
+ return m_enum.annotation().canonicalName;
+}
+
+bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const
+{
+ return _convertTo.category() == category() || _convertTo.category() == Category::Integer;
+}
+
+unsigned int EnumType::memberValue(ASTString const& _member) const
+{
+ unsigned int index = 0;
+ for (ASTPointer<EnumValue> const& decl: m_enum.members())
+ {
+ if (decl->name() == _member)
+ return index;
+ ++index;
+ }
+ BOOST_THROW_EXCEPTION(m_enum.createTypeError("Requested unknown enum value ." + _member));
+}
+
+bool TupleType::isImplicitlyConvertibleTo(Type const& _other) const
+{
+ if (auto tupleType = dynamic_cast<TupleType const*>(&_other))
+ {
+ TypePointers const& targets = tupleType->components();
+ if (targets.empty())
+ return components().empty();
+ if (components().size() != targets.size() && !targets.front() && !targets.back())
+ return false; // (,a,) = (1,2,3,4) - unable to position `a` in the tuple.
+ size_t minNumValues = targets.size();
+ if (!targets.back() || !targets.front())
+ --minNumValues; // wildcards can also match 0 components
+ if (components().size() < minNumValues)
+ return false;
+ if (components().size() > targets.size() && targets.front() && targets.back())
+ return false; // larger source and no wildcard
+ bool fillRight = !targets.back() || targets.front();
+ for (size_t i = 0; i < min(targets.size(), components().size()); ++i)
+ {
+ auto const& s = components()[fillRight ? i : components().size() - i - 1];
+ auto const& t = targets[fillRight ? i : targets.size() - i - 1];
+ if (!s && t)
+ return false;
+ else if (s && t && !s->isImplicitlyConvertibleTo(*t))
+ return false;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+bool TupleType::operator==(Type const& _other) const
+{
+ if (auto tupleType = dynamic_cast<TupleType const*>(&_other))
+ return components() == tupleType->components();
+ else
+ return false;
+}
+
+string TupleType::toString(bool _short) const
+{
+ if (components().empty())
+ return "tuple()";
+ string str = "tuple(";
+ for (auto const& t: components())
+ str += (t ? t->toString(_short) : "") + ",";
+ str.pop_back();
+ return str + ")";
+}
+
+u256 TupleType::storageSize() const
+{
+ BOOST_THROW_EXCEPTION(
+ InternalCompilerError() <<
+ errinfo_comment("Storage size of non-storable tuple type requested.")
+ );
+}
+
+unsigned TupleType::sizeOnStack() const
+{
+ unsigned size = 0;
+ for (auto const& t: components())
+ size += t ? t->sizeOnStack() : 0;
+ return size;
+}
+
+TypePointer TupleType::mobileType() const
+{
+ TypePointers mobiles;
+ for (auto const& c: components())
+ mobiles.push_back(c ? c->mobileType() : TypePointer());
+ return make_shared<TupleType>(mobiles);
+}
+
+TypePointer TupleType::closestTemporaryType(TypePointer const& _targetType) const
+{
+ solAssert(!!_targetType, "");
+ TypePointers const& targetComponents = dynamic_cast<TupleType const&>(*_targetType).components();
+ bool fillRight = !targetComponents.empty() && (!targetComponents.back() || targetComponents.front());
+ TypePointers tempComponents(targetComponents.size());
+ for (size_t i = 0; i < min(targetComponents.size(), components().size()); ++i)
+ {
+ size_t si = fillRight ? i : components().size() - i - 1;
+ size_t ti = fillRight ? i : targetComponents.size() - i - 1;
+ if (components()[si] && targetComponents[ti])
+ tempComponents[ti] = components()[si]->closestTemporaryType(targetComponents[ti]);
+ }
+ return make_shared<TupleType>(tempComponents);
+}
+
+FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal):
+ m_location(_isInternal ? Location::Internal : Location::External),
+ m_isConstant(_function.isDeclaredConst()),
+ m_declaration(&_function)
+{
+ TypePointers params;
+ vector<string> paramNames;
+ TypePointers retParams;
+ vector<string> retParamNames;
+
+ params.reserve(_function.parameters().size());
+ paramNames.reserve(_function.parameters().size());
+ for (ASTPointer<VariableDeclaration> const& var: _function.parameters())
+ {
+ paramNames.push_back(var->name());
+ params.push_back(var->annotation().type);
+ }
+ retParams.reserve(_function.returnParameters().size());
+ retParamNames.reserve(_function.returnParameters().size());
+ for (ASTPointer<VariableDeclaration> const& var: _function.returnParameters())
+ {
+ retParamNames.push_back(var->name());
+ retParams.push_back(var->annotation().type);
+ }
+ swap(params, m_parameterTypes);
+ swap(paramNames, m_parameterNames);
+ swap(retParams, m_returnParameterTypes);
+ swap(retParamNames, m_returnParameterNames);
+}
+
+FunctionType::FunctionType(VariableDeclaration const& _varDecl):
+ m_location(Location::External), m_isConstant(true), m_declaration(&_varDecl)
+{
+ TypePointers paramTypes;
+ vector<string> paramNames;
+ auto returnType = _varDecl.annotation().type;
+
+ while (true)
+ {
+ if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
+ {
+ paramTypes.push_back(mappingType->keyType());
+ paramNames.push_back("");
+ returnType = mappingType->valueType();
+ }
+ else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
+ {
+ if (arrayType->isByteArray())
+ // Return byte arrays as as whole.
+ break;
+ returnType = arrayType->baseType();
+ paramNames.push_back("");
+ paramTypes.push_back(make_shared<IntegerType>(256));
+ }
+ else
+ break;
+ }
+
+ TypePointers retParams;
+ vector<string> retParamNames;
+ if (auto structType = dynamic_cast<StructType const*>(returnType.get()))
+ {
+ for (auto const& member: structType->members())
+ if (member.type->category() != Category::Mapping)
+ {
+ if (auto arrayType = dynamic_cast<ArrayType const*>(member.type.get()))
+ if (!arrayType->isByteArray())
+ continue;
+ retParams.push_back(member.type);
+ retParamNames.push_back(member.name);
+ }
+ }
+ else
+ {
+ retParams.push_back(ReferenceType::copyForLocationIfReference(
+ DataLocation::Memory,
+ returnType
+ ));
+ retParamNames.push_back("");
+ }
+
+ swap(paramTypes, m_parameterTypes);
+ swap(paramNames, m_parameterNames);
+ swap(retParams, m_returnParameterTypes);
+ swap(retParamNames, m_returnParameterNames);
+}
+
+FunctionType::FunctionType(const EventDefinition& _event):
+ m_location(Location::Event), m_isConstant(true), m_declaration(&_event)
+{
+ TypePointers params;
+ vector<string> paramNames;
+ params.reserve(_event.parameters().size());
+ paramNames.reserve(_event.parameters().size());
+ for (ASTPointer<VariableDeclaration> const& var: _event.parameters())
+ {
+ paramNames.push_back(var->name());
+ params.push_back(var->annotation().type);
+ }
+ swap(params, m_parameterTypes);
+ swap(paramNames, m_parameterNames);
+}
+
+bool FunctionType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ FunctionType const& other = dynamic_cast<FunctionType const&>(_other);
+
+ if (m_location != other.m_location)
+ return false;
+ if (m_isConstant != other.isConstant())
+ return false;
+
+ if (m_parameterTypes.size() != other.m_parameterTypes.size() ||
+ m_returnParameterTypes.size() != other.m_returnParameterTypes.size())
+ return false;
+ auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; };
+
+ if (!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(),
+ other.m_parameterTypes.cbegin(), typeCompare))
+ return false;
+ if (!equal(m_returnParameterTypes.cbegin(), m_returnParameterTypes.cend(),
+ other.m_returnParameterTypes.cbegin(), typeCompare))
+ return false;
+ //@todo this is ugly, but cannot be prevented right now
+ if (m_gasSet != other.m_gasSet || m_valueSet != other.m_valueSet)
+ return false;
+ return true;
+}
+
+string FunctionType::toString(bool _short) const
+{
+ string name = "function (";
+ for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
+ name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
+ name += ") returns (";
+ for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it)
+ name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ",");
+ return name + ")";
+}
+
+u256 FunctionType::storageSize() const
+{
+ BOOST_THROW_EXCEPTION(
+ InternalCompilerError()
+ << errinfo_comment("Storage size of non-storable function type requested."));
+}
+
+unsigned FunctionType::sizeOnStack() const
+{
+ Location location = m_location;
+ if (m_location == Location::SetGas || m_location == Location::SetValue)
+ {
+ solAssert(m_returnParameterTypes.size() == 1, "");
+ location = dynamic_cast<FunctionType const&>(*m_returnParameterTypes.front()).m_location;
+ }
+
+ unsigned size = 0;
+ if (location == Location::External || location == Location::CallCode)
+ size = 2;
+ else if (location == Location::Bare || location == Location::BareCallCode)
+ size = 1;
+ else if (location == Location::Internal)
+ size = 1;
+ else if (location == Location::ArrayPush || location == Location::ByteArrayPush)
+ size = 1;
+ if (m_gasSet)
+ size++;
+ if (m_valueSet)
+ size++;
+ return size;
+}
+
+FunctionTypePointer FunctionType::interfaceFunctionType() const
+{
+ // Note that m_declaration might also be a state variable!
+ solAssert(m_declaration, "Declaration needed to determine interface function type.");
+ bool isLibraryFunction = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
+
+ TypePointers paramTypes;
+ TypePointers retParamTypes;
+
+ for (auto type: m_parameterTypes)
+ {
+ if (auto ext = type->interfaceType(isLibraryFunction))
+ paramTypes.push_back(ext);
+ else
+ return FunctionTypePointer();
+ }
+ for (auto type: m_returnParameterTypes)
+ {
+ if (auto ext = type->interfaceType(isLibraryFunction))
+ retParamTypes.push_back(ext);
+ else
+ return FunctionTypePointer();
+ }
+ return make_shared<FunctionType>(paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_location, m_arbitraryParameters);
+}
+
+MemberList const& FunctionType::members() const
+{
+ switch (m_location)
+ {
+ case Location::External:
+ case Location::Creation:
+ case Location::ECRecover:
+ case Location::SHA256:
+ case Location::RIPEMD160:
+ case Location::Bare:
+ case Location::BareCallCode:
+ if (!m_members)
+ {
+ MemberList::MemberMap members{
+ {
+ "value",
+ make_shared<FunctionType>(
+ parseElementaryTypeVector({"uint"}),
+ TypePointers{copyAndSetGasOrValue(false, true)},
+ strings(),
+ strings(),
+ Location::SetValue,
+ false,
+ nullptr,
+ m_gasSet,
+ m_valueSet
+ )
+ }
+ };
+ if (m_location != Location::Creation)
+ members.push_back(
+ MemberList::Member(
+ "gas",
+ make_shared<FunctionType>(
+ parseElementaryTypeVector({"uint"}),
+ TypePointers{copyAndSetGasOrValue(true, false)},
+ strings(),
+ strings(),
+ Location::SetGas,
+ false,
+ nullptr,
+ m_gasSet,
+ m_valueSet
+ )
+ )
+ );
+ m_members.reset(new MemberList(members));
+ }
+ return *m_members;
+ default:
+ return EmptyMemberList;
+ }
+}
+
+bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes) const
+{
+ TypePointers const& paramTypes = parameterTypes();
+ if (takesArbitraryParameters())
+ return true;
+ else if (_argumentTypes.size() != paramTypes.size())
+ return false;
+ else
+ return std::equal(
+ _argumentTypes.cbegin(),
+ _argumentTypes.cend(),
+ paramTypes.cbegin(),
+ [](TypePointer const& argumentType, TypePointer const& parameterType)
+ {
+ return argumentType->isImplicitlyConvertibleTo(*parameterType);
+ }
+ );
+}
+
+bool FunctionType::hasEqualArgumentTypes(FunctionType const& _other) const
+{
+ if (m_parameterTypes.size() != _other.m_parameterTypes.size())
+ return false;
+ return equal(
+ m_parameterTypes.cbegin(),
+ m_parameterTypes.cend(),
+ _other.m_parameterTypes.cbegin(),
+ [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; }
+ );
+}
+
+bool FunctionType::isBareCall() const
+{
+ switch (m_location)
+ {
+ case Location::Bare:
+ case Location::BareCallCode:
+ case Location::ECRecover:
+ case Location::SHA256:
+ case Location::RIPEMD160:
+ return true;
+ default:
+ return false;
+ }
+}
+
+string FunctionType::externalSignature() const
+{
+ solAssert(m_declaration != nullptr, "External signature of function needs declaration");
+
+ bool _inLibrary = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
+
+ string ret = m_declaration->name() + "(";
+
+ FunctionTypePointer external = interfaceFunctionType();
+ solAssert(!!external, "External function type requested.");
+ TypePointers externalParameterTypes = external->parameterTypes();
+ for (auto it = externalParameterTypes.cbegin(); it != externalParameterTypes.cend(); ++it)
+ {
+ solAssert(!!(*it), "Parameter should have external type");
+ ret += (*it)->canonicalName(_inLibrary) + (it + 1 == externalParameterTypes.cend() ? "" : ",");
+ }
+
+ return ret + ")";
+}
+
+u256 FunctionType::externalIdentifier() const
+{
+ return FixedHash<4>::Arith(FixedHash<4>(dev::sha3(externalSignature())));
+}
+
+TypePointers FunctionType::parseElementaryTypeVector(strings const& _types)
+{
+ TypePointers pointers;
+ pointers.reserve(_types.size());
+ for (string const& type: _types)
+ pointers.push_back(Type::fromElementaryTypeName(type));
+ return pointers;
+}
+
+TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) const
+{
+ return make_shared<FunctionType>(
+ m_parameterTypes,
+ m_returnParameterTypes,
+ m_parameterNames,
+ m_returnParameterNames,
+ m_location,
+ m_arbitraryParameters,
+ m_declaration,
+ m_gasSet || _setGas,
+ m_valueSet || _setValue
+ );
+}
+
+FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary) const
+{
+ TypePointers parameterTypes;
+ for (auto const& t: m_parameterTypes)
+ {
+ auto refType = dynamic_cast<ReferenceType const*>(t.get());
+ if (refType && refType->location() == DataLocation::CallData)
+ parameterTypes.push_back(refType->copyForLocation(DataLocation::Memory, false));
+ else
+ parameterTypes.push_back(t);
+ }
+
+ // Removes dynamic types.
+ TypePointers returnParameterTypes;
+ vector<string> returnParameterNames;
+ for (size_t i = 0; i < m_returnParameterTypes.size(); ++i)
+ if (m_returnParameterTypes[i]->calldataEncodedSize() > 0)
+ {
+ returnParameterTypes.push_back(m_returnParameterTypes[i]);
+ returnParameterNames.push_back(m_returnParameterNames[i]);
+ }
+ return make_shared<FunctionType>(
+ parameterTypes,
+ returnParameterTypes,
+ m_parameterNames,
+ returnParameterNames,
+ _inLibrary ? Location::CallCode : m_location,
+ m_arbitraryParameters,
+ m_declaration,
+ m_gasSet,
+ m_valueSet
+ );
+}
+
+vector<string> const FunctionType::parameterTypeNames(bool _addDataLocation) const
+{
+ vector<string> names;
+ for (TypePointer const& t: m_parameterTypes)
+ names.push_back(t->canonicalName(_addDataLocation));
+
+ return names;
+}
+
+vector<string> const FunctionType::returnParameterTypeNames(bool _addDataLocation) const
+{
+ vector<string> names;
+ for (TypePointer const& t: m_returnParameterTypes)
+ names.push_back(t->canonicalName(_addDataLocation));
+
+ return names;
+}
+
+ASTPointer<ASTString> FunctionType::documentation() const
+{
+ auto function = dynamic_cast<Documented const*>(m_declaration);
+ if (function)
+ return function->documentation();
+
+ return ASTPointer<ASTString>();
+}
+
+bool MappingType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ MappingType const& other = dynamic_cast<MappingType const&>(_other);
+ return *other.m_keyType == *m_keyType && *other.m_valueType == *m_valueType;
+}
+
+string MappingType::toString(bool _short) const
+{
+ return "mapping(" + keyType()->toString(_short) + " => " + valueType()->toString(_short) + ")";
+}
+
+string MappingType::canonicalName(bool) const
+{
+ return "mapping(" + keyType()->canonicalName(false) + " => " + valueType()->canonicalName(false) + ")";
+}
+
+bool TypeType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ TypeType const& other = dynamic_cast<TypeType const&>(_other);
+ return *actualType() == *other.actualType();
+}
+
+u256 TypeType::storageSize() const
+{
+ BOOST_THROW_EXCEPTION(
+ InternalCompilerError()
+ << errinfo_comment("Storage size of non-storable type type requested."));
+}
+
+unsigned TypeType::sizeOnStack() const
+{
+ if (auto contractType = dynamic_cast<ContractType const*>(m_actualType.get()))
+ if (contractType->contractDefinition().isLibrary())
+ return 1;
+ return 0;
+}
+
+MemberList const& TypeType::members() const
+{
+ // We need to lazy-initialize it because of recursive references.
+ if (!m_members)
+ {
+ MemberList::MemberMap members;
+ if (m_actualType->category() == Category::Contract)
+ {
+ ContractDefinition const& contract = dynamic_cast<ContractType const&>(*m_actualType).contractDefinition();
+ if (contract.isLibrary())
+ for (auto const& it: contract.interfaceFunctions())
+ members.push_back(MemberList::Member(
+ it.second->declaration().name(),
+ it.second->asMemberFunction(true), // use callcode
+ &it.second->declaration()
+ ));
+ else if (m_currentContract != nullptr)
+ {
+ auto const& currentBases = m_currentContract->annotation().linearizedBaseContracts;
+ if (find(currentBases.begin(), currentBases.end(), &contract) != currentBases.end())
+ // We are accessing the type of a base contract, so add all public and protected
+ // members. Note that this does not add inherited functions on purpose.
+ for (Declaration const* decl: contract.inheritableMembers())
+ members.push_back(MemberList::Member(decl->name(), decl->type(), decl));
+ }
+ }
+ else if (m_actualType->category() == Category::Enum)
+ {
+ EnumDefinition const& enumDef = dynamic_cast<EnumType const&>(*m_actualType).enumDefinition();
+ auto enumType = make_shared<EnumType>(enumDef);
+ for (ASTPointer<EnumValue> const& enumValue: enumDef.members())
+ members.push_back(MemberList::Member(enumValue->name(), enumType));
+ }
+ m_members.reset(new MemberList(members));
+ }
+ return *m_members;
+}
+
+ModifierType::ModifierType(const ModifierDefinition& _modifier)
+{
+ TypePointers params;
+ params.reserve(_modifier.parameters().size());
+ for (ASTPointer<VariableDeclaration> const& var: _modifier.parameters())
+ params.push_back(var->annotation().type);
+ swap(params, m_parameterTypes);
+}
+
+u256 ModifierType::storageSize() const
+{
+ BOOST_THROW_EXCEPTION(
+ InternalCompilerError()
+ << errinfo_comment("Storage size of non-storable type type requested."));
+}
+
+bool ModifierType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ ModifierType const& other = dynamic_cast<ModifierType const&>(_other);
+
+ if (m_parameterTypes.size() != other.m_parameterTypes.size())
+ return false;
+ auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; };
+
+ if (!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(),
+ other.m_parameterTypes.cbegin(), typeCompare))
+ return false;
+ return true;
+}
+
+string ModifierType::toString(bool _short) const
+{
+ string name = "modifier (";
+ for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
+ name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
+ return name + ")";
+}
+
+MagicType::MagicType(MagicType::Kind _kind):
+ m_kind(_kind)
+{
+ switch (m_kind)
+ {
+ case Kind::Block:
+ m_members = MemberList({
+ {"coinbase", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
+ {"timestamp", make_shared<IntegerType>(256)},
+ {"blockhash", make_shared<FunctionType>(strings{"uint"}, strings{"bytes32"}, FunctionType::Location::BlockHash)},
+ {"difficulty", make_shared<IntegerType>(256)},
+ {"number", make_shared<IntegerType>(256)},
+ {"gaslimit", make_shared<IntegerType>(256)}
+ });
+ break;
+ case Kind::Message:
+ m_members = MemberList({
+ {"sender", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
+ {"gas", make_shared<IntegerType>(256)},
+ {"value", make_shared<IntegerType>(256)},
+ {"data", make_shared<ArrayType>(DataLocation::CallData)},
+ {"sig", make_shared<FixedBytesType>(4)}
+ });
+ break;
+ case Kind::Transaction:
+ m_members = MemberList({
+ {"origin", make_shared<IntegerType>(0, IntegerType::Modifier::Address)},
+ {"gasprice", make_shared<IntegerType>(256)}
+ });
+ break;
+ default:
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));
+ }
+}
+
+bool MagicType::operator==(Type const& _other) const
+{
+ if (_other.category() != category())
+ return false;
+ MagicType const& other = dynamic_cast<MagicType const&>(_other);
+ return other.m_kind == m_kind;
+}
+
+string MagicType::toString(bool) const
+{
+ switch (m_kind)
+ {
+ case Kind::Block:
+ return "block";
+ case Kind::Message:
+ return "msg";
+ case Kind::Transaction:
+ return "tx";
+ default:
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic."));
+ }
+}
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
new file mode 100644
index 00000000..2f75975f
--- /dev/null
+++ b/libsolidity/ast/Types.h
@@ -0,0 +1,996 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2014
+ * Solidity data types
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <map>
+#include <boost/noncopyable.hpp>
+#include <libdevcore/Common.h>
+#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/ast/ASTForward.h>
+#include <libsolidity/parsing/Token.h>
+#include <libdevcore/UndefMacros.h>
+
+namespace dev
+{
+namespace solidity
+{
+
+class Type; // forward
+class FunctionType; // forward
+using TypePointer = std::shared_ptr<Type const>;
+using FunctionTypePointer = std::shared_ptr<FunctionType const>;
+using TypePointers = std::vector<TypePointer>;
+
+
+enum class DataLocation { Storage, CallData, Memory };
+
+/**
+ * Helper class to compute storage offsets of members of structs and contracts.
+ */
+class StorageOffsets
+{
+public:
+ /// Resets the StorageOffsets objects and determines the position in storage for each
+ /// of the elements of @a _types.
+ void computeOffsets(TypePointers const& _types);
+ /// @returns the offset of the given member, might be null if the member is not part of storage.
+ std::pair<u256, unsigned> const* offset(size_t _index) const;
+ /// @returns the total number of slots occupied by all members.
+ u256 const& storageSize() const { return m_storageSize; }
+
+private:
+ u256 m_storageSize;
+ std::map<size_t, std::pair<u256, unsigned>> m_offsets;
+};
+
+/**
+ * List of members of a type.
+ */
+class MemberList
+{
+public:
+ struct Member
+ {
+ Member(std::string const& _name, TypePointer const& _type, Declaration const* _declaration = nullptr):
+ name(_name),
+ type(_type),
+ declaration(_declaration)
+ {
+ }
+
+ std::string name;
+ TypePointer type;
+ Declaration const* declaration = nullptr;
+ };
+
+ using MemberMap = std::vector<Member>;
+
+ MemberList() {}
+ explicit MemberList(MemberMap const& _members): m_memberTypes(_members) {}
+ MemberList& operator=(MemberList&& _other);
+ TypePointer memberType(std::string const& _name) const
+ {
+ TypePointer type;
+ for (auto const& it: m_memberTypes)
+ if (it.name == _name)
+ {
+ solAssert(!type, "Requested member type by non-unique name.");
+ type = it.type;
+ }
+ return type;
+ }
+ MemberMap membersByName(std::string const& _name) const
+ {
+ MemberMap members;
+ for (auto const& it: m_memberTypes)
+ if (it.name == _name)
+ members.push_back(it);
+ return members;
+ }
+ /// @returns the offset of the given member in storage slots and bytes inside a slot or
+ /// a nullptr if the member is not part of storage.
+ std::pair<u256, unsigned> const* memberStorageOffset(std::string const& _name) const;
+ /// @returns the number of storage slots occupied by the members.
+ u256 const& storageSize() const;
+
+ MemberMap::const_iterator begin() const { return m_memberTypes.begin(); }
+ MemberMap::const_iterator end() const { return m_memberTypes.end(); }
+
+private:
+ MemberMap m_memberTypes;
+ mutable std::unique_ptr<StorageOffsets> m_storageOffsets;
+};
+
+/**
+ * Abstract base class that forms the root of the type hierarchy.
+ */
+class Type: private boost::noncopyable, public std::enable_shared_from_this<Type>
+{
+public:
+ enum class Category
+ {
+ Integer, IntegerConstant, StringLiteral, Bool, Real, Array,
+ FixedBytes, Contract, Struct, Function, Enum, Tuple,
+ Mapping, TypeType, Modifier, Magic
+ };
+
+ /// @{
+ /// @name Factory functions
+ /// Factory functions that convert an AST @ref TypeName to a Type.
+ static TypePointer fromElementaryTypeName(Token::Value _typeToken);
+ static TypePointer fromElementaryTypeName(std::string const& _name);
+ static TypePointer fromUserDefinedTypeName(UserDefinedTypeName const& _typeName);
+ static TypePointer fromMapping(ElementaryTypeName& _keyType, TypeName& _valueType);
+ static TypePointer fromArrayTypeName(TypeName& _baseTypeName, Expression* _length);
+ /// @}
+
+ /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
+ /// not fit any type.
+ static TypePointer forLiteral(Literal const& _literal);
+ /// @returns a pointer to _a or _b if the other is implicitly convertible to it or nullptr otherwise
+ static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
+
+ /// Calculates the
+
+ virtual Category category() const = 0;
+ virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const
+ {
+ return isImplicitlyConvertibleTo(_convertTo);
+ }
+ /// @returns the resulting type of applying the given unary operator or an empty pointer if
+ /// this is not possible.
+ /// The default implementation does not allow any unary operator.
+ virtual TypePointer unaryOperatorResult(Token::Value) const { return TypePointer(); }
+ /// @returns the resulting type of applying the given binary operator or an empty pointer if
+ /// this is not possible.
+ /// The default implementation allows comparison operators if a common type exists
+ virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const
+ {
+ return Token::isCompareOp(_operator) ? commonType(shared_from_this(), _other) : TypePointer();
+ }
+
+ virtual bool operator==(Type const& _other) const { return category() == _other.category(); }
+ virtual bool operator!=(Type const& _other) const { return !this->operator ==(_other); }
+
+ /// @returns number of bytes used by this type when encoded for CALL, or 0 if the encoding
+ /// is not a simple big-endian encoding or the type cannot be stored in calldata.
+ /// If @a _padded then it is assumed that each element is padded to a multiple of 32 bytes.
+ virtual unsigned calldataEncodedSize(bool _padded) const { (void)_padded; return 0; }
+ /// @returns the size of this data type in bytes when stored in memory. For memory-reference
+ /// types, this is the size of the memory pointer.
+ virtual unsigned memoryHeadSize() const { return calldataEncodedSize(); }
+ /// Convenience version of @see calldataEncodedSize(bool)
+ unsigned calldataEncodedSize() const { return calldataEncodedSize(true); }
+ /// @returns true if the type is dynamically encoded in calldata
+ virtual bool isDynamicallySized() const { return false; }
+ /// @returns the number of storage slots required to hold this value in storage.
+ /// For dynamically "allocated" types, it returns the size of the statically allocated head,
+ virtual u256 storageSize() const { return 1; }
+ /// Multiple small types can be packed into a single storage slot. If such a packing is possible
+ /// this function @returns the size in bytes smaller than 32. Data is moved to the next slot if
+ /// it does not fit.
+ /// In order to avoid computation at runtime of whether such moving is necessary, structs and
+ /// array data (not each element) always start a new slot.
+ virtual unsigned storageBytes() const { return 32; }
+ /// Returns true if the type can be stored in storage.
+ virtual bool canBeStored() const { return true; }
+ /// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
+ virtual bool canLiveOutsideStorage() const { return true; }
+ /// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
+ /// i.e. it behaves differently in lvalue context and in value context.
+ virtual bool isValueType() const { return false; }
+ virtual unsigned sizeOnStack() const { return 1; }
+ /// @returns the mobile (in contrast to static) type corresponding to the given type.
+ /// This returns the corresponding integer type for IntegerConstantTypes and the pointer type
+ /// for storage reference types.
+ virtual TypePointer mobileType() const { return shared_from_this(); }
+ /// @returns true if this is a non-value type and the data of this type is stored at the
+ /// given location.
+ virtual bool dataStoredIn(DataLocation) const { return false; }
+ /// @returns the type of a temporary during assignment to a variable of the given type.
+ /// Specifically, returns the requested itself if it can be dynamically allocated (or is a value type)
+ /// and the mobile type otherwise.
+ virtual TypePointer closestTemporaryType(TypePointer const& _targetType) const
+ {
+ return _targetType->dataStoredIn(DataLocation::Storage) ? mobileType() : _targetType;
+ }
+
+ /// Returns the list of all members of this type. Default implementation: no members.
+ virtual MemberList const& members() const { return EmptyMemberList; }
+ /// Convenience method, returns the type of the given named member or an empty pointer if no such member exists.
+ TypePointer memberType(std::string const& _name) const { return members().memberType(_name); }
+
+ virtual std::string toString(bool _short) const = 0;
+ std::string toString() const { return toString(false); }
+ /// @returns the canonical name of this type for use in function signatures.
+ /// @param _addDataLocation if true, includes data location for reference types if it is "storage".
+ virtual std::string canonicalName(bool /*_addDataLocation*/) const { return toString(true); }
+ virtual u256 literalValue(Literal const*) const
+ {
+ BOOST_THROW_EXCEPTION(
+ InternalCompilerError() <<
+ errinfo_comment("Literal value requested for type without literals.")
+ );
+ }
+
+ /// @returns a (simpler) type that is encoded in the same way for external function calls.
+ /// This for example returns address for contract types.
+ /// If there is no such type, returns an empty shared pointer.
+ virtual TypePointer encodingType() const { return TypePointer(); }
+ /// @returns a (simpler) type that is used when decoding this type in calldata.
+ virtual TypePointer decodingType() const { return encodingType(); }
+ /// @returns a type that will be used outside of Solidity for e.g. function signatures.
+ /// This for example returns address for contract types.
+ /// If there is no such type, returns an empty shared pointer.
+ /// @param _inLibrary if set, returns types as used in a library, e.g. struct and contract types
+ /// are returned without modification.
+ virtual TypePointer interfaceType(bool /*_inLibrary*/) const { return TypePointer(); }
+
+protected:
+ /// Convenience object used when returning an empty member list.
+ static const MemberList EmptyMemberList;
+};
+
+/**
+ * Any kind of integer type (signed, unsigned, address).
+ */
+class IntegerType: public Type
+{
+public:
+ enum class Modifier
+ {
+ Unsigned, Signed, Address
+ };
+ virtual Category category() const override { return Category::Integer; }
+
+ explicit IntegerType(int _bits, Modifier _modifier = Modifier::Unsigned);
+
+ virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+
+ virtual bool operator==(Type const& _other) const override;
+
+ virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_bits / 8; }
+ virtual unsigned storageBytes() const override { return m_bits / 8; }
+ virtual bool isValueType() const override { return true; }
+
+ virtual MemberList const& members() const override { return isAddress() ? AddressMemberList : EmptyMemberList; }
+
+ virtual std::string toString(bool _short) const override;
+
+ virtual TypePointer encodingType() const override { return shared_from_this(); }
+ virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+
+ int numBits() const { return m_bits; }
+ bool isAddress() const { return m_modifier == Modifier::Address; }
+ bool isSigned() const { return m_modifier == Modifier::Signed; }
+
+ static const MemberList AddressMemberList;
+
+private:
+ int m_bits;
+ Modifier m_modifier;
+};
+
+/**
+ * Integer constants either literals or computed. Example expressions: 2, 2+10, ~10.
+ * There is one distinct type per value.
+ */
+class IntegerConstantType: public Type
+{
+public:
+ virtual Category category() const override { return Category::IntegerConstant; }
+
+ /// @returns true if the literal is a valid integer.
+ static bool isValidLiteral(Literal const& _literal);
+
+ explicit IntegerConstantType(Literal const& _literal);
+ explicit IntegerConstantType(bigint _value): m_value(_value) {}
+
+ virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+
+ virtual bool operator==(Type const& _other) const override;
+
+ virtual bool canBeStored() const override { return false; }
+ virtual bool canLiveOutsideStorage() const override { return false; }
+
+ virtual std::string toString(bool _short) const override;
+ virtual u256 literalValue(Literal const* _literal) const override;
+ virtual TypePointer mobileType() const override;
+
+ /// @returns the smallest integer type that can hold the value or an empty pointer if not possible.
+ std::shared_ptr<IntegerType const> integerType() const;
+
+private:
+ bigint m_value;
+};
+
+/**
+ * Literal string, can be converted to bytes, bytesX or string.
+ */
+class StringLiteralType: public Type
+{
+public:
+ virtual Category category() const override { return Category::StringLiteral; }
+
+ explicit StringLiteralType(Literal const& _literal);
+
+ virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
+ {
+ return TypePointer();
+ }
+
+ virtual bool operator==(Type const& _other) const override;
+
+ virtual bool canBeStored() const override { return false; }
+ virtual bool canLiveOutsideStorage() const override { return false; }
+ virtual unsigned sizeOnStack() const override { return 0; }
+
+ virtual std::string toString(bool) const override { return "literal_string \"" + m_value + "\""; }
+ virtual TypePointer mobileType() const override;
+
+ std::string const& value() const { return m_value; }
+
+private:
+ std::string m_value;
+};
+
+/**
+ * Bytes type with fixed length of up to 32 bytes.
+ */
+class FixedBytesType: public Type
+{
+public:
+ virtual Category category() const override { return Category::FixedBytes; }
+
+ /// @returns the smallest bytes type for the given literal or an empty pointer
+ /// if no type fits.
+ static std::shared_ptr<FixedBytesType> smallestTypeForLiteral(std::string const& _literal);
+
+ explicit FixedBytesType(int _bytes);
+
+ virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual bool operator==(Type const& _other) const override;
+ virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+
+ virtual unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
+ virtual unsigned storageBytes() const override { return m_bytes; }
+ virtual bool isValueType() const override { return true; }
+
+ virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
+ virtual TypePointer encodingType() const override { return shared_from_this(); }
+ virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+
+ int numBytes() const { return m_bytes; }
+
+private:
+ int m_bytes;
+};
+
+/**
+ * The boolean type.
+ */
+class BoolType: public Type
+{
+public:
+ BoolType() {}
+ virtual Category category() const override { return Category::Bool; }
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+
+ virtual unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
+ virtual unsigned storageBytes() const override { return 1; }
+ virtual bool isValueType() const override { return true; }
+
+ virtual std::string toString(bool) const override { return "bool"; }
+ virtual u256 literalValue(Literal const* _literal) const override;
+ virtual TypePointer encodingType() const override { return shared_from_this(); }
+ virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+};
+
+/**
+ * Base class used by types which are not value types and can be stored either in storage, memory
+ * or calldata. This is currently used by arrays and structs.
+ */
+class ReferenceType: public Type
+{
+public:
+ explicit ReferenceType(DataLocation _location): m_location(_location) {}
+ DataLocation location() const { return m_location; }
+
+ virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
+ {
+ return TypePointer();
+ }
+ virtual unsigned memoryHeadSize() const override { return 32; }
+
+ /// @returns a copy of this type with location (recursively) changed to @a _location,
+ /// whereas isPointer is only shallowly changed - the deep copy is always a bound reference.
+ virtual TypePointer copyForLocation(DataLocation _location, bool _isPointer) const = 0;
+
+ virtual TypePointer mobileType() const override { return copyForLocation(m_location, true); }
+ virtual bool dataStoredIn(DataLocation _location) const override { return m_location == _location; }
+
+ /// Storage references can be pointers or bound references. In general, local variables are of
+ /// pointer type, state variables are bound references. Assignments to pointers or deleting
+ /// them will not modify storage (that will only change the pointer). Assignment from
+ /// non-storage objects to a variable of storage pointer type is not possible.
+ bool isPointer() const { return m_isPointer; }
+
+ bool operator==(ReferenceType const& _other) const
+ {
+ return location() == _other.location() && isPointer() == _other.isPointer();
+ }
+
+ /// @returns a copy of @a _type having the same location as this (and is not a pointer type)
+ /// if _type is a reference type and an unmodified copy of _type otherwise.
+ /// This function is mostly useful to modify inner types appropriately.
+ static TypePointer copyForLocationIfReference(DataLocation _location, TypePointer const& _type);
+
+protected:
+ TypePointer copyForLocationIfReference(TypePointer const& _type) const;
+ /// @returns a human-readable description of the reference part of the type.
+ std::string stringForReferencePart() const;
+
+ DataLocation m_location = DataLocation::Storage;
+ bool m_isPointer = true;
+};
+
+/**
+ * The type of an array. The flavours are byte array (bytes), statically- (<type>[<length>])
+ * and dynamically-sized array (<type>[]).
+ * In storage, all arrays are packed tightly (as long as more than one elementary type fits in
+ * one slot). Dynamically sized arrays (including byte arrays) start with their size as a uint and
+ * thus start on their own slot.
+ */
+class ArrayType: public ReferenceType
+{
+public:
+ virtual Category category() const override { return Category::Array; }
+
+ /// Constructor for a byte array ("bytes") and string.
+ explicit ArrayType(DataLocation _location, bool _isString = false):
+ ReferenceType(_location),
+ m_arrayKind(_isString ? ArrayKind::String : ArrayKind::Bytes),
+ m_baseType(std::make_shared<FixedBytesType>(1))
+ {
+ }
+ /// Constructor for a dynamically sized array type ("type[]")
+ ArrayType(DataLocation _location, TypePointer const& _baseType):
+ ReferenceType(_location),
+ m_baseType(copyForLocationIfReference(_baseType))
+ {
+ }
+ /// Constructor for a fixed-size array type ("type[20]")
+ ArrayType(DataLocation _location, TypePointer const& _baseType, u256 const& _length):
+ ReferenceType(_location),
+ m_baseType(copyForLocationIfReference(_baseType)),
+ m_hasDynamicLength(false),
+ m_length(_length)
+ {}
+
+ virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual bool operator==(const Type& _other) const override;
+ virtual unsigned calldataEncodedSize(bool _padded) const override;
+ virtual bool isDynamicallySized() const override { return m_hasDynamicLength; }
+ virtual u256 storageSize() const override;
+ virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
+ virtual unsigned sizeOnStack() const override;
+ virtual std::string toString(bool _short) const override;
+ virtual std::string canonicalName(bool _addDataLocation) const override;
+ virtual MemberList const& members() const override;
+ virtual TypePointer encodingType() const override;
+ virtual TypePointer decodingType() const override;
+ virtual TypePointer interfaceType(bool _inLibrary) const override;
+
+ /// @returns true if this is a byte array or a string
+ bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
+ /// @returns true if this is a string
+ bool isString() const { return m_arrayKind == ArrayKind::String; }
+ TypePointer const& baseType() const { solAssert(!!m_baseType, ""); return m_baseType;}
+ u256 const& length() const { return m_length; }
+ u256 memorySize() const;
+
+ TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
+
+private:
+ /// String is interpreted as a subtype of Bytes.
+ enum class ArrayKind { Ordinary, Bytes, String };
+
+ ///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
+ ArrayKind m_arrayKind = ArrayKind::Ordinary;
+ TypePointer m_baseType;
+ bool m_hasDynamicLength = true;
+ u256 m_length;
+ /// List of member types, will be lazy-initialized because of recursive references.
+ mutable std::unique_ptr<MemberList> m_members;
+};
+
+/**
+ * The type of a contract instance or library, there is one distinct type for each contract definition.
+ */
+class ContractType: public Type
+{
+public:
+ virtual Category category() const override { return Category::Contract; }
+ explicit ContractType(ContractDefinition const& _contract, bool _super = false):
+ m_contract(_contract), m_super(_super) {}
+ /// Contracts can be implicitly converted to super classes and to addresses.
+ virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ /// Contracts can be converted to themselves and to integers.
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual bool operator==(Type const& _other) const override;
+ virtual unsigned calldataEncodedSize(bool _padded ) const override
+ {
+ return encodingType()->calldataEncodedSize(_padded);
+ }
+ virtual unsigned storageBytes() const override { return 20; }
+ virtual bool canLiveOutsideStorage() const override { return true; }
+ virtual bool isValueType() const override { return true; }
+ virtual std::string toString(bool _short) const override;
+ virtual std::string canonicalName(bool _addDataLocation) const override;
+
+ virtual MemberList const& members() const override;
+ virtual TypePointer encodingType() const override
+ {
+ return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
+ }
+ virtual TypePointer interfaceType(bool _inLibrary) const override
+ {
+ return _inLibrary ? shared_from_this() : encodingType();
+ }
+
+ bool isSuper() const { return m_super; }
+ ContractDefinition const& contractDefinition() const { return m_contract; }
+
+ /// Returns the function type of the constructor. Note that the location part of the function type
+ /// is not used, as this type cannot be the type of a variable or expression.
+ FunctionTypePointer const& constructorType() const;
+
+ /// @returns the identifier of the function with the given name or Invalid256 if such a name does
+ /// not exist.
+ u256 functionIdentifier(std::string const& _functionName) const;
+
+ /// @returns a list of all state variables (including inherited) of the contract and their
+ /// offsets in storage.
+ std::vector<std::tuple<VariableDeclaration const*, u256, unsigned>> stateVariables() const;
+
+private:
+ ContractDefinition const& m_contract;
+ /// If true, it is the "super" type of the current contract, i.e. it contains only inherited
+ /// members.
+ bool m_super = false;
+ /// Type of the constructor, @see constructorType. Lazily initialized.
+ mutable FunctionTypePointer m_constructorType;
+ /// List of member types, will be lazy-initialized because of recursive references.
+ mutable std::unique_ptr<MemberList> m_members;
+};
+
+/**
+ * The type of a struct instance, there is one distinct type per struct definition.
+ */
+class StructType: public ReferenceType
+{
+public:
+ virtual Category category() const override { return Category::Struct; }
+ explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
+ ReferenceType(_location), m_struct(_struct) {}
+ virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
+ virtual bool operator==(Type const& _other) const override;
+ virtual unsigned calldataEncodedSize(bool _padded) const override;
+ u256 memorySize() const;
+ virtual u256 storageSize() const override;
+ virtual bool canLiveOutsideStorage() const override { return true; }
+ virtual std::string toString(bool _short) const override;
+
+ virtual MemberList const& members() const override;
+ virtual TypePointer encodingType() const override
+ {
+ return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : TypePointer();
+ }
+ virtual TypePointer interfaceType(bool _inLibrary) const override;
+
+ TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
+
+ virtual std::string canonicalName(bool _addDataLocation) const override;
+
+ /// @returns a function that peforms the type conversion between a list of struct members
+ /// and a memory struct of this type.
+ FunctionTypePointer constructorType() const;
+
+ std::pair<u256, unsigned> const& storageOffsetsOfMember(std::string const& _name) const;
+ u256 memoryOffsetOfMember(std::string const& _name) const;
+
+ StructDefinition const& structDefinition() const { return m_struct; }
+
+ /// @returns the set of all members that are removed in the memory version (typically mappings).
+ std::set<std::string> membersMissingInMemory() const;
+
+private:
+ StructDefinition const& m_struct;
+ /// List of member types, will be lazy-initialized because of recursive references.
+ mutable std::unique_ptr<MemberList> m_members;
+};
+
+/**
+ * The type of an enum instance, there is one distinct type per enum definition.
+ */
+class EnumType: public Type
+{
+public:
+ virtual Category category() const override { return Category::Enum; }
+ explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
+ virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual bool operator==(Type const& _other) const override;
+ virtual unsigned calldataEncodedSize(bool _padded) const override
+ {
+ return encodingType()->calldataEncodedSize(_padded);
+ }
+ virtual unsigned storageBytes() const override;
+ virtual bool canLiveOutsideStorage() const override { return true; }
+ virtual std::string toString(bool _short) const override;
+ virtual std::string canonicalName(bool _addDataLocation) const override;
+ virtual bool isValueType() const override { return true; }
+
+ virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual TypePointer encodingType() const override
+ {
+ return std::make_shared<IntegerType>(8 * int(storageBytes()));
+ }
+ virtual TypePointer interfaceType(bool _inLibrary) const override
+ {
+ return _inLibrary ? shared_from_this() : encodingType();
+ }
+
+ EnumDefinition const& enumDefinition() const { return m_enum; }
+ /// @returns the value that the string has in the Enum
+ unsigned int memberValue(ASTString const& _member) const;
+
+private:
+ EnumDefinition const& m_enum;
+ /// List of member types, will be lazy-initialized because of recursive references.
+ mutable std::unique_ptr<MemberList> m_members;
+};
+
+/**
+ * Type that can hold a finite sequence of values of different types.
+ * In some cases, the components are empty pointers (when used as placeholders).
+ */
+class TupleType: public Type
+{
+public:
+ virtual Category category() const override { return Category::Tuple; }
+ explicit TupleType(std::vector<TypePointer> const& _types = std::vector<TypePointer>()): m_components(_types) {}
+ virtual bool isImplicitlyConvertibleTo(Type const& _other) const override;
+ virtual bool operator==(Type const& _other) const override;
+ virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual std::string toString(bool) const override;
+ virtual bool canBeStored() const override { return false; }
+ virtual u256 storageSize() const override;
+ virtual bool canLiveOutsideStorage() const override { return false; }
+ virtual unsigned sizeOnStack() const override;
+ virtual TypePointer mobileType() const override;
+ /// Converts components to their temporary types and performs some wildcard matching.
+ virtual TypePointer closestTemporaryType(TypePointer const& _targetType) const override;
+
+ std::vector<TypePointer> const& components() const { return m_components; }
+
+private:
+ std::vector<TypePointer> const m_components;
+};
+
+/**
+ * The type of a function, identified by its (return) parameter types.
+ * @todo the return parameters should also have names, i.e. return parameters should be a struct
+ * type.
+ */
+class FunctionType: public Type
+{
+public:
+ /// How this function is invoked on the EVM.
+ /// @todo This documentation is outdated, and Location should rather be named "Type"
+ enum class Location
+ {
+ Internal, ///< stack-call using plain JUMP
+ External, ///< external call using CALL
+ CallCode, ///< extercnal call using CALLCODE, i.e. not exchanging the storage
+ Bare, ///< CALL without function hash
+ BareCallCode, ///< CALLCODE without function hash
+ Creation, ///< external call using CREATE
+ Send, ///< CALL, but without data and gas
+ SHA3, ///< SHA3
+ Suicide, ///< SUICIDE
+ ECRecover, ///< CALL to special contract for ecrecover
+ SHA256, ///< CALL to special contract for sha256
+ RIPEMD160, ///< CALL to special contract for ripemd160
+ Log0,
+ Log1,
+ Log2,
+ Log3,
+ Log4,
+ Event, ///< syntactic sugar for LOG*
+ SetGas, ///< modify the default gas value for the function call
+ SetValue, ///< modify the default value transfer for the function call
+ BlockHash, ///< BLOCKHASH
+ ArrayPush, ///< .push() to a dynamically sized array in storage
+ ByteArrayPush ///< .push() to a dynamically sized byte array in storage
+ };
+
+ virtual Category category() const override { return Category::Function; }
+
+ /// Creates the type of a function.
+ explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
+ /// Creates the accessor function type of a state variable.
+ explicit FunctionType(VariableDeclaration const& _varDecl);
+ /// Creates the function type of an event.
+ explicit FunctionType(EventDefinition const& _event);
+ FunctionType(
+ strings const& _parameterTypes,
+ strings const& _returnParameterTypes,
+ Location _location = Location::Internal,
+ bool _arbitraryParameters = false
+ ): FunctionType(
+ parseElementaryTypeVector(_parameterTypes),
+ parseElementaryTypeVector(_returnParameterTypes),
+ strings(),
+ strings(),
+ _location,
+ _arbitraryParameters
+ )
+ {
+ }
+ FunctionType(
+ TypePointers const& _parameterTypes,
+ TypePointers const& _returnParameterTypes,
+ strings _parameterNames = strings(),
+ strings _returnParameterNames = strings(),
+ Location _location = Location::Internal,
+ bool _arbitraryParameters = false,
+ Declaration const* _declaration = nullptr,
+ bool _gasSet = false,
+ bool _valueSet = false
+ ):
+ m_parameterTypes(_parameterTypes),
+ m_returnParameterTypes(_returnParameterTypes),
+ m_parameterNames(_parameterNames),
+ m_returnParameterNames(_returnParameterNames),
+ m_location(_location),
+ m_arbitraryParameters(_arbitraryParameters),
+ m_gasSet(_gasSet),
+ m_valueSet(_valueSet),
+ m_declaration(_declaration)
+ {}
+
+ TypePointers const& parameterTypes() const { return m_parameterTypes; }
+ std::vector<std::string> const& parameterNames() const { return m_parameterNames; }
+ std::vector<std::string> const parameterTypeNames(bool _addDataLocation) const;
+ TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
+ std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
+ std::vector<std::string> const returnParameterTypeNames(bool _addDataLocation) const;
+
+ virtual bool operator==(Type const& _other) const override;
+ virtual std::string toString(bool _short) const override;
+ virtual bool canBeStored() const override { return false; }
+ virtual u256 storageSize() const override;
+ virtual bool canLiveOutsideStorage() const override { return false; }
+ virtual unsigned sizeOnStack() const override;
+ virtual MemberList const& members() const override;
+
+ /// @returns TypePointer of a new FunctionType object. All input/return parameters are an
+ /// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
+ /// current function.
+ /// Returns an empty shared pointer if one of the input/return parameters does not have an
+ /// external type.
+ FunctionTypePointer interfaceFunctionType() const;
+
+ /// @returns true if this function can take the given argument types (possibly
+ /// after implicit conversion).
+ bool canTakeArguments(TypePointers const& _arguments) const;
+ /// @returns true if the types of parameters are equal (does't check return parameter types)
+ bool hasEqualArgumentTypes(FunctionType const& _other) const;
+
+ /// @returns true if the ABI is used for this call (only meaningful for external calls)
+ bool isBareCall() const;
+ Location const& location() const { return m_location; }
+ /// @returns the external signature of this function type given the function name
+ std::string externalSignature() const;
+ /// @returns the external identifier of this function (the hash of the signature).
+ u256 externalIdentifier() const;
+ Declaration const& declaration() const
+ {
+ solAssert(m_declaration, "Requested declaration from a FunctionType that has none");
+ return *m_declaration;
+ }
+ bool hasDeclaration() const { return !!m_declaration; }
+ bool isConstant() const { return m_isConstant; }
+ /// @return A shared pointer of an ASTString.
+ /// Can contain a nullptr in which case indicates absence of documentation
+ ASTPointer<ASTString> documentation() const;
+
+ /// true iff arguments are to be padded to multiples of 32 bytes for external calls
+ bool padArguments() const { return !(m_location == Location::SHA3 || m_location == Location::SHA256 || m_location == Location::RIPEMD160); }
+ bool takesArbitraryParameters() const { return m_arbitraryParameters; }
+ bool gasSet() const { return m_gasSet; }
+ bool valueSet() const { return m_valueSet; }
+
+ /// @returns a copy of this type, where gas or value are set manually. This will never set one
+ /// of the parameters to fals.
+ TypePointer copyAndSetGasOrValue(bool _setGas, bool _setValue) const;
+
+ /// @returns a copy of this function type where all return parameters of dynamic size are
+ /// removed and the location of reference types is changed from CallData to Memory.
+ /// This is needed if external functions are called on other contracts, as they cannot return
+ /// dynamic values.
+ /// @param _inLibrary if true, uses CallCode as location.
+ FunctionTypePointer asMemberFunction(bool _inLibrary) const;
+
+private:
+ static TypePointers parseElementaryTypeVector(strings const& _types);
+
+ TypePointers m_parameterTypes;
+ TypePointers m_returnParameterTypes;
+ std::vector<std::string> m_parameterNames;
+ std::vector<std::string> m_returnParameterNames;
+ Location const m_location;
+ /// true if the function takes an arbitrary number of arguments of arbitrary types
+ bool const m_arbitraryParameters = false;
+ bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack
+ bool const m_valueSet = false; ///< true iff the value to be sent is on the stack
+ bool m_isConstant = false;
+ mutable std::unique_ptr<MemberList> m_members;
+ Declaration const* m_declaration = nullptr;
+};
+
+/**
+ * The type of a mapping, there is one distinct type per key/value type pair.
+ * Mappings always occupy their own storage slot, but do not actually use it.
+ */
+class MappingType: public Type
+{
+public:
+ virtual Category category() const override { return Category::Mapping; }
+ MappingType(TypePointer const& _keyType, TypePointer const& _valueType):
+ m_keyType(_keyType), m_valueType(_valueType) {}
+
+ virtual bool operator==(Type const& _other) const override;
+ virtual std::string toString(bool _short) const override;
+ virtual std::string canonicalName(bool _addDataLocation) const override;
+ virtual bool canLiveOutsideStorage() const override { return false; }
+ virtual TypePointer encodingType() const override
+ {
+ return std::make_shared<IntegerType>(256);
+ }
+ virtual TypePointer interfaceType(bool _inLibrary) const override
+ {
+ return _inLibrary ? shared_from_this() : TypePointer();
+ }
+
+ TypePointer const& keyType() const { return m_keyType; }
+ TypePointer const& valueType() const { return m_valueType; }
+
+private:
+ TypePointer m_keyType;
+ TypePointer m_valueType;
+};
+
+/**
+ * The type of a type reference. The type of "uint32" when used in "a = uint32(2)" is an example
+ * of a TypeType.
+ * For super contracts or libraries, this has members directly.
+ */
+class TypeType: public Type
+{
+public:
+ virtual Category category() const override { return Category::TypeType; }
+ explicit TypeType(TypePointer const& _actualType, ContractDefinition const* _currentContract = nullptr):
+ m_actualType(_actualType), m_currentContract(_currentContract) {}
+ TypePointer const& actualType() const { return m_actualType; }
+
+ virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual bool operator==(Type const& _other) const override;
+ virtual bool canBeStored() const override { return false; }
+ virtual u256 storageSize() const override;
+ virtual bool canLiveOutsideStorage() const override { return false; }
+ virtual unsigned sizeOnStack() const override;
+ virtual std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
+ virtual MemberList const& members() const override;
+
+private:
+ TypePointer m_actualType;
+ /// Context in which this type is used (influences visibility etc.), can be nullptr.
+ ContractDefinition const* m_currentContract;
+ /// List of member types, will be lazy-initialized because of recursive references.
+ mutable std::unique_ptr<MemberList> m_members;
+};
+
+
+/**
+ * The type of a function modifier. Not used for anything for now.
+ */
+class ModifierType: public Type
+{
+public:
+ virtual Category category() const override { return Category::Modifier; }
+ explicit ModifierType(ModifierDefinition const& _modifier);
+
+ virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual bool canBeStored() const override { return false; }
+ virtual u256 storageSize() const override;
+ virtual bool canLiveOutsideStorage() const override { return false; }
+ virtual unsigned sizeOnStack() const override { return 0; }
+ virtual bool operator==(Type const& _other) const override;
+ virtual std::string toString(bool _short) const override;
+
+private:
+ TypePointers m_parameterTypes;
+};
+
+
+/**
+ * Special type for magic variables (block, msg, tx), similar to a struct but without any reference
+ * (it always references a global singleton by name).
+ */
+class MagicType: public Type
+{
+public:
+ enum class Kind { Block, Message, Transaction };
+ virtual Category category() const override { return Category::Magic; }
+
+ explicit MagicType(Kind _kind);
+
+ virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
+ {
+ return TypePointer();
+ }
+
+ virtual bool operator==(Type const& _other) const override;
+ virtual bool canBeStored() const override { return false; }
+ virtual bool canLiveOutsideStorage() const override { return true; }
+ virtual unsigned sizeOnStack() const override { return 0; }
+ virtual MemberList const& members() const override { return m_members; }
+
+ virtual std::string toString(bool _short) const override;
+
+private:
+ Kind m_kind;
+
+ MemberList m_members;
+};
+
+}
+}