Implement switch.

This commit is contained in:
chriseth 2019-04-23 21:32:58 +02:00
parent c3705f268c
commit 01d1d08fea
3 changed files with 56 additions and 13 deletions

View File

@ -57,7 +57,11 @@ struct BuiltinCall { std::string functionName; std::vector<Expression> arguments
struct LocalAssignment { std::string variableName; std::unique_ptr<Expression> value; };
struct GlobalAssignment { std::string variableName; std::unique_ptr<Expression> value; };
struct Block { std::string labelName; std::vector<Expression> statements; };
struct If { std::unique_ptr<Expression> condition; std::vector<Expression> statements; };
struct If {
std::unique_ptr<Expression> condition;
std::vector<Expression> statements;
std::unique_ptr<std::vector<Expression>> elseStatements;
};
struct Loop { std::string labelName; std::vector<Expression> statements; };
struct Break { Label label; };
struct Continue { Label label; };

View File

@ -44,7 +44,10 @@ string EWasmCodeTransform::run(Dialect const& _dialect, yul::Block const& _ast)
for (auto const& statement: _ast.statements)
{
yulAssert(statement.type() == typeid(yul::FunctionDefinition), "");
yulAssert(
statement.type() == typeid(yul::FunctionDefinition),
"Expected only function definitions at the highest level."
);
functions.emplace_back(transform.translateFunction(boost::get<yul::FunctionDefinition>(statement)));
}
@ -57,19 +60,19 @@ wasm::Expression EWasmCodeTransform::generateMultiAssignment(
)
{
yulAssert(!_variableNames.empty(), "");
wasm::LocalAssignment assignment{std::move(_variableNames.front()), std::move(_firstValue)};
wasm::LocalAssignment assignment{move(_variableNames.front()), std::move(_firstValue)};
if (_variableNames.size() == 1)
return move(assignment);
wasm::Block block;
block.statements.emplace_back(std::move(assignment));
block.statements.emplace_back(move(assignment));
for (size_t i = 1; i < _variableNames.size(); ++i)
block.statements.emplace_back(wasm::LocalAssignment{
std::move(_variableNames.at(i)),
move(_variableNames.at(i)),
make_unique<wasm::Expression>(wasm::GlobalVariable{m_globalVariables.at(i - 1).variableName})
});
return std::move(block);
return move(block);
}
wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varDecl)
@ -82,7 +85,7 @@ wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varD
}
if (_varDecl.value)
return generateMultiAssignment(std::move(variableNames), visit(*_varDecl.value));
return generateMultiAssignment(move(variableNames), visit(*_varDecl.value));
else
return wasm::BuiltinCall{"nop", {}};
}
@ -92,7 +95,7 @@ wasm::Expression EWasmCodeTransform::operator()(Assignment const& _assignment)
vector<string> variableNames;
for (auto const& var: _assignment.variableNames)
variableNames.emplace_back(var.name.str());
return generateMultiAssignment(std::move(variableNames), visit(*_assignment.value));
return generateMultiAssignment(move(variableNames), visit(*_assignment.value));
}
wasm::Expression EWasmCodeTransform::operator()(StackAssignment const&)
@ -150,13 +153,46 @@ wasm::Expression EWasmCodeTransform::operator()(yul::Instruction const&)
wasm::Expression EWasmCodeTransform::operator()(If const& _if)
{
return wasm::If{visit(*_if.condition), visit(_if.body.statements)};
return wasm::If{visit(*_if.condition), visit(_if.body.statements), {}};
}
wasm::Expression EWasmCodeTransform::operator()(Switch const&)
wasm::Expression EWasmCodeTransform::operator()(Switch const& _switch)
{
solUnimplementedAssert(false, "");
return {};
wasm::Block block;
string condition = m_nameDispenser.newName("condition"_yulstring).str();
m_localVariables.emplace_back(wasm::VariableDeclaration{condition});
block.statements.emplace_back(wasm::LocalAssignment{condition, visit(*_switch.expression)});
vector<wasm::Expression>* currentBlock = &block.statements;
for (size_t i = 0; i < _switch.cases.size(); ++i)
{
Case const& c = _switch.cases.at(i);
if (c.value)
{
wasm::BuiltinCall comparison{"i64.eq", {}};
comparison.arguments.emplace_back(wasm::LocalVariable{condition});
comparison.arguments.emplace_back(visitReturnByValue(*c.value));
wasm::If ifStmnt{
make_unique<wasm::Expression>(move(comparison)),
visit(c.body.statements),
{}
};
vector<wasm::Expression>* nextBlock = nullptr;
if (i != _switch.cases.size() - 1)
{
ifStmnt.elseStatements = make_unique<vector<wasm::Expression>>();
nextBlock = ifStmnt.elseStatements.get();
}
currentBlock->emplace_back(move(ifStmnt));
currentBlock = nextBlock;
}
else
{
yulAssert(i == _switch.cases.size() - 1, "Default case must be last.");
*currentBlock += visit(c.body.statements);
}
}
return move(block);
}
wasm::Expression EWasmCodeTransform::operator()(FunctionDefinition const&)

View File

@ -84,7 +84,10 @@ string EWasmToText::operator()(wasm::GlobalAssignment const& _assignment)
string EWasmToText::operator()(wasm::If const& _if)
{
return "(if " + visit(*_if.condition) + " (then\n" + indented(joinTransformed(_if.statements)) + "\n))\n";
string text = "(if " + visit(*_if.condition) + " (then\n" + indented(joinTransformed(_if.statements)) + ")";
if (_if.elseStatements)
text += "(else\n" + indented(joinTransformed(*_if.elseStatements)) + ")";
return std::move(text) + ")\n";
}
string EWasmToText::operator()(wasm::Loop const& _loop)