aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/formal/Why3Translator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/formal/Why3Translator.cpp')
-rw-r--r--libsolidity/formal/Why3Translator.cpp142
1 files changed, 104 insertions, 38 deletions
diff --git a/libsolidity/formal/Why3Translator.cpp b/libsolidity/formal/Why3Translator.cpp
index 944b1e7b..4c187a56 100644
--- a/libsolidity/formal/Why3Translator.cpp
+++ b/libsolidity/formal/Why3Translator.cpp
@@ -35,7 +35,6 @@ bool Why3Translator::process(SourceUnit const& _source)
fatalError(_source, "Multiple source units not yet supported");
appendPreface();
_source.accept(*this);
- addLine("end");
}
catch (FatalError& _e)
{
@@ -71,18 +70,6 @@ module UInt256
type t = uint256,
constant max = max_uint256
end
-
-module Solidity
-use import int.Int
-use import ref.Ref
-use import map.Map
-use import array.Array
-use import int.ComputerDivision
-use import mach.int.Unsigned
-use import UInt256
-
-exception Ret
-type state = StateUnused
)";
}
@@ -113,6 +100,8 @@ void Why3Translator::addLine(string const& _line)
void Why3Translator::add(string const& _str)
{
+ if (m_currentLine.empty())
+ m_indentationAtLineStart = m_indentation;
m_currentLine += _str;
}
@@ -120,7 +109,7 @@ void Why3Translator::newLine()
{
if (!m_currentLine.empty())
{
- for (size_t i = 0; i < m_indentation; ++i)
+ for (size_t i = 0; i < m_indentationAtLineStart; ++i)
m_result.push_back('\t');
m_result += m_currentLine;
m_result.push_back('\n');
@@ -130,6 +119,7 @@ void Why3Translator::newLine()
void Why3Translator::unindent()
{
+ newLine();
solAssert(m_indentation > 0, "");
m_indentation--;
}
@@ -142,9 +132,52 @@ bool Why3Translator::visit(ContractDefinition const& _contract)
if (_contract.isLibrary())
error(_contract, "Libraries not supported.");
- addSourceFromDocStrings(_contract.annotation());
+ addLine("module Contract_" + _contract.name());
+ indent();
+ addLine("use import int.Int");
+ addLine("use import ref.Ref");
+ addLine("use import map.Map");
+ addLine("use import array.Array");
+ addLine("use import int.ComputerDivision");
+ addLine("use import mach.int.Unsigned");
+ addLine("use import UInt256");
+ addLine("exception Ret");
+
+ addLine("type state = {");
+ indent();
+ m_stateVariables = &_contract.stateVariables();
+ for (auto const& variable: _contract.stateVariables())
+ {
+ string varType = toFormalType(*variable->annotation().type);
+ if (varType.empty())
+ fatalError(*variable, "Type not supported.");
+ addLine("mutable _" + variable->name() + ": ref " + varType);
+ }
+ unindent();
+ addLine("}");
- return true;
+ if (!_contract.baseContracts().empty())
+ error(*_contract.baseContracts().front(), "Inheritance not supported.");
+ if (!_contract.definedStructs().empty())
+ error(*_contract.definedStructs().front(), "User-defined types not supported.");
+ if (!_contract.definedEnums().empty())
+ error(*_contract.definedEnums().front(), "User-defined types not supported.");
+ if (!_contract.events().empty())
+ error(*_contract.events().front(), "Events not supported.");
+ if (!_contract.functionModifiers().empty())
+ error(*_contract.functionModifiers().front(), "Modifiers not supported.");
+
+ ASTNode::listAccept(_contract.definedFunctions(), *this);
+
+ return false;
+}
+
+void Why3Translator::endVisit(ContractDefinition const& _contract)
+{
+ m_stateVariables = nullptr;
+ addSourceFromDocStrings(_contract.annotation());
+ unindent();
+ addLine("end");
}
bool Why3Translator::visit(FunctionDefinition const& _function)
@@ -177,7 +210,6 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
add(" (arg_" + param->name() + ": " + paramType + ")");
}
add(":");
- newLine();
indent();
indent();
@@ -191,7 +223,7 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
retString += ", ";
retString += paramType;
}
- addLine(retString + ")");
+ add(retString + ")");
unindent();
addSourceFromDocStrings(_function.annotation());
@@ -218,6 +250,7 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
addLine("try");
_function.body().accept(*this);
+ add(";");
addLine("raise Ret");
string retVals;
@@ -238,9 +271,18 @@ bool Why3Translator::visit(FunctionDefinition const& _function)
bool Why3Translator::visit(Block const& _node)
{
addSourceFromDocStrings(_node.annotation());
- addLine("begin");
+ add("begin");
indent();
- return true;
+ for (size_t i = 0; i < _node.statements().size(); ++i)
+ {
+ _node.statements()[i]->accept(*this);
+ if (!m_currentLine.empty() && i != _node.statements().size() - 1)
+ add(";");
+ newLine();
+ }
+ unindent();
+ add("end");
+ return false;
}
bool Why3Translator::visit(IfStatement const& _node)
@@ -250,12 +292,12 @@ bool Why3Translator::visit(IfStatement const& _node)
add("if ");
_node.condition().accept(*this);
add(" then");
- newLine();
- _node.trueStatement().accept(*this);
+ visitIndentedUnlessBlock(_node.trueStatement());
if (_node.falseStatement())
{
- addLine("else");
- _node.falseStatement()->accept(*this);
+ newLine();
+ add("else");
+ visitIndentedUnlessBlock(*_node.falseStatement());
}
return false;
}
@@ -266,10 +308,10 @@ bool Why3Translator::visit(WhileStatement const& _node)
add("while ");
_node.condition().accept(*this);
- add(" do");
newLine();
- _node.body().accept(*this);
- addLine("done;");
+ add("do");
+ visitIndentedUnlessBlock(_node.body());
+ add("done");
return false;
}
@@ -286,14 +328,12 @@ bool Why3Translator::visit(Return const& _node)
error(_node, "Directly returning tuples not supported. Rather assign to return variable.");
return false;
}
- newLine();
add("begin _" + params.front()->name() + " := ");
_node.expression()->accept(*this);
add("; raise Ret end");
- newLine();
}
else
- addLine("raise Ret;");
+ add("raise Ret");
return false;
}
@@ -310,8 +350,6 @@ bool Why3Translator::visit(VariableDeclarationStatement const& _node)
{
add("_" + _node.declarations().front()->name() + " := ");
_node.initialValue()->accept(*this);
- add(";");
- newLine();
}
return false;
}
@@ -429,7 +467,7 @@ bool Why3Translator::visit(FunctionCall const& _node)
add("(");
_node.expression().accept(*this);
- add(" StateUnused");
+ add(" state");
for (auto const& arg: _node.arguments())
{
add(" ");
@@ -487,10 +525,15 @@ bool Why3Translator::visit(Identifier const& _identifier)
add("_" + functionDef->name());
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
{
- if (_identifier.annotation().lValueRequested)
- add("_" + variable->name());
- else
- add("!_" + variable->name());
+ bool isStateVar = isStateVariable(variable);
+ bool lvalue = _identifier.annotation().lValueRequested;
+ if (!lvalue)
+ add("!(");
+ if (isStateVar)
+ add("state.");
+ add("_" + variable->name());
+ if (!lvalue)
+ add(")");
}
else
error(_identifier, "Not supported.");
@@ -517,7 +560,30 @@ bool Why3Translator::visit(Literal const& _literal)
return false;
}
-void Why3Translator::addSourceFromDocStrings(const DocumentedAnnotation& _annotation)
+bool Why3Translator::isStateVariable(VariableDeclaration const* _var) const
+{
+ solAssert(!!m_stateVariables, "");
+ for (auto const& var: *m_stateVariables)
+ if (var.get() == _var)
+ return true;
+ return false;
+}
+
+void Why3Translator::visitIndentedUnlessBlock(Statement const& _statement)
+{
+ bool isBlock = !!dynamic_cast<Block const*>(&_statement);
+ if (isBlock)
+ newLine();
+ else
+ indent();
+ _statement.accept(*this);
+ if (isBlock)
+ newLine();
+ else
+ unindent();
+}
+
+void Why3Translator::addSourceFromDocStrings(DocumentedAnnotation const& _annotation)
{
auto why3Range = _annotation.docTags.equal_range("why3");
for (auto i = why3Range.first; i != why3Range.second; ++i)