Skip to content

Commit d382513

Browse files
authored
Merge pull request #704 from viperproject/meilers_seqn_scopes
Fix scope (Seqn) handling in parser and pretty-printer
2 parents c112143 + e70c8b1 commit d382513

10 files changed

Lines changed: 229 additions & 86 deletions

File tree

src/main/scala/viper/silver/ast/pretty/PrettyPrinter.scala

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -541,10 +541,7 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter
541541
case None =>
542542
nil
543543
case Some(actualBody) =>
544-
braces(nest(defaultIndent,
545-
lineIfSomeNonEmpty(actualBody.children) <>
546-
ssep(Seq(showStmt(actualBody)), line)
547-
) <> line)
544+
showBlock(actualBody)
548545
})
549546
case Predicate(name, formalArgs, body) =>
550547
text("predicate") <+> name <> nest(defaultIndent, parens(showVars(formalArgs))) <+> (body match {
@@ -634,11 +631,20 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter
634631
}
635632

636633
/** Show some node inside square braces (with nesting). */
637-
def showBlock(stmt: Stmt): Cont = {
638-
braces(nest(defaultIndent,
639-
lineIfSomeNonEmpty(stmt match {case s: Seqn => s.scopedDecls; case _ => Seq()}, stmt.children) <>
640-
showStmt(stmt)
641-
) <> line)
634+
def showBlock(stmt: Stmt): Cont = stmt match {
635+
case Seqn(stmts, scopedDecls) =>
636+
val locals = scopedDecls.collect { case l: LocalVarDecl => l }
637+
val nonEmptyStmts = stmts.filter {
638+
case s@Seqn(ss, sd) => ss.nonEmpty || sd.nonEmpty || s.info.comment.nonEmpty
639+
case _ => true
640+
}
641+
braces(nest(defaultIndent,
642+
lineIfSomeNonEmpty(scopedDecls, nonEmptyStmts) <>
643+
ssep((locals map (text("var") <+> showVar(_))) ++ (nonEmptyStmts map show), line)) <> line)
644+
case s =>
645+
braces(nest(defaultIndent,
646+
line <> showStmt(s)
647+
))
642648
}
643649

644650
/** Show a statement. */
@@ -662,6 +668,19 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter
662668
case Nil => call
663669
case _ => ssep(targets map show, char(',') <> space) <+> ":=" <+> call
664670
}
671+
case Seqn(stmts, scopedDecls) if scopedDecls.nonEmpty =>
672+
val locals = scopedDecls.collect {case l: LocalVarDecl => l}
673+
val nonEmptyStmts = stmts.filter{
674+
case s@Seqn(ss, sd) => ss.nonEmpty || sd.nonEmpty || s.info.comment.nonEmpty
675+
case _ => true
676+
}
677+
if (stmts.isEmpty && locals.isEmpty)
678+
nil
679+
else {
680+
braces(nest(defaultIndent,
681+
lineIfSomeNonEmpty(scopedDecls, stmts) <>
682+
ssep((locals map (text("var") <+> showVar(_))) ++ (nonEmptyStmts map show), line)) <> line)
683+
}
665684
case seqn@Seqn(stmts, scopedDecls) =>
666685
val locals = scopedDecls.collect {case l: LocalVarDecl => l}
667686
if (stmts.isEmpty && locals.isEmpty && seqn.info.comment.isEmpty)
@@ -677,10 +696,7 @@ object FastPrettyPrinter extends FastPrettyPrinterBase with BracketPrettyPrinter
677696
nest(defaultIndent,
678697
showContracts("invariant", invs)
679698
) <+> lineIfSomeNonEmpty(invs) <>
680-
braces(nest(defaultIndent,
681-
lineIfSomeNonEmpty(body.scopedDecls, body.children) <>
682-
ssep(Seq(showStmt(body)), line)
683-
) <> line)
699+
showBlock(body)
684700
case If(cond, thn, els) =>
685701
text("if") <+> parens(show(cond)) <+> showBlock(thn) <> showElse(els)
686702
case Label(name, invs) =>

src/main/scala/viper/silver/parser/FastParser.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -495,17 +495,20 @@ class FastParser {
495495
})
496496

