Skip to content

Commit

Permalink
[PCompiler] Correct foreach -> while transformation (#684)
Browse files Browse the repository at this point in the history
* [PCompiler] Correct foreach -> while transformation to account for continue in loop body

* [Tst] Adds more regression tests for foreach with break/continue

* [Tst] Minor commments

* [Tst] Exclude unsupported tests from PSym regression suite
  • Loading branch information
aman-goel authored Nov 27, 2023
1 parent 2f3eff7 commit 19f9e97
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1435,7 +1435,7 @@ private void WriteExpr(CompilationContext context, StringWriter output, IPExpr p
break;

case IntLiteralExpr intLiteralExpr:
context.Write(output, $"((PrtInt){intLiteralExpr.Value})");
context.Write(output, $"((PrtInt)({intLiteralExpr.Value}))");
break;

case KeysExpr keysExpr:
Expand Down
34 changes: 19 additions & 15 deletions Src/PCompiler/CompilerCore/Backend/IRTransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -581,12 +581,12 @@ private IPStmt SimplifyForeachStmt(ForeachStmt foreachStmt)
// collectionCopy = collection;
// var i: int;
// var sizeof: int;
// i = 0;
// i = -1;
// sizeof = sizeof(collectionCopy);
// while(i < sizeof) {
// while(i < (sizeof - 1)) {
// i = i + 1;
// item = collectionCopy[i];
// body;
// i = i + 1;
// }

var location = foreachStmt.SourceLocation;
Expand All @@ -608,14 +608,25 @@ private IPStmt SimplifyForeachStmt(ForeachStmt foreachStmt)
sizeVar.Type = PrimitiveType.Int;
function.AddLocalVariable(sizeVar);

// i = 0;
newBody.Add(new AssignStmt(location, new VariableAccessExpr(location, iVar), new IntLiteralExpr(location, 0)));
// i = -1;
newBody.Add(new AssignStmt(location, new VariableAccessExpr(location, iVar), new IntLiteralExpr(location, -1)));

// sizeof = sizeof(collection)
newBody.Add(new AssignStmt(location, new VariableAccessExpr(location, sizeVar), new SizeofExpr(location, collectionCopy)));

// while(i < sizeof)
IPExpr cond = new BinOpExpr(location, BinOpType.Lt, new VariableAccessExpr(location, iVar), new VariableAccessExpr(location, sizeVar));
// while(i < (sizeof - 1))
IPExpr cond = new BinOpExpr(location, BinOpType.Lt,
new VariableAccessExpr(location, iVar),
new BinOpExpr(location, BinOpType.Sub,
new VariableAccessExpr(location, sizeVar),
new IntLiteralExpr(location, 1)));

// inside loop: i = i+1;
IPStmt incrementI = new AssignStmt(location, new VariableAccessExpr(location, iVar),
new BinOpExpr(location,
BinOpType.Add,
new VariableAccessExpr(location, iVar),
new IntLiteralExpr(location, 1)));

// inside loop: item = collection[i]
IPExpr accessExpr;
Expand All @@ -634,14 +645,7 @@ private IPStmt SimplifyForeachStmt(ForeachStmt foreachStmt)
}
IPStmt assignItem = new AssignStmt(location, new VariableAccessExpr(location, item), accessExpr);

// inside loop: i = i+1;
IPStmt incrementI = new AssignStmt(location, new VariableAccessExpr(location, iVar),
new BinOpExpr(location,
BinOpType.Add,
new VariableAccessExpr(location, iVar),
new IntLiteralExpr(location, 1)));

newBody.Add(new WhileStmt(location, cond, new CompoundStmt(location, new List<IPStmt>{ assignItem, body, incrementI })));
newBody.Add(new WhileStmt(location, cond, new CompoundStmt(location, new List<IPStmt>{ incrementI, assignItem, body })));
return new CompoundStmt(location, newBody);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ private static void createExcludeList() {
excluded.add("../../../Tst/RegressionTests/Feature2Stmts/DynamicError/receive7");

// TODO Unsupported: continue statement
excluded.add("../../../Tst/RegressionTests/Feature2Stmts/Correct/foreach2");
excluded.add("../../../Tst/RegressionTests/Feature2Stmts/Correct/foreach4");
excluded.add("../../../Tst/RegressionTests/Feature2Stmts/DynamicError/foreach2");
excluded.add("../../../Tst/RegressionTests/Feature2Stmts/DynamicError/foreach4");
excluded.add("../../../Tst/RegressionTests/Feature2Stmts/DynamicError/continue1");

// TODO Unsupported: receive in state exit functions
Expand Down
32 changes: 32 additions & 0 deletions Tst/RegressionTests/Feature2Stmts/Correct/foreach2/foreach2.p
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/********************
* This example explains the usage of foreach iterator with continue
* ******************/


machine Main {
var ss: set[int];

start state Init {
entry {
var iter: int;
var sum: int;
ss += (100);
ss += (134);
ss += (245);

foreach(iter in ss)
{
print format ("Iter = {0}, Sum = {1}", iter, sum);
assert sum <= 345, "Incorrect sum inside loop";
if (iter == 134) {
continue;
}
sum = sum + iter;
}

print format ("Final Sum = {0}", sum);
assert sum == 345, "Incorrect sum outside loop";
}
}
}

33 changes: 33 additions & 0 deletions Tst/RegressionTests/Feature2Stmts/Correct/foreach3/foreach3.p
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/********************
* This example explains the usage of foreach iterator with break
* ******************/


machine Main {
var ss: set[int];

start state Init {
entry {
var iter: int;
var sum: int;
ss += (100);
ss += (123);
ss += (134);
ss += (245);

foreach(iter in ss)
{
print format ("Iter = {0}, Sum = {1}", iter, sum);
assert sum <= 100, "Incorrect sum inside loop";
sum = sum + iter;
if (iter == 123) {
break;
}
}

print format ("Final Sum = {0}", sum);
assert sum == 223, "Incorrect sum outside loop";
}
}
}

36 changes: 36 additions & 0 deletions Tst/RegressionTests/Feature2Stmts/Correct/foreach4/foreach4.p
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/********************
* This example explains the usage of foreach iterator with break and continue
* ******************/


machine Main {
var ss: set[int];

start state Init {
entry {
var iter: int;
var sum: int;
ss += (100);
ss += (134);
ss += (123);
ss += (245);

foreach(iter in ss)
{
print format ("Iter = {0}, Sum = {1}", iter, sum);
assert sum <= 100, "Incorrect sum inside loop";
if (iter == 134) {
continue;
}
sum = sum + iter;
if (iter == 123) {
break;
}
}

print format ("Final Sum = {0}", sum);
assert sum == 223, "Incorrect sum outside loop";
}
}
}

32 changes: 32 additions & 0 deletions Tst/RegressionTests/Feature2Stmts/DynamicError/foreach2/foreach2.p
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/********************
* This example explains the usage of foreach iterator with continue
* ******************/


machine Main {
var ss: set[int];

start state Init {
entry {
var iter: int;
var sum: int;
ss += (100);
ss += (134);
ss += (245);

foreach(iter in ss)
{
print format ("Iter = {0}, Sum = {1}", iter, sum);
assert sum <= 345, "Incorrect sum inside loop";
if (iter == 134) {
continue;
}
sum = sum + iter;
}

print format ("Final Sum = {0}", sum);
assert sum != 345, "Should get triggered";
}
}
}

33 changes: 33 additions & 0 deletions Tst/RegressionTests/Feature2Stmts/DynamicError/foreach3/foreach3.p
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/********************
* This example explains the usage of foreach iterator with break
* ******************/


machine Main {
var ss: set[int];

start state Init {
entry {
var iter: int;
var sum: int;
ss += (100);
ss += (123);
ss += (134);
ss += (245);

foreach(iter in ss)
{
print format ("Iter = {0}, Sum = {1}", iter, sum);
assert sum <= 100, "Incorrect sum inside loop";
sum = sum + iter;
if (iter == 123) {
break;
}
}

print format ("Final Sum = {0}", sum);
assert sum != 223, "Should get triggered";
}
}
}

36 changes: 36 additions & 0 deletions Tst/RegressionTests/Feature2Stmts/DynamicError/foreach4/foreach4.p
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/********************
* This example explains the usage of foreach iterator with break and continue
* ******************/


machine Main {
var ss: set[int];

start state Init {
entry {
var iter: int;
var sum: int;
ss += (100);
ss += (134);
ss += (123);
ss += (245);

foreach(iter in ss)
{
print format ("Iter = {0}, Sum = {1}", iter, sum);
assert sum <= 100, "Incorrect sum inside loop";
if (iter == 134) {
continue;
}
sum = sum + iter;
if (iter == 123) {
break;
}
}

print format ("Final Sum = {0}", sum);
assert sum != 223, "Should get triggered";
}
}
}

0 comments on commit 19f9e97

Please sign in to comment.