Minor code factoring to clarify for init scope extension

This commit is contained in:
Bhargava Shastry 2020-04-22 11:17:15 +02:00
parent 7280ed716a
commit 62e5ccec90
2 changed files with 49 additions and 80 deletions

View File

@ -344,62 +344,80 @@ void ProtoConverter::visit(BinaryOp const& _x)
m_output << ")";
}
void ProtoConverter::visit(VarDecl const& _x)
void ProtoConverter::scopeVariables(vector<string> const& _varNames)
{
string varName = newVarName();
m_output << "let " << varName << " := ";
visit(_x.expr());
m_output << "\n";
// If we are inside a for-init block, there are two places
// where the visited vardecl may have been defined:
// - directly inside the for-init block
// - inside a block within the for-init block
// In the latter case, we don't scope extend.
// In the latter case, we don't scope extend. The flag
// m_forInitScopeExtEnabled (= true) indicates whether we are directly
// inside a for-init block e.g., for { let x } or (= false) inside a
// nested for-init block e.g., for { { let x } }
bool forInitScopeExtendVariable = m_inForInitScope && m_forInitScopeExtEnabled;
// There are four cases that are tackled here
// Case 1. We are inside a function definition and the variable declaration's
// scope needs to be extended.
// Case 2. We are inside a function definition but scope extension is disabled
// Case 3. We are inside global scope and scope extension is required
// Case 4. We are inside global scope but scope extension is disabled
if (m_inFunctionDef)
{
// Variables declared directly in for-init block
// are tracked separately because their scope
// extends beyond the block they are defined in
// to the rest of the for-loop statement.
if (m_inForInitScope && m_forInitScopeExtEnabled)
// Case 1
if (forInitScopeExtendVariable)
{
yulAssert(
!m_funcForLoopInitVars.empty() && !m_funcForLoopInitVars.back().empty(),
"Proto fuzzer: Invalid operation"
);
m_funcForLoopInitVars.back().back().push_back(varName);
!m_funcForLoopInitVars.empty() && !m_funcForLoopInitVars.back().empty(), "Proto fuzzer: Invalid operation");
for (auto const& varName: _varNames)
m_funcForLoopInitVars.back().back().push_back(varName);
}
// Case 2
else
{
yulAssert(
!m_funcVars.empty() && !m_funcVars.back().empty(),
"Proto fuzzer: Invalid operation"
);
m_funcVars.back().back().push_back(varName);
for (auto const& varName: _varNames)
m_funcVars.back().back().push_back(varName);
}
}
// If m_inFunctionDef is false, we are in global scope
else
{
if (m_inForInitScope && m_forInitScopeExtEnabled)
// Case 3
if (forInitScopeExtendVariable)
{
yulAssert(
!m_globalForLoopInitVars.empty(),
"Proto fuzzer: Invalid operation"
);
m_globalForLoopInitVars.back().push_back(varName);
yulAssert(!m_globalForLoopInitVars.empty(), "Proto fuzzer: Invalid operation");
for (auto const& varName: _varNames)
m_globalForLoopInitVars.back().push_back(varName);
}
// Case 4
else
{
yulAssert(
!m_globalVars.empty(),
"Proto fuzzer: Invalid operation"
);
m_globalVars.back().push_back(varName);
yulAssert(!m_globalVars.empty(), "Proto fuzzer: Invalid operation");
for (auto const& varName: _varNames)
m_globalVars.back().push_back(varName);
}
}
}
void ProtoConverter::visit(VarDecl const& _x)
{
string varName = newVarName();
m_output << "let " << varName << " := ";
visit(_x.expr());
m_output << "\n";
scopeVariables({varName});
}
void ProtoConverter::visit(MultiVarDecl const& _x)
{
m_output << "let ";
@ -417,61 +435,7 @@ void ProtoConverter::visit(MultiVarDecl const& _x)
delimiter = ", ";
}
m_output << "\n";
// If we are inside a for-init block, there are two places
// where the visited vardecl may have been defined:
// - directly inside the for-init block
// - inside a block within the for-init block
// In the latter case, we don't scope extend.
if (m_inFunctionDef)
{
// Variables declared directly in for-init block
// are tracked separately because their scope
// extends beyond the block they are defined in
// to the rest of the for-loop statement.
if (m_inForInitScope && m_forInitScopeExtEnabled)
{
yulAssert(
!m_funcForLoopInitVars.empty() && !m_funcForLoopInitVars.back().empty(),
"Proto fuzzer: Invalid operation"
);
for (auto const& varName: varNames)
m_funcForLoopInitVars.back().back().push_back(varName);
}
else
{
yulAssert(
!m_funcVars.empty() && !m_funcVars.back().empty(),
"Proto fuzzer: Invalid operation"
);
for (auto const& varName: varNames)
m_funcVars.back().back().push_back(varName);
}
}
else
{
if (m_inForInitScope && m_forInitScopeExtEnabled)
{
yulAssert(
!m_globalForLoopInitVars.empty(),
"Proto fuzzer: Invalid operation"
);
for (auto const& varName: varNames)
m_globalForLoopInitVars.back().push_back(varName);
}
else
{
yulAssert(
!m_globalVars.empty(),
"Proto fuzzer: Invalid operation"
);
for (auto const& varName: varNames)
m_globalVars.back().push_back(varName);
}
}
scopeVariables(varNames);
}
void ProtoConverter::visit(TypedVarDecl const& _x)
@ -1824,7 +1788,7 @@ void ProtoConverter::createFunctionDefAndCall(
yulAssert(
!m_inForInitScope,
"Proto fuzzer: Trying to create function call inside for-init block"
"Proto fuzzer: Trying to create function call inside a for-init block"
);
if (_x.force_call())
createFunctionCall(funcName, _numInParams, _numOutParams);

View File

@ -236,6 +236,11 @@ private:
/// @return A vector of strings containing the printed variable names.
std::vector<std::string> createVars(unsigned _startIdx, unsigned _endIdx);
/// Manages scope of yul variables
/// @param _varNames is a list of yul variable names whose scope needs
/// to be tracked according to yul scoping rules.
void scopeVariables(std::vector<std::string> const& _varNames);
/// Print the yul syntax to make a call to a function named @a _funcName to
/// the output stream.
/// @param _funcName Name of the function to be called