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 LocalAssignment { std::string variableName; std::unique_ptr<Expression> value; };
struct GlobalAssignment { 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 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 Loop { std::string labelName; std::vector<Expression> statements; };
struct Break { Label label; }; struct Break { Label label; };
struct Continue { 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) 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))); functions.emplace_back(transform.translateFunction(boost::get<yul::FunctionDefinition>(statement)));
} }
@ -57,19 +60,19 @@ wasm::Expression EWasmCodeTransform::generateMultiAssignment(
) )
{ {
yulAssert(!_variableNames.empty(), ""); 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) if (_variableNames.size() == 1)
return move(assignment); return move(assignment);
wasm::Block block; 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) for (size_t i = 1; i < _variableNames.size(); ++i)
block.statements.emplace_back(wasm::LocalAssignment{ 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}) 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) wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varDecl)
@ -82,7 +85,7 @@ wasm::Expression EWasmCodeTransform::operator()(VariableDeclaration const& _varD
} }
if (_varDecl.value) if (_varDecl.value)
return generateMultiAssignment(std::move(variableNames), visit(*_varDecl.value)); return generateMultiAssignment(move(variableNames), visit(*_varDecl.value));
else else
return wasm::BuiltinCall{"nop", {}}; return wasm::BuiltinCall{"nop", {}};
} }
@ -92,7 +95,7 @@ wasm::Expression EWasmCodeTransform::operator()(Assignment const& _assignment)
vector<string> variableNames; vector<string> variableNames;
for (auto const& var: _assignment.variableNames) for (auto const& var: _assignment.variableNames)
variableNames.emplace_back(var.name.str()); 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&) wasm::Expression EWasmCodeTransform::operator()(StackAssignment const&)
@ -150,13 +153,46 @@ wasm::Expression EWasmCodeTransform::operator()(yul::Instruction const&)
wasm::Expression EWasmCodeTransform::operator()(If const& _if) 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, ""); wasm::Block block;
return {}; 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&) 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) 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) string EWasmToText::operator()(wasm::Loop const& _loop)