2015-10-21 14:43:31 +00:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
* Component that translates Solidity code into the why3 programming language.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <libsolidity/ast/ASTVisitor.h>
|
|
|
|
#include <libsolidity/interface/Exceptions.h>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
namespace dev
|
|
|
|
{
|
|
|
|
namespace solidity
|
|
|
|
{
|
|
|
|
|
|
|
|
class SourceUnit;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Simple translator from Solidity to Why3.
|
|
|
|
*
|
2016-09-07 13:20:19 +00:00
|
|
|
* @todo detect side effects in sub-expressions and limit them to one per statement. #1043
|
2015-10-21 14:43:31 +00:00
|
|
|
* @todo `x = y = z`
|
|
|
|
* @todo implicit and explicit type conversion
|
|
|
|
*/
|
|
|
|
class Why3Translator: private ASTConstVisitor
|
|
|
|
{
|
|
|
|
public:
|
2015-11-26 13:47:28 +00:00
|
|
|
Why3Translator(ErrorList& _errors): m_lines(std::vector<Line>{{std::string(), 0}}), m_errors(_errors) {}
|
2015-10-21 14:43:31 +00:00
|
|
|
|
|
|
|
/// Appends formalisation of the given source unit to the output.
|
|
|
|
/// @returns false on error.
|
|
|
|
bool process(SourceUnit const& _source);
|
|
|
|
|
2015-11-22 19:39:24 +00:00
|
|
|
std::string translation() const;
|
2015-10-21 14:43:31 +00:00
|
|
|
|
|
|
|
private:
|
2016-03-09 16:23:05 +00:00
|
|
|
/// Creates an error and adds it to errors list.
|
2015-10-21 14:43:31 +00:00
|
|
|
void error(ASTNode const& _node, std::string const& _description);
|
|
|
|
/// Reports a fatal error and throws.
|
|
|
|
void fatalError(ASTNode const& _node, std::string const& _description);
|
|
|
|
|
|
|
|
/// Appends imports and constants use throughout the formal code.
|
|
|
|
void appendPreface();
|
|
|
|
|
2016-09-07 18:16:46 +00:00
|
|
|
/// @returns a string representation of the corresponding formal type or throws NoFormalType exception.
|
2015-10-21 14:43:31 +00:00
|
|
|
std::string toFormalType(Type const& _type) const;
|
2016-09-07 18:16:46 +00:00
|
|
|
using errinfo_noFormalTypeFrom = boost::error_info<struct tag_noFormalTypeFrom, std::string /* name of the type that cannot be translated */ >;
|
|
|
|
struct NoFormalType: virtual Exception {};
|
2015-10-21 14:43:31 +00:00
|
|
|
|
2015-11-22 19:39:24 +00:00
|
|
|
void indent() { newLine(); m_lines.back().indentation++; }
|
2015-10-21 14:43:31 +00:00
|
|
|
void unindent();
|
|
|
|
void addLine(std::string const& _line);
|
|
|
|
void add(std::string const& _str);
|
|
|
|
void newLine();
|
2015-11-22 19:39:24 +00:00
|
|
|
void appendSemicolon();
|
2015-10-21 14:43:31 +00:00
|
|
|
|
|
|
|
virtual bool visit(SourceUnit const&) override { return true; }
|
|
|
|
virtual bool visit(ContractDefinition const& _contract) override;
|
2015-11-16 19:35:54 +00:00
|
|
|
virtual void endVisit(ContractDefinition const& _contract) override;
|
2015-10-21 14:43:31 +00:00
|
|
|
virtual bool visit(FunctionDefinition const& _function) override;
|
2015-11-22 23:26:04 +00:00
|
|
|
virtual void endVisit(FunctionDefinition const& _function) override;
|
2015-10-21 14:43:31 +00:00
|
|
|
virtual bool visit(Block const&) override;
|
|
|
|
virtual bool visit(IfStatement const& _node) override;
|
|
|
|
virtual bool visit(WhileStatement const& _node) override;
|
|
|
|
virtual bool visit(Return const& _node) override;
|
2016-07-13 09:16:00 +00:00
|
|
|
virtual bool visit(Throw const& _node) override;
|
2015-10-21 14:43:31 +00:00
|
|
|
virtual bool visit(VariableDeclarationStatement const& _node) override;
|
|
|
|
virtual bool visit(ExpressionStatement const&) override;
|
|
|
|
virtual bool visit(Assignment const& _node) override;
|
|
|
|
virtual bool visit(TupleExpression const& _node) override;
|
|
|
|
virtual void endVisit(TupleExpression const&) override { add(")"); }
|
|
|
|
virtual bool visit(UnaryOperation const& _node) override;
|
|
|
|
virtual bool visit(BinaryOperation const& _node) override;
|
|
|
|
virtual bool visit(FunctionCall const& _node) override;
|
|
|
|
virtual bool visit(MemberAccess const& _node) override;
|
|
|
|
virtual bool visit(IndexAccess const& _node) override;
|
|
|
|
virtual bool visit(Identifier const& _node) override;
|
|
|
|
virtual bool visit(Literal const& _node) override;
|
2016-10-07 13:32:47 +00:00
|
|
|
virtual bool visit(PragmaDirective const& _node) override;
|
2015-10-21 14:43:31 +00:00
|
|
|
|
|
|
|
virtual bool visitNode(ASTNode const& _node) override
|
|
|
|
{
|
|
|
|
error(_node, "Code not supported for formal verification.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-16 19:35:54 +00:00
|
|
|
bool isStateVariable(VariableDeclaration const* _var) const;
|
2015-11-22 23:26:04 +00:00
|
|
|
bool isStateVariable(std::string const& _name) const;
|
|
|
|
bool isLocalVariable(VariableDeclaration const* _var) const;
|
|
|
|
bool isLocalVariable(std::string const& _name) const;
|
2015-11-16 19:35:54 +00:00
|
|
|
|
2016-07-13 09:16:00 +00:00
|
|
|
/// @returns a string representing an expression that is a copy of this.storage
|
|
|
|
std::string copyOfStorage() const;
|
|
|
|
|
2016-09-07 11:54:57 +00:00
|
|
|
/// Visits the given statement and indents it unless it is a block
|
2015-11-11 14:20:53 +00:00
|
|
|
/// (which does its own indentation).
|
|
|
|
void visitIndentedUnlessBlock(Statement const& _statement);
|
|
|
|
|
2015-10-21 14:43:31 +00:00
|
|
|
void addSourceFromDocStrings(DocumentedAnnotation const& _annotation);
|
2015-11-22 23:26:04 +00:00
|
|
|
/// Transforms substring like `#varName` and `#stateVarName` to code that evaluates to their value.
|
|
|
|
std::string transformVariableReferences(std::string const& _annotation);
|
2015-10-21 14:43:31 +00:00
|
|
|
|
|
|
|
/// True if we have already seen a contract. For now, only a single contract
|
|
|
|
/// is supported.
|
|
|
|
bool m_seenContract = false;
|
|
|
|
bool m_errorOccured = false;
|
2015-11-16 19:35:54 +00:00
|
|
|
|
2016-07-13 09:16:00 +00:00
|
|
|
/// Metadata relating to the current contract
|
|
|
|
struct ContractMetadata
|
|
|
|
{
|
|
|
|
ContractDefinition const* contract = nullptr;
|
|
|
|
std::vector<VariableDeclaration const*> stateVariables;
|
|
|
|
|
|
|
|
void reset() { contract = nullptr; stateVariables.clear(); }
|
|
|
|
};
|
|
|
|
|
|
|
|
ContractMetadata m_currentContract;
|
|
|
|
bool m_currentLValueIsRef = false;
|
2015-11-22 23:26:04 +00:00
|
|
|
std::map<std::string, VariableDeclaration const*> m_localVariables;
|
2015-11-16 19:35:54 +00:00
|
|
|
|
2015-11-22 19:39:24 +00:00
|
|
|
struct Line
|
|
|
|
{
|
|
|
|
std::string contents;
|
|
|
|
unsigned indentation;
|
|
|
|
};
|
|
|
|
std::vector<Line> m_lines;
|
2015-10-21 14:43:31 +00:00
|
|
|
ErrorList& m_errors;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|