mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Sol -> Yul] Fix ForLoops and implement WhileLoops
This commit is contained in:
parent
f61348728c
commit
0abe00d393
@ -152,27 +152,28 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRGeneratorForStatements::visit(ForStatement const& _for)
|
bool IRGeneratorForStatements::visit(ForStatement const& _forStatement)
|
||||||
{
|
{
|
||||||
m_code << "for {\n";
|
generateLoop(
|
||||||
if (_for.initializationExpression())
|
_forStatement.body(),
|
||||||
_for.initializationExpression()->accept(*this);
|
_forStatement.condition(),
|
||||||
m_code << "} return_flag {\n";
|
_forStatement.initializationExpression(),
|
||||||
if (_for.loopExpression())
|
_forStatement.loopExpression()
|
||||||
_for.loopExpression()->accept(*this);
|
);
|
||||||
m_code << "}\n";
|
|
||||||
if (_for.condition())
|
return false;
|
||||||
{
|
|
||||||
_for.condition()->accept(*this);
|
|
||||||
m_code <<
|
|
||||||
"if iszero(" <<
|
|
||||||
expressionAsType(*_for.condition(), *TypeProvider::boolean()) <<
|
|
||||||
") { break }\n";
|
|
||||||
}
|
}
|
||||||
_for.body().accept(*this);
|
|
||||||
m_code << "}\n";
|
bool IRGeneratorForStatements::visit(WhileStatement const& _whileStatement)
|
||||||
// Bubble up the return condition.
|
{
|
||||||
m_code << "if iszero(return_flag) { break }\n";
|
generateLoop(
|
||||||
|
_whileStatement.body(),
|
||||||
|
&_whileStatement.condition(),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
_whileStatement.isDoWhile()
|
||||||
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,6 +797,54 @@ void IRGeneratorForStatements::setLValue(Expression const& _expression, unique_p
|
|||||||
defineExpression(_expression) << _lvalue->retrieveValue() << "\n";
|
defineExpression(_expression) << _lvalue->retrieveValue() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IRGeneratorForStatements::generateLoop(
|
||||||
|
Statement const& _body,
|
||||||
|
Expression const* _conditionExpression,
|
||||||
|
Statement const* _initExpression,
|
||||||
|
ExpressionStatement const* _loopExpression,
|
||||||
|
bool _isDoWhile
|
||||||
|
)
|
||||||
|
{
|
||||||
|
string firstRun;
|
||||||
|
|
||||||
|
if (_isDoWhile)
|
||||||
|
{
|
||||||
|
solAssert(_conditionExpression, "Expected condition for doWhile");
|
||||||
|
firstRun = m_context.newYulVariable();
|
||||||
|
m_code << "let " << firstRun << " := 1\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
m_code << "for {\n";
|
||||||
|
if (_initExpression)
|
||||||
|
_initExpression->accept(*this);
|
||||||
|
m_code << "} return_flag {\n";
|
||||||
|
if (_loopExpression)
|
||||||
|
_loopExpression->accept(*this);
|
||||||
|
m_code << "}\n";
|
||||||
|
m_code << "{\n";
|
||||||
|
|
||||||
|
if (_conditionExpression)
|
||||||
|
{
|
||||||
|
if (_isDoWhile)
|
||||||
|
m_code << "if iszero(" << firstRun << ") {\n";
|
||||||
|
|
||||||
|
_conditionExpression->accept(*this);
|
||||||
|
m_code <<
|
||||||
|
"if iszero(" <<
|
||||||
|
expressionAsType(*_conditionExpression, *TypeProvider::boolean()) <<
|
||||||
|
") { break }\n";
|
||||||
|
|
||||||
|
if (_isDoWhile)
|
||||||
|
m_code << "}\n" << firstRun << " := 0\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
_body.accept(*this);
|
||||||
|
|
||||||
|
m_code << "}\n";
|
||||||
|
// Bubble up the return condition.
|
||||||
|
m_code << "if iszero(return_flag) { break }\n";
|
||||||
|
}
|
||||||
|
|
||||||
Type const& IRGeneratorForStatements::type(Expression const& _expression)
|
Type const& IRGeneratorForStatements::type(Expression const& _expression)
|
||||||
{
|
{
|
||||||
solAssert(_expression.annotation().type, "Type of expression not set.");
|
solAssert(_expression.annotation().type, "Type of expression not set.");
|
||||||
|
@ -49,6 +49,7 @@ public:
|
|||||||
bool visit(Assignment const& _assignment) override;
|
bool visit(Assignment const& _assignment) override;
|
||||||
bool visit(TupleExpression const& _tuple) override;
|
bool visit(TupleExpression const& _tuple) override;
|
||||||
bool visit(ForStatement const& _forStatement) override;
|
bool visit(ForStatement const& _forStatement) override;
|
||||||
|
bool visit(WhileStatement const& _whileStatement) override;
|
||||||
bool visit(Continue const& _continueStatement) override;
|
bool visit(Continue const& _continueStatement) override;
|
||||||
bool visit(Break const& _breakStatement) override;
|
bool visit(Break const& _breakStatement) override;
|
||||||
void endVisit(Return const& _return) override;
|
void endVisit(Return const& _return) override;
|
||||||
@ -70,6 +71,13 @@ private:
|
|||||||
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
|
void appendAndOrOperatorCode(BinaryOperation const& _binOp);
|
||||||
|
|
||||||
void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue);
|
void setLValue(Expression const& _expression, std::unique_ptr<IRLValue> _lvalue);
|
||||||
|
void generateLoop(
|
||||||
|
Statement const& _body,
|
||||||
|
Expression const* _conditionExpression,
|
||||||
|
Statement const* _initExpression = nullptr,
|
||||||
|
ExpressionStatement const* _loopExpression = nullptr,
|
||||||
|
bool _isDoWhile = false
|
||||||
|
);
|
||||||
|
|
||||||
static Type const& type(Expression const& _expression);
|
static Type const& type(Expression const& _expression);
|
||||||
|
|
||||||
|
31
test/libsolidity/semanticTests/viaYul/loops/break.sol
Normal file
31
test/libsolidity/semanticTests/viaYul/loops/break.sol
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
for (uint a = 0; a < 10; a = a + 1) {
|
||||||
|
x = x + x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function g() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
uint a = 0;
|
||||||
|
while (a < 10) {
|
||||||
|
x = x + x;
|
||||||
|
break;
|
||||||
|
a = a + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function h() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
do {
|
||||||
|
x = x + 1;
|
||||||
|
break;
|
||||||
|
} while (x < 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: true
|
||||||
|
// ----
|
||||||
|
// f() -> 2
|
||||||
|
// g() -> 2
|
||||||
|
// h() -> 2
|
37
test/libsolidity/semanticTests/viaYul/loops/continue.sol
Normal file
37
test/libsolidity/semanticTests/viaYul/loops/continue.sol
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
uint a = 0;
|
||||||
|
for (; a < 10; a = a + 1) {
|
||||||
|
continue;
|
||||||
|
x = x + x;
|
||||||
|
}
|
||||||
|
x = x + a;
|
||||||
|
}
|
||||||
|
function g() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
uint a = 0;
|
||||||
|
while (a < 10) {
|
||||||
|
a = a + 1;
|
||||||
|
continue;
|
||||||
|
x = x + x;
|
||||||
|
}
|
||||||
|
x = x + a;
|
||||||
|
}
|
||||||
|
function h() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
uint a = 0;
|
||||||
|
do {
|
||||||
|
a = a + 1;
|
||||||
|
continue;
|
||||||
|
x = x + x;
|
||||||
|
} while (a < 4);
|
||||||
|
x = x + a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: true
|
||||||
|
// ----
|
||||||
|
// f() -> 11
|
||||||
|
// g() -> 11
|
||||||
|
// h() -> 5
|
34
test/libsolidity/semanticTests/viaYul/loops/return.sol
Normal file
34
test/libsolidity/semanticTests/viaYul/loops/return.sol
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
uint a;
|
||||||
|
for (; a < 10; a = a + 1) {
|
||||||
|
return x;
|
||||||
|
x = x + x;
|
||||||
|
}
|
||||||
|
x = x + a;
|
||||||
|
}
|
||||||
|
function g() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
uint a;
|
||||||
|
while (a < 10) {
|
||||||
|
return x;
|
||||||
|
x = x + x;
|
||||||
|
a = a + 1;
|
||||||
|
}
|
||||||
|
x = x + a;
|
||||||
|
}
|
||||||
|
function h() public returns (uint x) {
|
||||||
|
x = 1;
|
||||||
|
do {
|
||||||
|
x = x + 1;
|
||||||
|
return x;
|
||||||
|
} while (x < 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: true
|
||||||
|
// ----
|
||||||
|
// f() -> 1
|
||||||
|
// g() -> 1
|
||||||
|
// h() -> 2
|
@ -7,34 +7,33 @@ contract C {
|
|||||||
}
|
}
|
||||||
function g() public returns (uint x) {
|
function g() public returns (uint x) {
|
||||||
x = 1;
|
x = 1;
|
||||||
for (uint a = 0; a < 10; a = a + 1) {
|
uint a = 0;
|
||||||
|
while (a < 10) {
|
||||||
x = x + x;
|
x = x + x;
|
||||||
break;
|
a = a + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function h() public returns (uint x) {
|
function h() public returns (uint x) {
|
||||||
x = 1;
|
x = 1;
|
||||||
uint a = 0;
|
do {
|
||||||
for (; a < 10; a = a + 1) {
|
x = x + 1;
|
||||||
continue;
|
} while (false);
|
||||||
x = x + x;
|
|
||||||
}
|
|
||||||
x = x + a;
|
|
||||||
}
|
}
|
||||||
function i() public returns (uint x) {
|
function i() public returns (uint x) {
|
||||||
x = 1;
|
x = 1;
|
||||||
uint a;
|
do {
|
||||||
for (; a < 10; a = a + 1) {
|
x = x + 1;
|
||||||
return x;
|
} while (x < 3);
|
||||||
x = x + x;
|
|
||||||
}
|
}
|
||||||
x = x + a;
|
function j() public {
|
||||||
|
for (;;) {break;}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ===
|
// ====
|
||||||
// compileViaYul: true
|
// compileViaYul: true
|
||||||
// ----
|
// ----
|
||||||
// f() -> 1024
|
// f() -> 1024
|
||||||
// g() -> 2
|
// g() -> 1024
|
||||||
// h() -> 11
|
// h() -> 2
|
||||||
// i() -> 1
|
// i() -> 3
|
||||||
|
// j() ->
|
Loading…
Reference in New Issue
Block a user