Skip to content

Commit a5a8050

Browse files
committed
Tests pass
1 parent cb50467 commit a5a8050

38 files changed

Lines changed: 1152 additions & 1083 deletions

src/main/scala/viper/silver/ast/Program.scala

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -214,18 +214,20 @@ case class Program(domains: Seq[Domain], fields: Seq[Field], functions: Seq[Func
214214
}
215215

216216
def checkNamesInScope(currentScope: Scope, dMap: immutable.HashMap[String, Declaration]) : Seq[ConsistencyError] = {
217-
var declarationMap = dMap
217+
var newMap = immutable.HashMap.empty[String, Declaration]
218218
var s: Seq[ConsistencyError] = Seq.empty[ConsistencyError]
219219
//check name declarations
220220
currentScope.scopedDecls.foreach(l=> {
221221
if(!Consistency.validUserDefinedIdentifier(l.name))
222222
s :+= ConsistencyError(s"${l.name} is not a valid identifier.", l.pos)
223223

224-
declarationMap.get(l.name) match {
225-
case Some(_: Declaration) => s :+= ConsistencyError(s"Duplicate identifier ${l.name} found.", l.pos)
226-
case None => declarationMap += (l.name -> l)
224+
newMap.get(l.name) match {
225+
case Some(_: Declaration) => s :+= ConsistencyError(s"Duplicate identifier `${l.name}` found.", l.pos)
226+
case None => newMap += (l.name -> l)
227227
}
228228
})
229+
// Override duplicate keys in old map
230+
val declarationMap = dMap ++ newMap
229231

230232
//check name uses
231233
Visitor.visitOpt(currentScope.asInstanceOf[Node], Nodes.subnodes){ n => {
@@ -409,11 +411,13 @@ case class Method(name: String, formalArgs: Seq[LocalVarDecl], formalReturns: Se
409411
}
410412

411413
def deepCollectInBody[A](f: PartialFunction[Node, A]): Seq[A] = body match {
414+
case null => Nil
415+
case None => Nil
412416
case Some(actualBody) => actualBody.deepCollect(f)
413-
case None => Seq()
414417
}
415418

416-
val scopedDecls: Seq[Declaration] = formalArgs ++ formalReturns
419+
def labels: Seq[Label] = deepCollectInBody { case l: Label => l }
420+
val scopedDecls: Seq[Declaration] = formalArgs ++ formalReturns ++ labels
417421

418422
override lazy val check: Seq[ConsistencyError] =
419423
pres.flatMap(Consistency.checkPre) ++
@@ -444,19 +448,6 @@ case class Method(name: String, formalArgs: Seq[LocalVarDecl], formalReturns: Se
444448
def toCfg(simplify: Boolean = true, detect: Boolean = true): SilverCfg = CfgGenerator.methodToCfg(this, simplify, detect)
445449
}
446450

447-
object MethodWithLabelsInScope {
448-
def apply(name: String, formalArgs: Seq[LocalVarDecl], formalReturns: Seq[LocalVarDecl], pres: Seq[Exp], posts: Seq[Exp], body: Option[Seqn])
449-
(pos: Position = NoPosition, info: Info = NoInfo, errT: ErrorTrafo = NoTrafos): Method = {
450-
val newBody = body match {
451-
case Some(actualBody) =>
452-
val newScopedDecls = actualBody.scopedSeqnDeclarations ++ actualBody.deepCollect({case l: Label => l})
453-
Some(actualBody.copy(scopedSeqnDeclarations = newScopedDecls)(actualBody.pos, actualBody.info, actualBody.errT))
454-
case _ => body
455-
}
456-
Method(name, formalArgs, formalReturns, pres, posts, newBody)(pos, info, errT)
457-
}
458-
}
459-
460451
/** A function declaration */
461452
case class Function(name: String, formalArgs: Seq[LocalVarDecl], typ: Type, pres: Seq[Exp], posts: Seq[Exp], body: Option[Exp])(val pos: Position = NoPosition, val info: Info = NoInfo, val errT: ErrorTrafo = NoTrafos) extends Member with FuncLike with Contracted {
462453
override lazy val check : Seq[ConsistencyError] =

src/main/scala/viper/silver/ast/utility/QuantifiedPermissions.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ object QuantifiedPermissions {
141141
val currentRoot = toVisit.dequeue()
142142

143143
val relevantNodes: Seq[Node] = currentRoot match {
144-
case m@Method(_, _, _, pres, posts, _) if m != root =>
144+
case m: Method if m != root =>
145145
// use only specification of called methods
146-
pres ++ posts
146+
m.pres ++ m.posts
147147
case f@Function(_, _, _, pres, posts, _) if f != root =>
148148
// use only specification of called functions
149149
pres ++ posts

src/main/scala/viper/silver/ast/utility/rewriter/Rewritable.scala

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@
66

77
package viper.silver.ast.utility.rewriter
88

9-
import viper.silver.parser.Transformer.ParseTreeDuplicationError
9+
import viper.silver.parser.PNode
1010
import viper.silver.ast.{AtomicType, BackendFuncApp, DomainFuncApp, ErrorTrafo, FuncApp, Info, Node, Position}
1111

1212
import scala.reflect.runtime.{universe => reflection}
1313

14+
trait HasExtraValList {
15+
def getExtraVals: Seq[Any]
16+
}
17+
trait HasExtraVars {
18+
def copyExtraVars(from: Any): Unit
19+
}
20+
1421
/**
1522
* Trait Rewritable provides an interface that specifies which methods are required for the rewriter to work with.
1623
* For classes that implement product (especially case classes) everything is already implemented here and one only has to extend this base class
@@ -39,18 +46,23 @@ trait Rewritable extends Product {
3946
val firstArgList = children
4047
var secondArgList = Seq.empty[Any]
4148
import viper.silver.ast.{DomainType, DomainAxiom, FuncApp, DomainFunc, DomainFuncApp}
42-
import viper.silver.parser.{PAxiom, PDomainFunction, PDomainType, PNode}
4349
this match {
50+
// TODO: remove the following cases by implementing `HasExtraValList` on the respective classes
4451
case dt: DomainType => secondArgList = Seq(dt.typeParameters)
4552
case da: DomainAxiom => secondArgList = Seq(da.pos, da.info, da.domainName, da.errT)
4653
case fa: FuncApp => secondArgList = Seq(fa.pos, fa.info, fa.typ, fa.errT)
4754
case df: DomainFunc => secondArgList = Seq(df.pos, df.info, df.domainName, df.errT)
4855
case df: DomainFuncApp => secondArgList = Seq(df.pos, df.info, df.typ, df.domainName, df.errT)
4956
case ba: BackendFuncApp => secondArgList = Seq(ba.pos, ba.info, ba.typ, ba.interpretation, ba.errT)
5057
case no: Node => secondArgList = no.getMetadata
51-
case pa: PAxiom => secondArgList = Seq(pa.domainName) ++ Seq(pos.getOrElse(pa.pos))
52-
case pd: PDomainFunction => secondArgList = Seq(pd.domainName) ++ Seq(pos.getOrElse(pd.pos))
53-
case pn: PNode => secondArgList = Seq(pos.getOrElse(pn.pos))
58+
59+
case evl: HasExtraValList => {
60+
secondArgList = evl.getExtraVals.map(ev => {
61+
// Replace positions with the new one
62+
val replace = pos.isDefined && ev.isInstanceOf[(_, _)] && ev.asInstanceOf[(_, _)]._1.isInstanceOf[Position] && ev.asInstanceOf[(_, _)]._2.isInstanceOf[Position]
63+
if (replace) pos.get else ev
64+
})
65+
}
5466
case _ =>
5567
}
5668

@@ -62,9 +74,9 @@ trait Rewritable extends Product {
6274
}
6375

6476
// Copy member values, as they aren't in the parameters' list.
65-
this match {
66-
case dt: PDomainType =>
67-
newNode.asInstanceOf[PDomainType].kind = dt.kind
77+
newNode match {
78+
case ev: HasExtraVars =>
79+
ev.copyExtraVars(this)
6880
case _ =>
6981
}
7082

@@ -109,4 +121,9 @@ trait Rewritable extends Product {
109121
newNode.asInstanceOf[this.type]
110122
}
111123
}
124+
125+
def initProperties(): Unit = ()
112126
}
127+
128+
case class ParseTreeDuplicationError(original: PNode, newChildren: Seq[Any])
129+
extends RuntimeException(s"Cannot duplicate $original with new children $newChildren")

src/main/scala/viper/silver/ast/utility/rewriter/Strategy.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ class Strategy[N <: Rewritable : reflection.TypeTag : scala.reflect.ClassTag, C
356356
case Traverse.Innermost => rewriteInnermost(node, contextUsed)
357357
}
358358
changed = !(result eq node)
359+
result.initProperties()
359360
result
360361
}
361362

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

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ object FastParserCompanion {
4141
def identStarts[$: P] = CharIn("A-Z", "a-z", "$_")
4242
def identContinues[$: P] = CharIn("0-9", "A-Z", "a-z", "$_")
4343

44-
type Pos = (Position, Position)
44+
type Pos = (FilePosition, FilePosition)
4545
import scala.language.implicitConversions
4646
implicit def LeadingWhitespaceStr[$: P](p: String): LeadingWhitespace[Unit] = new LeadingWhitespace(() => P(p))
4747
implicit def LeadingWhitespace[T](p: => P[T]) = new LeadingWhitespace(() => p)
@@ -62,7 +62,7 @@ object FastParserCompanion {
6262
def ~~~[$: P, V, R](other: LW[V])(implicit s: Implicits.Sequencer[T, V, R]): P[R] = (p() ~~ other.p()).asInstanceOf[P[R]]
6363
def ~~~/[$: P, V, R](other: LW[V])(implicit s: Implicits.Sequencer[T, V, R]): P[R] = (p() ~~/ other.p()).asInstanceOf[P[R]]
6464
}
65-
class PositionParsing[T](val p: () => P[((Position, Position)) => T]) extends AnyVal {
65+
class PositionParsing[T](val p: () => P[((FilePosition, FilePosition)) => T]) extends AnyVal {
6666
def pos(implicit ctx: P[Any], lineCol: LineCol, _file: Path): P[T] = {
6767
// TODO: switch over to this?
6868
// Index ~~ p() ~~ Index map { case (start, f, end) => {
@@ -71,7 +71,7 @@ object FastParserCompanion {
7171
// f((FilePosition(_file, startPos._1, startPos._2), FilePosition(_file, finishPos._1, finishPos._2)))
7272
// }}
7373
val startPos = lineCol.getPos(ctx.index)
74-
val res: P[((Position, Position)) => T] = p()
74+
val res: P[((FilePosition, FilePosition)) => T] = p()
7575
val finishPos = lineCol.getPos(ctx.index)
7676
res.map(_((FilePosition(_file, startPos._1, startPos._2), FilePosition(_file, finishPos._1, finishPos._2))))
7777
}
@@ -286,7 +286,7 @@ class FastParser {
286286
j += 1
287287
}
288288
}
289-
PProgram(imports, macros, domains, fields, functions, predicates, methods, extensions, errors)(p.pos)
289+
PProgram(imports, macros, domains, fields, functions, predicates, methods, extensions)(p.pos, errors)
290290
}
291291

292292

@@ -304,7 +304,7 @@ class FastParser {
304304
case _ =>
305305
SourcePosition(_file, 0, 0)
306306
}
307-
PProgram(Nil, Nil, Nil, Nil, Nil, Nil, Nil, Nil, Seq(ParseError(msg, location)))((NoPosition, NoPosition))
307+
PProgram(Nil, Nil, Nil, Nil, Nil, Nil, Nil, Nil)((NoPosition, NoPosition), Seq(ParseError(msg, location)))
308308
}
309309
}
310310

@@ -517,9 +517,9 @@ class FastParser {
517517

518518
def idnuse[$: P]: P[PIdnUseExp] = P(ident map (PIdnUseExp.apply _)).pos
519519

520-
def idnref[$: P]: P[PIdnRef] = P(ident map (PIdnRef.apply _)).pos
520+
def idnref[$: P, T <: PDeclarationInner](implicit ctag: scala.reflect.ClassTag[T]): P[PIdnRef[T]] = P(ident map (PIdnRef.apply[T] _)).pos
521521

522-
def oldLabel[$: P]: P[PLabelUse] = P((P(PKw.Lhs) map (PLhsLabel.apply _)).pos | idnuse)
522+
def oldLabel[$: P]: P[Either[PKw.Lhs, PIdnRef[PLabel]]] = P((P(PKw.Lhs) map (Left(_))) | (idnref[$, PLabel] map (Right(_))))
523523

524524
def old[$: P]: P[PKwOp.Old => Pos => POldExp] = P(oldLabel.brackets.? ~ exp.parens).map {
525525
case (lbl, g) => POldExp(_, lbl, g)
@@ -560,7 +560,7 @@ class FastParser {
560560
=> SuffixedExpressionGenerator[PExp](e0 => PLookup(e0, l, e1, r)(e0.pos._1, pos._2)) })
561561

562562
def fieldAccess[$: P]: P[SuffixedExpressionGenerator[PExp]] =
563-
P(((!P(PSymOp.DotDot) ~~ PSymOp.Dot) ~ idnref) map { case (dot, id) => pos: Pos => SuffixedExpressionGenerator[PExp](e => PFieldAccess(e, dot, id)(e.pos._1, pos._2)) }).pos
563+
P(((!P(PSymOp.DotDot) ~~ PSymOp.Dot) ~ idnref[$, PFieldDecl]) map { case (dot, id) => pos: Pos => SuffixedExpressionGenerator[PExp](e => PFieldAccess(e, dot, id)(e.pos._1, pos._2)) }).pos
564564

565565
def sliceEnd[$: P]: P[((PSymOp.LBracket, PSymOp.RBracket)) => Pos => SuffixedExpressionGenerator[PExp]] =
566566
P((P(PSymOp.DotDot) ~ exp).map { case (d, n) => b => pos: Pos
@@ -617,9 +617,9 @@ class FastParser {
617617

618618
def chainComp(op: PReserved[PBinaryOp], right: PExp)(pos: Pos)(from: PExp) = SuffixedExpressionGenerator(_ match {
619619
case left@PBinExp(_, op0, middle) if cmpOps.contains(op0.rs.token) && left != from =>
620-
PBinExp(left, PReserved(PSymOp.AndAnd)(NoPosition, NoPosition), PBinExp(middle, op, right)(middle.pos._1, pos._2))(left.pos._1, pos._2)
620+
PBinExp(left, PReserved(PSymOp.AndAnd)(NoPosition, NoPosition), PBinExp(middle.deepCopyAll.asInstanceOf[PExp], op, right)(middle.pos._1, pos._2))(left.pos._1, pos._2)
621621
case left@PBinExp(_, PReserved(PSymOp.AndAnd), PBinExp(_, op0, middle)) if cmpOps.contains(op0.rs.token) && left != from =>
622-
PBinExp(left, PReserved(PSymOp.AndAnd)(NoPosition, NoPosition), PBinExp(middle, op, right)(middle.pos._1, pos._2))(left.pos._1, pos._2)
622+
PBinExp(left, PReserved(PSymOp.AndAnd)(NoPosition, NoPosition), PBinExp(middle.deepCopyAll.asInstanceOf[PExp], op, right)(middle.pos._1, pos._2))(left.pos._1, pos._2)
623623
case left => PBinExp(left, op, right)(left.pos._1, pos._2)
624624
})
625625

@@ -674,11 +674,7 @@ class FastParser {
674674
P(idndef ~ PSymOp.EqEq ~ parenthesizedExp ~ PKwOp.In ~ exp).map {
675675
case (id, eq, exp1, in, exp2) =>
676676
val nestedScope = PLetNestedScope(exp2)(exp2.pos)
677-
k => pos => {
678-
val let = PLet(k, id, eq, exp1, in, nestedScope)(pos)
679-
nestedScope.outerLet = let
680-
let
681-
}
677+
k => PLet(k, id, eq, exp1, in, nestedScope)(_)
682678
}
683679

684680
def idndef[$: P]: P[PIdnDef] = P(ident map (PIdnDef.apply _)).pos
@@ -717,7 +713,7 @@ class FastParser {
717713

718714
def typ[$: P]: P[PType] = P(typReservedKw | domainTyp | macroType)
719715

720-
def domainTyp[$: P]: P[PDomainType] = P((idnref ~~~ typeList(typ).lw.?) map (PDomainType.apply _).tupled).pos
716+
def domainTyp[$: P]: P[PDomainType] = P((idnref[$, PTypeDeclaration] ~~~ typeList(typ).lw.?) map (PDomainType.apply _).tupled).pos
721717

722718
def seqType[$: P]: P[PKw.Seq => Pos => PSeqType] = P(typ.brackets map { t => PSeqType(_, t) })
723719

@@ -804,11 +800,15 @@ class FastParser {
804800

805801
def newExp[$: P]: P[PKw.New => Pos => PNewExp] = P(newExpFields.parens map { n => PNewExp(_, n) })
806802

807-
def newExpFields[$: P]: P[Either[PSym.Star, PDelimited[PIdnUseExp, PSym.Comma]]] = P(P(PSym.Star).map(Left(_)) | P(idnuse.delimited(PSym.Comma).map(Right(_))))
803+
def newExpFields[$: P]: P[Either[PSym.Star, PDelimited[PIdnRef[PFieldDecl], PSym.Comma]]] = P(P(PSym.Star).map(Left(_)) | P(idnref[$, PFieldDecl].delimited(PSym.Comma).map(Right(_))))
808804

809-
def funcApp[$: P]: P[PCall] = P((idnref ~ argList(exp)) map {
810-
case (func, args) => PCall(func, args, None)(_)
811-
}).pos
805+
def funcApp[$: P]: P[PCall] = P(idnref[$, PGlobalCallable] ~~ " ".repX(1).map { _ => pos: Pos => pos }.pos.? ~~ argList(exp)).map {
806+
case (func, space, args) =>
807+
space.foreach { space =>
808+
_warnings = _warnings :+ ParseWarning("Whitespace between a function identifier and the opening paren is deprecated, remove the spaces", SourcePosition(_file, space._1, space._2))
809+
}
810+
PCall(func, args, None)(_)
811+
}.pos
812812

813813
def maybeTypedFuncApp[$: P](bracketed: Boolean): P[PCall] = P(if (!bracketed) funcApp else (funcApp ~~~ (P(PSym.Colon) ~ typ).lw.?).map {
814814
case (func, typeGiven) => func.copy(typeAnnotated = typeGiven)(_)
@@ -905,13 +905,13 @@ class FastParser {
905905
P((nonEmptyIdnTypeList(PLocalVarDecl(_)) ~~~ (P(PSymOp.Assign) ~ exp).lw.?) map { case (a, i) => PVars(_, a, i) })
906906

907907
def defineDecl[$: P]: P[PKw.Define => PAnnotationsPosition => PDefine] =
908-
P((idndef ~~~/ NoCut(argList(idndef)).lw.? ~ (stmtBlock(false) | exp)) map {
908+
P((idndef ~~~/ NoCut(argList((idndef map PDefineParam.apply).pos)).lw.? ~ (stmtBlock(false) | exp)) map {
909909
case (idn, args, body) => k => ap: PAnnotationsPosition => PDefine(ap.annotations, k, idn, args, body)(ap.pos)
910910
})
911911

912912
def defineDeclStmt[$: P]: P[PKw.Define => Pos => PDefine] = P(defineDecl.map { f => k => pos: Pos => f(k)(PAnnotationsPosition(Nil, pos)) })
913913

914-
def goto[$: P]: P[PKw.Goto => Pos => PGoto] = P(idnuse map { i => PGoto(_, i) _ })
914+
def goto[$: P]: P[PKw.Goto => Pos => PGoto] = P(idnref[$, PLabel] map { i => PGoto(_, i) _ })
915915

916916
def label[$: P]: P[PKw.Label => Pos => PLabel] =
917917
P((idndef ~ semiSeparated(invariant)) map { case (i, inv) => k=> PLabel(k, i, inv) _ })
@@ -954,8 +954,7 @@ class FastParser {
954954
decls.collect { case p: PPredicate => p }, // Predicates
955955
decls.collect { case m: PMethod => m }, // Methods
956956
decls.collect { case e: PExtender => e }, // Extensions
957-
warnings // Parse Warnings
958-
)(_)
957+
)(_, warnings) // Parse Warnings
959958
}
960959
}).pos
961960

@@ -981,8 +980,8 @@ class FastParser {
981980
val members = block.inner.members
982981
val funcs1 = members collect { case m: PDomainFunction1 => m }
983982
val axioms1 = members collect { case m: PAxiom1 => m }
984-
val funcs = funcs1 map (f => (PDomainFunction(f.annotations, f.unique, f.function, f.idndef, f.args, f.c, f.typ, f.interpretation)(PIdnRef(name.name)(name.pos))(f.pos), f.s))
985-
val axioms = axioms1 map (a => (PAxiom(a.annotations, a.axiom, a.idndef, a.exp)(PIdnRef(name.name)(name.pos))(a.pos), a.s))
983+
val funcs = funcs1 map (f => (PDomainFunction(f.annotations, f.unique, f.function, f.idndef, f.args, f.c, f.typ, f.interpretation)(f.pos), f.s))
984+
val axioms = axioms1 map (a => (PAxiom(a.annotations, a.axiom, a.idndef, a.exp)(a.pos), a.s))
986985
val allMembers = block.update(PDomainMembers(PDelimited(funcs)(NoPosition, NoPosition), PDelimited(axioms)(NoPosition, NoPosition))(block.pos))
987986
k => ap: PAnnotationsPosition => PDomain(
988987
ap.annotations,
@@ -1000,11 +999,11 @@ class FastParser {
1000999
case (unique, (function, idn, args, c, typ), interpretation, s) => ap: PAnnotationsPosition => PDomainFunction1(ap.annotations, unique, function, idn, args, c, typ, interpretation, s)(ap.pos)
10011000
}
10021001

1003-
def domainFunctionSignature[$: P] = P(P(PKw.Function) ~ idndef ~ argList(formalArg | unnamedFormalArg) ~ PSym.Colon ~ typ)
1002+
def domainFunctionSignature[$: P] = P(P(PKw.Function) ~ idndef ~ argList(domainFunctionArg) ~ PSym.Colon ~ typ)
10041003

1005-
def formalArg[$: P]: P[PFormalArgDecl] = P(idnTypeBinding.map(PFormalArgDecl(_)))
1004+
def domainFunctionArg[$: P]: P[PDomainFunctionArg] = P(idnTypeBinding.map(PDomainFunctionArg(_)) | typ.map(PDomainFunctionArg(None, None, _) _).pos)
10061005

1007-
def unnamedFormalArg[$: P] = P(typ map (PUnnamedFormalArgDecl.apply _)).pos
1006+
def formalArg[$: P]: P[PFormalArgDecl] = P(idnTypeBinding map (PFormalArgDecl(_)))
10081007

10091008
def bracedExp[$: P]: P[PBracedExp] = P(exp.braces map (PBracedExp(_) _)).pos
10101009

0 commit comments

Comments
 (0)