Implement function modifiers.

This commit is contained in:
chriseth
2020-12-17 17:00:51 +01:00
parent 9328503265
commit ccaa81fbe7
22 changed files with 220 additions and 8 deletions
+133 -3
View File
@@ -249,10 +249,10 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
{
string functionName = IRNames::function(_function);
return m_context.functionCollector().createFunction(functionName, [&]() {
solUnimplementedAssert(_function.modifiers().empty(), "Modifiers not implemented yet.");
m_context.resetLocalVariables();
Whiskers t(R"(
function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> {
<initReturnVariables>
<retInit>
<body>
}
)");
@@ -268,8 +268,137 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function)
retParams += m_context.addLocalVariable(*varDecl).stackSlots();
retInit += generateInitialAssignment(*varDecl);
}
t("retParams", joinHumanReadable(retParams));
t("initReturnVariables", retInit);
t("retInit", retInit);
if (_function.modifiers().empty())
t("body", generate(_function.body()));
else
{
for (size_t i = 0; i < _function.modifiers().size(); ++i)
{
ModifierInvocation const& modifier = *_function.modifiers().at(i);
string next =
i + 1 < _function.modifiers().size() ?
IRNames::modifierInvocation(*_function.modifiers().at(i + 1)) :
IRNames::functionWithModifierInner(_function);
generateModifier(modifier, _function, next);
}
t("body",
(retParams.empty() ? string{} : joinHumanReadable(retParams) + " := ") +
IRNames::modifierInvocation(*_function.modifiers().at(0)) +
"(" +
joinHumanReadable(retParams + params) +
")"
);
// Now generate the actual inner function.
generateFunctionWithModifierInner(_function);
}
return t.render();
});
}
string IRGenerator::generateModifier(
ModifierInvocation const& _modifierInvocation,
FunctionDefinition const& _function,
string const& _nextFunction
)
{
string functionName = IRNames::modifierInvocation(_modifierInvocation);
return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables();
Whiskers t(R"(
function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> {
<assignRetParams>
<evalArgs>
<body>
}
)");
t("functionName", functionName);
vector<string> retParamsIn;
for (auto const& varDecl: _function.returnParameters())
retParamsIn += IRVariable(*varDecl).stackSlots();
vector<string> params = retParamsIn;
for (auto const& varDecl: _function.parameters())
params += m_context.addLocalVariable(*varDecl).stackSlots();
t("params", joinHumanReadable(params));
vector<string> retParams;
string assignRetParams;
for (size_t i = 0; i < retParamsIn.size(); ++i)
{
retParams.emplace_back(m_context.newYulVariable());
assignRetParams += retParams.back() + " := " + retParamsIn[i] + "\n";
}
t("retParams", joinHumanReadable(retParams));
t("assignRetParams", assignRetParams);
solAssert(*_modifierInvocation.name().annotation().requiredLookup == VirtualLookup::Virtual, "");
ModifierDefinition const& modifier = dynamic_cast<ModifierDefinition const&>(
*_modifierInvocation.name().annotation().referencedDeclaration
).resolveVirtual(m_context.mostDerivedContract());
solAssert(
modifier.parameters().empty() ==
(!_modifierInvocation.arguments() || _modifierInvocation.arguments()->empty()),
""
);
IRGeneratorForStatements expressionEvaluator(m_context, m_utils);
if (_modifierInvocation.arguments())
for (size_t i = 0; i < _modifierInvocation.arguments()->size(); i++)
{
IRVariable argument = expressionEvaluator.evaluateExpression(
*_modifierInvocation.arguments()->at(i),
*modifier.parameters()[i]->annotation().type
);
expressionEvaluator.define(
m_context.addLocalVariable(*modifier.parameters()[i]),
argument
);
}
t("evalArgs", expressionEvaluator.code());
IRGeneratorForStatements generator(m_context, m_utils, [&]() {
string ret = joinHumanReadable(retParams);
return
(ret.empty() ? "" : ret + " := ") +
_nextFunction + "(" + joinHumanReadable(params) + ")\n";
});
generator.generate(modifier.body());
t("body", generator.code());
return t.render();
});
}
string IRGenerator::generateFunctionWithModifierInner(FunctionDefinition const& _function)
{
string functionName = IRNames::functionWithModifierInner(_function);
return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables();
Whiskers t(R"(
function <functionName>(<params>)<?+retParams> -> <retParams></+retParams> {
<assignRetParams>
<body>
}
)");
t("functionName", functionName);
vector<string> retParams;
vector<string> retParamsIn;
for (auto const& varDecl: _function.returnParameters())
retParams += m_context.addLocalVariable(*varDecl).stackSlots();
string assignRetParams;
for (size_t i = 0; i < retParams.size(); ++i)
{
retParamsIn.emplace_back(m_context.newYulVariable());
assignRetParams += retParams.back() + " := " + retParamsIn[i] + "\n";
}
vector<string> params = retParamsIn;
for (auto const& varDecl: _function.parameters())
params += m_context.addLocalVariable(*varDecl).stackSlots();
t("params", joinHumanReadable(params));
t("retParams", joinHumanReadable(retParams));
t("assignRetParams", assignRetParams);
t("body", generate(_function.body()));
return t.render();
});
@@ -510,6 +639,7 @@ string IRGenerator::initStateVariables(ContractDefinition const& _contract)
void IRGenerator::generateImplicitConstructors(ContractDefinition const& _contract)
{
// TODO reset local variables somewhere here.
auto listAllParams = [&](
map<ContractDefinition const*, vector<string>> const& baseParams) -> vector<string>
{