mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
For loop with custom init and post blocks and potentially unbounded conditional expression
This commit is contained in:
parent
7187a3e5ca
commit
b5cbb1a3e9
@ -616,7 +616,9 @@ void ProtoConverter::visit(FunctionCall const& _x)
|
||||
visit(_x.call_zero());
|
||||
break;
|
||||
case FunctionCall::kCallMultidecl:
|
||||
visit(_x.call_multidecl());
|
||||
// Hack: Disallow (multi) variable declarations until scope extension is implemented for "for-init"
|
||||
if (!m_inForInitScope)
|
||||
visit(_x.call_multidecl());
|
||||
break;
|
||||
case FunctionCall::kCallMultiassign:
|
||||
visit(_x.call_multiassign());
|
||||
@ -655,17 +657,38 @@ void ProtoConverter::visit(StoreFunc const& _x)
|
||||
}
|
||||
|
||||
void ProtoConverter::visit(ForStmt const& _x)
|
||||
{
|
||||
bool wasInForBody = m_inForBodyScope;
|
||||
bool wasInForInit = m_inForInitScope;
|
||||
m_inForBodyScope = false;
|
||||
m_inForInitScope = true;
|
||||
m_output << "for ";
|
||||
visit(_x.for_init());
|
||||
m_inForInitScope = false;
|
||||
visit(_x.for_cond());
|
||||
visit(_x.for_post());
|
||||
m_inForBodyScope = true;
|
||||
visit(_x.for_body());
|
||||
m_inForBodyScope = wasInForBody;
|
||||
m_inForInitScope = wasInForInit;
|
||||
}
|
||||
|
||||
void ProtoConverter::visit(BoundedForStmt const& _x)
|
||||
{
|
||||
// Boilerplate for loop that limits the number of iterations to a maximum of 4.
|
||||
// TODO: Generalize for loop init, condition, and post blocks.
|
||||
std::string loopVarName("i_" + std::to_string(m_numNestedForLoops++));
|
||||
m_output << "for { let " << loopVarName << " := 0 } "
|
||||
<< "lt(" << loopVarName << ", 0x60) "
|
||||
<< "{ " << loopVarName << " := add(" << loopVarName << ", 0x20) } ";
|
||||
m_inForScope.push(true);
|
||||
<< "lt(" << loopVarName << ", 0x60) "
|
||||
<< "{ " << loopVarName << " := add(" << loopVarName << ", 0x20) } ";
|
||||
// Store previous for body scope
|
||||
bool wasInForBody = m_inForBodyScope;
|
||||
bool wasInForInit = m_inForInitScope;
|
||||
m_inForBodyScope = true;
|
||||
m_inForInitScope = false;
|
||||
visit(_x.for_body());
|
||||
m_inForScope.pop();
|
||||
--m_numNestedForLoops;
|
||||
// Restore previous for body scope and init
|
||||
m_inForBodyScope = wasInForBody;
|
||||
m_inForInitScope = wasInForInit;
|
||||
}
|
||||
|
||||
void ProtoConverter::visit(CaseStmt const& _x)
|
||||
@ -765,7 +788,9 @@ void ProtoConverter::visit(Statement const& _x)
|
||||
switch (_x.stmt_oneof_case())
|
||||
{
|
||||
case Statement::kDecl:
|
||||
visit(_x.decl());
|
||||
// Hack: Disallow (multi) variable declarations until scope extension is implemented for "for-init"
|
||||
if (!m_inForInitScope)
|
||||
visit(_x.decl());
|
||||
break;
|
||||
case Statement::kAssignment:
|
||||
visit(_x.assignment());
|
||||
@ -782,15 +807,18 @@ void ProtoConverter::visit(Statement const& _x)
|
||||
case Statement::kForstmt:
|
||||
visit(_x.forstmt());
|
||||
break;
|
||||
case Statement::kBoundedforstmt:
|
||||
visit(_x.boundedforstmt());
|
||||
break;
|
||||
case Statement::kSwitchstmt:
|
||||
visit(_x.switchstmt());
|
||||
break;
|
||||
case Statement::kBreakstmt:
|
||||
if (m_inForScope.top())
|
||||
if (m_inForBodyScope)
|
||||
m_output << "break\n";
|
||||
break;
|
||||
case Statement::kContstmt:
|
||||
if (m_inForScope.top())
|
||||
if (m_inForBodyScope)
|
||||
m_output << "continue\n";
|
||||
break;
|
||||
case Statement::kLogFunc:
|
||||
|
@ -42,9 +42,10 @@ public:
|
||||
{
|
||||
m_numLiveVars = 0;
|
||||
m_numVarsPerScope.push(m_numLiveVars);
|
||||
m_numNestedForLoops = 0;
|
||||
m_inForScope.push(false);
|
||||
m_numFunctionSets = 0;
|
||||
m_inForBodyScope = false;
|
||||
m_inForInitScope = false;
|
||||
m_numNestedForLoops = 0;
|
||||
}
|
||||
ProtoConverter(ProtoConverter const&) = delete;
|
||||
ProtoConverter(ProtoConverter&&) = delete;
|
||||
@ -69,6 +70,7 @@ private:
|
||||
void visit(Statement const&);
|
||||
void visit(FunctionDefinition const&);
|
||||
void visit(ForStmt const&);
|
||||
void visit(BoundedForStmt const&);
|
||||
void visit(CaseStmt const&);
|
||||
void visit(SwitchStmt const&);
|
||||
void visit(TernaryOp const&);
|
||||
@ -131,9 +133,6 @@ private:
|
||||
std::stack<unsigned> m_numVarsPerScope;
|
||||
// Number of live variables in function scope
|
||||
unsigned m_numLiveVars;
|
||||
// Number of nested for loops for loop index referencing
|
||||
unsigned m_numNestedForLoops;
|
||||
std::stack<bool> m_inForScope;
|
||||
// Set that is used for deduplicating switch case literals
|
||||
std::stack<std::set<dev::u256>> m_switchLiteralSetPerScope;
|
||||
// Total number of function sets. A function set contains one function of each type defined by
|
||||
@ -146,6 +145,12 @@ private:
|
||||
// mod input/output parameters impose an upper bound on the number of input/output parameters a function may have.
|
||||
static unsigned constexpr modInputParams = 5;
|
||||
static unsigned constexpr modOutputParams = 5;
|
||||
// predicate to keep track of for body scope
|
||||
bool m_inForBodyScope;
|
||||
// Index used for naming loop variable of bounded for loops
|
||||
unsigned m_numNestedForLoops;
|
||||
// predicate to keep track of for loop init scope
|
||||
bool m_inForInitScope;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -256,8 +256,15 @@ message IfStmt {
|
||||
required Block if_body = 2;
|
||||
}
|
||||
|
||||
message BoundedForStmt {
|
||||
required Block for_body = 1;
|
||||
}
|
||||
|
||||
message ForStmt {
|
||||
required Block for_body = 1;
|
||||
required Block for_init = 2;
|
||||
required Block for_post = 3;
|
||||
required Expression for_cond = 4;
|
||||
}
|
||||
|
||||
message CaseStmt {
|
||||
@ -324,6 +331,7 @@ message Statement {
|
||||
ExtCodeCopy extcode_copy = 12;
|
||||
TerminatingStmt terminatestmt = 13;
|
||||
FunctionCall functioncall = 14;
|
||||
BoundedForStmt boundedforstmt = 15;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user