497497
def linearizeMethod(method: PMethod): PMethod = {
498-
def linearizeSeqOfNestedStmt(pseqn: PSeqn): Seq[PStmt] = {
498+
def linearizeSeqOfNestedStmt(ss: Seq[PStmt]): Seq[PStmt] = {
499499
var stmts = Seq.empty[PStmt]
500-
pseqn.ss.foreach {
501-
case s: PSeqn => stmts = stmts ++ linearizeSeqOfNestedStmt(s)
500+
ss.foreach {
501+
case s: PMacroSeqn => stmts = stmts ++ linearizeSeqOfNestedStmt(s.ss)
502+
case s@PSeqn(ss) => stmts = stmts :+ PSeqn(linearizeSeqOfNestedStmt(ss))(s.pos)
503+
case i@PIf(cond, t@PSeqn(thn), e@PSeqn(els)) => stmts = stmts :+ PIf(cond, PSeqn(linearizeSeqOfNestedStmt(thn))(t.pos), PSeqn(linearizeSeqOfNestedStmt(els))(e.pos))(i.pos)
504+
case w@PWhile(cond, invs, b@PSeqn(body)) => stmts = stmts :+ PWhile(cond, invs, PSeqn(linearizeSeqOfNestedStmt(body))(b.pos))(w.pos)
502505
case v => stmts = stmts :+ v
503506
}
504507
stmts
505508
}
506509

507510
val body = method.body match {
508-
case Some(s: PSeqn) => Some(PSeqn(linearizeSeqOfNestedStmt(s))(method.pos))
511+
case Some(s: PSeqn) => Some(PSeqn(linearizeSeqOfNestedStmt(s.ss))(method.pos))
509512
case v => v
510513
}
511514

@@ -678,7 +681,10 @@ class FastParser {
678681
def replacerOnBody(body: PNode, paramToArgMap: Map[String, PExp], pos: (Position, Position)): PNode = {
679682

680683
// Duplicate the body of the macro to allow for differing type checks depending on the context
681-
val replicatedBody = body.deepCopyAll
684+
val replicatedBody = body.deepCopyAll match {
685+
case s@PSeqn(ss) => PMacroSeqn(ss)(s.pos)
686+
case b => b
687+
}
682688

683689
// Rename locally bound variables in macro's body
684690
var bodyWithRenamedVars = renamer.execute[PNode](replicatedBody)

src/main/scala/viper/silver/parser/ParseAst.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,14 @@ case class PAnnotatedStmt(stmt: PStmt, annotation: (String, Seq[String]))(val po
12151215

12161216
case class PSeqn(ss: Seq[PStmt])(val pos: (Position, Position)) extends PStmt with PScope
12171217

1218+
/**
1219+
* PSeqn representing the expanded body of a statement macro.
1220+
* Unlike a normal PSeqn, it does not represent its own scope.
1221+
* Is created only temporarily during macro expansion and eliminated (i.e., expanded into the surrounding scope)
1222+
* before translation.
1223+
*/
1224+
case class PMacroSeqn(ss: Seq[PStmt])(val pos: (Position, Position)) extends PStmt
1225+
12181226
case class PFold(e: PExp)(val pos: (Position, Position)) extends PStmt
12191227

12201228
case class PUnfold(e: PExp)(val pos: (Position, Position)) extends PStmt
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Any copyright is dedicated to the Public Domain.
2+
// http://creativecommons.org/publicdomain/zero/1.0/
3+
4+
5+
method main1(b: Bool)
6+
{
7+
if (b) {
8+
var x: Int
9+
x := 45
10+
assert x > 34
11+
}
12+
{
13+
var x: Int
14+
x := 45
15+
assert x > 34
16+
}
17+
}
18+
19+
method main2(b: Bool)
20+
{
21+
if (b) {
22+
//:: ExpectedOutput(consistency.error)
23+
var x: Int
24+
x := 45
25+
assert x > 34
26+
}
27+
28+
var x: Int
29+
x := 45
30+
assert x > 34
31+
32+
}

src/test/resources/transformations/Macros/Hygienic/collision2Ref.vpr

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,11 @@ define macro2(x, y) {
1212

1313
method main()
1414
{
15-
{
16-
var x: Bool
17-
x := true
18-
assert((true && true) && x)
19-
}
20-
{
21-
var x$0: Bool
22-
x$0 := true
23-
assert((true && true) && x$0)
24-
}
15+
var x: Bool
16+
x := true
17+
assert((true && true) && x)
18+
19+
var x$0: Bool
20+
x$0 := true
21+
assert((true && true) && x$0)
2522
}

src/test/resources/transformations/Macros/Hygienic/collisionRef.vpr

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,11 @@ function x$3() : Bool {
1616

1717
method main()
1818
{
19-
{
20-
var x: Bool
21-
x := true
22-
assert(x)
23-
}
24-
{
25-
var x$2: Bool
26-
x$2 := true
27-
assert(x$2)
28-
}
19+
var x: Bool
20+
x := true
21+
assert(x)
22+
23+
var x$2: Bool
24+
x$2 := true
25+
assert(x$2)
2926
}

src/test/resources/transformations/Macros/Hygienic/loopConstructionRef.vpr

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,32 @@ method main()
55
{
66
var value:Int
77
value := 0
8-
{
9-
var oldX: Int
10-
var ctr: Int
11-
oldX := value
12-
ctr := 0
13-
label loop invariant ctr < 5 && value == oldX + ctr
14-
value := value + 1
15-
ctr := ctr + 1
16-
if(ctr < 5) {
17-
goto loop
18-
}
19-
assert(ctr == 5)
20-
assert(oldX + 5 == value)
8+
9+
var oldX: Int
10+
var ctr: Int
11+
oldX := value
12+
ctr := 0
13+
label loop invariant ctr < 5 && value == oldX + ctr
14+
value := value + 1
15+
ctr := ctr + 1
16+
if(ctr < 5) {
17+
goto loop
2118
}
22-
{
23-
var oldX$0: Int
24-
var ctr$0: Int
25-
oldX$0 := value
26-
ctr$0 := 0
27-
label loop$0 invariant ctr$0 < 5 && value == oldX$0 + ctr$0
28-
value := value + 1
29-
ctr$0 := ctr$0 + 1
30-
if(ctr$0 < 5) {
31-
goto loop$0
32-
}
33-
assert(ctr$0 == 5)
34-
assert(oldX$0 + 5 == value)
19+
assert(ctr == 5)
20+
assert(oldX + 5 == value)
21+
22+
var oldX$0: Int
23+
var ctr$0: Int
24+
oldX$0 := value
25+
ctr$0 := 0
26+
label loop$0 invariant ctr$0 < 5 && value == oldX$0 + ctr$0
27+
value := value + 1
28+
ctr$0 := ctr$0 + 1
29+
if(ctr$0 < 5) {
30+
goto loop$0
3531
}
32+
assert(ctr$0 == 5)
33+
assert(oldX$0 + 5 == value)
34+
3635
assert(value == 10)
3736
}

src/test/resources/transformations/Macros/Hygienic/nestedRef.vpr

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,11 @@ define macro2(y) {
1313

1414
method main()
1515
{
16-
{
17-
var x: Bool := true
18-
{
19-
var x$0: Bool := false
20-
assert(x || x$0)
21-
}
22-
}
23-
{
24-
var x$1: Bool := true
25-
{
26-
var x$2: Bool := false
27-
assert(x$1 || x$2)
28-
}
29-
}
16+
var x: Bool := true
17+
var x$0: Bool := false
18+
assert(x || x$0)
19+
20+
var x$1: Bool := true
21+
var x$2: Bool := false
22+
assert(x$1 || x$2)
3023
}

src/test/resources/transformations/Macros/Hygienic/simpleRef.vpr

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@ define macro {
88

99
method main()
1010
{
11-
{
12-
var x: Bool := true
13-
assert(x)
14-
}
15-
{
16-
var x$0: Bool := true
17-
assert(x$0)
18-
}
11+
var x: Bool := true
12+
assert(x)
13+
14+
var x$0: Bool := true
15+
assert(x$0)
1916
}

0 commit comments

Comments
 (0)