Skip to content
Merged
5 changes: 5 additions & 0 deletions src/main/scala/viper/silver/ast/Ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ case object NoInfo extends Info {
override val isCached = false
}

case class AnnotationInfo(values: Map[String, Seq[String]]) extends Info {
override val isCached = false
override val comment = Nil
}

/** A simple `Info` that contains a list of comments. */
case class SimpleInfo(comment: Seq[String]) extends Info {
override val isCached = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

package viper.silver.ast.utility.rewriter

import viper.silver.parser.PDomainFunction
import viper.silver.parser.{PDomain, PDomainFunction, PField, PFunction, PMethod, PPredicate}
import viper.silver.parser.Transformer.ParseTreeDuplicationError
import viper.silver.ast.{AtomicType, BackendFuncApp, DomainFuncApp, ErrorTrafo, FuncApp, Info, Node, Position}

Expand Down Expand Up @@ -49,9 +49,14 @@ trait Rewritable extends Product {
case df: DomainFuncApp => secondArgList = Seq(df.pos, df.info, df.typ, df.domainName, df.errT)
case ba: BackendFuncApp => secondArgList = Seq(ba.pos, ba.info, ba.typ, ba.interpretation, ba.errT)
case no: Node => secondArgList = no.getMetadata
case pa: PAxiom => secondArgList = Seq(pa.domainName) ++ Seq(pos.getOrElse(pa.pos))
case pa: PAxiom => secondArgList = Seq(pa.domainName) ++ Seq(pos.getOrElse(pa.pos), pa.annotations)
case pm: PMagicWandExp => firstArgList = Seq(children.head) ++ children.drop(2) ++ Seq(pos.getOrElse(pm.pos))
case pd: PDomainFunction => secondArgList = Seq(pd.domainName) ++ Seq(pos.getOrElse(pd.pos))
case pd: PDomainFunction => secondArgList = Seq(pd.domainName) ++ Seq(pos.getOrElse(pd.pos), pd.annotations)
case pd: PDomain => secondArgList = Seq(pos.getOrElse(pd.pos), pd.annotations)
case pm: PMethod => secondArgList = Seq(pos.getOrElse(pm.pos), pm.annotations)
case pp: PPredicate => secondArgList = Seq(pos.getOrElse(pp.pos), pp.annotations)
case pf: PFunction => secondArgList = Seq(pos.getOrElse(pf.pos), pf.annotations)
case pf: PField => secondArgList = Seq(pos.getOrElse(pf.pos), pf.annotations)
case pn: PNode => secondArgList = Seq(pos.getOrElse(pn.pos))
case _ =>
}
Expand Down
63 changes: 39 additions & 24 deletions src/main/scala/viper/silver/parser/FastParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ class FastParser {
}

if (body != method.body) {
PMethod(method.idndef, method.formalArgs, method.formalReturns, method.pres, method.posts, body)(method.pos)
PMethod(method.idndef, method.formalArgs, method.formalReturns, method.pres, method.posts, body)(method.pos, method.annotations)
} else {
method
}
Expand Down Expand Up @@ -794,14 +794,23 @@ class FastParser {

// Note that `typedFapp` is before `"(" ~ exp ~ ")"` to ensure that the latter doesn't gobble up the brackets for the former
// and then look like an `fapp` up untill the `: type` part, after which we need to backtrack all the way back (or error if cut)
def atom(implicit ctx : P[_]) : P[PExp] = P(ParserExtension.newExpAtStart(ctx) | integer | booltrue | boolfalse | nul | old
def atom(implicit ctx : P[_]) : P[PExp] = P(ParserExtension.newExpAtStart(ctx) | annotatedAtom
| integer | booltrue | boolfalse | nul | old
| result | unExp | typedFapp
| "(" ~ exp ~ ")" | accessPred | inhaleExhale | perm | let | quant | forperm | unfolding | applying
| setTypedEmpty | explicitSetNonEmpty | multiSetTypedEmpty | explicitMultisetNonEmpty | seqTypedEmpty
| size | explicitSeqNonEmpty | seqRange
| mapTypedEmpty | explicitMapNonEmpty | mapDomain | mapRange
| fapp | idnuse | ParserExtension.newExpAtEnd(ctx))

def stringLiteral[$: P]: P[String] = P("\"" ~ CharsWhile(_ != '\"').! ~ "\"")

def annotation[$: P]: P[(String, Seq[String])] = P("@" ~~ ident ~ parens(stringLiteral.rep(sep = ",")))

def annotatedAtom[$: P]: P[PExp] = FP(annotation ~ atom).map{
case (pos, (key, value, exp)) => PAnnotatedExp(exp, (key, value))(pos)
}

def result[$: P]: P[PResultLit] = FP(keyword("result")).map { case (pos, _) => PResultLit()(pos) }

def unExp[$: P]: P[PUnExp] = FP(CharIn("\\-\\!").! ~ suffixExpr).map { case (pos, (a, b)) => PUnExp(a, b)(pos) }
Expand Down Expand Up @@ -1094,11 +1103,16 @@ class FastParser {
case (pos, (func, args, typeGiven)) => PCall(func, args, Some(typeGiven))(pos)
}

def stmt(implicit ctx : P[_]) : P[PStmt] = P(ParserExtension.newStmtAtStart(ctx) | macroassign | fieldassign | localassign | fold | unfold | exhale | assertP |
def stmt(implicit ctx : P[_]) : P[PStmt] = P(ParserExtension.newStmtAtStart(ctx) | annotatedStmt |
macroassign | fieldassign | localassign | fold | unfold | exhale | assertP |
inhale | assume | ifthnels | whle | varDecl | defineDecl | newstmt |
methodCall | goto | lbl | packageWand | applyWand | macroref | block |
quasihavoc | quasihavocall | ParserExtension.newStmtAtEnd(ctx))

def annotatedStmt(implicit ctx : P[_]): P[PStmt] = (FP(annotation ~ stmt).map{
case (pos, (key, value, pStmt)) => PAnnotatedStmt(pStmt, (key, value))(pos)
})

def nodefinestmt(implicit ctx : P[_]) : P[PStmt] = P(ParserExtension.newStmtAtStart(ctx) | fieldassign | localassign | fold | unfold | exhale | assertP |
inhale | assume | ifthnels | whle | varDecl | newstmt |
methodCall | goto | lbl | packageWand | applyWand | macroref | block |
Expand Down Expand Up @@ -1210,7 +1224,8 @@ class FastParser {

def applying[$: P]: P[PExp] = FP(keyword("applying") ~/ "(" ~ magicWandExp ~ ")" ~ "in" ~ exp).map { case (pos, (a, b)) => PApplying(a, b)(pos) }

def programDecl(implicit ctx : P[_]) : P[PProgram] = P(FP((ParserExtension.newDeclAtStart(ctx) | preambleImport | defineDecl | domainDecl | fieldDecl | functionDecl | predicateDecl | methodDecl | ParserExtension.newDeclAtEnd(ctx)).rep).map {
def programDecl(implicit ctx : P[_]) : P[PProgram] =
P(FP((ParserExtension.newDeclAtStart(ctx) | preambleImport | defineDecl | fieldDecl | methodDecl | domainDecl | functionDecl | predicateDecl | ParserExtension.newDeclAtEnd(ctx)).rep).map {
case (pos, decls) => {
PProgram(
decls.collect { case i: PImport => i }, // Imports
Expand All @@ -1235,26 +1250,26 @@ class FastParser {

def anyString[$: P]: P[String] = P(CharPred(c => c !='\"').rep(1).!)

def domainDecl[$: P]: P[PDomain] = FP("domain" ~/ idndef ~ typeParams ~ ("interpretation" ~ parens((ident ~ ":" ~ quoted(anyString.!)).rep(sep = ","))).? ~ "{" ~ (domainFunctionDecl | axiomDecl).rep ~
def domainDecl[$: P]: P[PDomain] = FP(annotation.rep(0) ~ "domain" ~/ idndef ~ typeParams ~ ("interpretation" ~ parens((ident ~ ":" ~ quoted(anyString.!)).rep(sep = ","))).? ~ "{" ~ (domainFunctionDecl | axiomDecl).rep ~
"}").map {
case (pos, (name, typparams, interpretations, members)) =>
case (pos, (anns, name, typparams, interpretations, members)) =>
val funcs = members collect { case m: PDomainFunction1 => m }
val axioms = members collect { case m: PAxiom1 => m }
PDomain(
name,
typparams,
funcs map (f => PDomainFunction(f.idndef, f.formalArgs, f.typ, f.unique, f.interpretation)(PIdnUse(name.name)(name.pos))(f.pos)),
axioms map (a => PAxiom(a.idndef, a.exp)(PIdnUse(name.name)(name.pos))(a.pos)),
interpretations.map(i => i.toMap))(pos)
funcs map (f => PDomainFunction(f.idndef, f.formalArgs, f.typ, f.unique, f.interpretation)(PIdnUse(name.name)(name.pos))(f.pos, f.annotations)),
axioms map (a => PAxiom(a.idndef, a.exp)(PIdnUse(name.name)(name.pos))(a.pos, a.annotations)),
interpretations.map(i => i.toMap))(pos, anns)
}

def domainTypeVarDecl[$: P]: P[PTypeVarDecl] = FP(idndef).map{ case (pos, i) => PTypeVarDecl(i)(pos) }

def typeParams[$: P]: P[Seq[PTypeVarDecl]] = P(("[" ~ domainTypeVarDecl.rep(sep = ",") ~ "]").?).map(_.getOrElse(Nil))

def domainFunctionDecl[$: P]: P[PDomainFunction1] = FP("unique".!.? ~ domainFunctionSignature ~ ("interpretation" ~ quoted(anyString.!)).? ~~~ ";".lw.?).map {
case (pos, (unique, fdecl, interpretation)) => fdecl match {
case (name, formalArgs, t) => PDomainFunction1(name, formalArgs, t, unique.isDefined, interpretation)(pos)
def domainFunctionDecl[$: P]: P[PDomainFunction1] = FP(annotation.rep(0) ~ "unique".!.? ~ domainFunctionSignature ~ ("interpretation" ~ quoted(anyString.!)).? ~~~ ";".lw.?).map {
case (pos, (anns, unique, fdecl, interpretation)) => fdecl match {
case (name, formalArgs, t) => PDomainFunction1(name, formalArgs, t, unique.isDefined, interpretation)(pos, anns)
}
}

Expand All @@ -1268,15 +1283,15 @@ class FastParser {

def formalArgList[$: P]: P[Seq[PFormalArgDecl]] = P(formalArg.rep(sep = ","))

def axiomDecl[$: P]: P[PAxiom1] = FP(keyword("axiom") ~ idndef.? ~ "{" ~ exp ~ "}" ~~~ ";".lw.?).map { case (pos, (a, b)) => PAxiom1(a, b)(pos) }
def axiomDecl[$: P]: P[PAxiom1] = FP(annotation.rep(0) ~ keyword("axiom") ~ idndef.? ~ "{" ~ exp ~ "}" ~~~ ";".lw.?).map { case (pos, (anns, a, b)) => PAxiom1(a, b)(pos, anns) }

def fieldDecl[$: P]: P[PField] = FP(keyword("field") ~/ idndef ~ ":" ~ typ ~~~ ";".lw.?).map {
case (pos, (a, b)) => PField(a, b)(pos)
def fieldDecl[$: P]: P[PField] = FP(annotation.rep(0) ~ keyword("field") ~/ idndef ~ ":" ~ typ ~~~ ";".lw.?).map {
case (pos, (anns, a, b)) => PField(a, b)(pos, anns)
}

def functionDecl[$: P]: P[PFunction] = FP("function" ~/ idndef ~ "(" ~ formalArgList ~ ")" ~ ":" ~ typ ~~~ pre.lw.rep ~~~
post.lw.rep ~~~ ("{" ~ exp ~ "}").lw.?).map({ case (pos, (a, b, c, d, e, f)) =>
PFunction(a, b, c, d, e, f)(pos)
def functionDecl[$: P]: P[PFunction] = FP(annotation.rep(0) ~ "function" ~/ idndef ~ "(" ~ formalArgList ~ ")" ~ ":" ~ typ ~~~ pre.lw.rep ~~~
post.lw.rep ~~~ ("{" ~ exp ~ "}").lw.?).map({ case (pos, (anns, a, b, c, d, e, f)) =>
PFunction(a, b, c, d, e, f)(pos, anns)
})


Expand All @@ -1286,14 +1301,14 @@ class FastParser {

def decCl[$: P]: P[Seq[PExp]] = P(exp.rep(sep = ","))

def predicateDecl[$: P]: P[PPredicate] = FP(keyword("predicate") ~/ idndef ~ "(" ~ formalArgList ~ ")" ~~~ ("{" ~ exp ~ "}").lw.?).map {
case (pos, (a, b, c)) =>
PPredicate(a, b, c)(pos)
def predicateDecl[$: P]: P[PPredicate] = FP(annotation.rep(0) ~ keyword("predicate") ~/ idndef ~ "(" ~ formalArgList ~ ")" ~~~ ("{" ~ exp ~ "}").lw.?).map {
case (pos, (anns, a, b, c)) =>
PPredicate(a, b, c)(pos, anns)
}

def methodDecl[$: P]: P[PMethod] = FP(methodSignature ~~~/ pre.lw.rep ~~~ post.lw.rep ~~~ block.lw.?).map {
case (pos, (name, args, rets, pres, posts, body)) =>
PMethod(name, args, rets.getOrElse(Nil), pres, posts, body)(pos)
def methodDecl[$: P]: P[PMethod] = FP(annotation.rep(0) ~ methodSignature ~~~/ pre.lw.rep ~~~ post.lw.rep ~~~ block.lw.?).map {
case (pos, (anns, (name, args, rets), pres, posts, body)) =>
PMethod(name, args, rets.getOrElse(Nil), pres, posts, body)(pos, anns)
}

def methodSignature[$: P] = P("method" ~/ idndef ~ "(" ~ formalArgList ~ ")" ~~~ ("returns" ~ "(" ~ formalArgList ~ ")").lw.?)
Expand Down
47 changes: 29 additions & 18 deletions src/main/scala/viper/silver/parser/ParseAst.scala
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,11 @@ trait PExp extends PNode {
def forceSubstitution(ts: PTypeSubstitution): Unit
}

case class PAnnotatedExp(e: PExp, annotation: (String, Seq[String]))(val pos: (Position, Position)) extends PExp {
override def typeSubstitutions: collection.Seq[PTypeSubstitution] = e.typeSubstitutions
override def forceSubstitution(ts: PTypeSubstitution): Unit = e.forceSubstitution(ts)
}

case class PMagicWandExp(override val left: PExp, override val right: PExp)(val posi: (Position, Position)) extends PBinExp(left, MagicWandOp.op, right)(posi) with PResourceAccess

class PTypeSubstitution(val m: Map[String, PType]) //extends Map[String,PType]()
Expand Down Expand Up @@ -1206,6 +1211,8 @@ trait PStmt extends PNode {
}
}

case class PAnnotatedStmt(stmt: PStmt, annotation: (String, Seq[String]))(val pos: (Position, Position)) extends PStmt

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

case class PFold(e: PExp)(val pos: (Position, Position)) extends PStmt
Expand Down Expand Up @@ -1325,7 +1332,9 @@ abstract class PErrorEntity extends PEntity {


// a member (like method or axiom) that is its own name scope
trait PMember extends PDeclaration with PScope
trait PMember extends PDeclaration with PScope {

}

trait PAnyFunction extends PMember with PGlobalDeclaration with PTypedDeclaration {
def idndef: PIdnDef
Expand All @@ -1343,46 +1352,46 @@ case class PLocalImport(file: String)(val pos: (Position, Position)) extends PIm

case class PStandardImport(file: String)(val pos: (Position, Position)) extends PImport()

case class PMethod(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], formalReturns: Seq[PFormalArgDecl], pres: Seq[PExp], posts: Seq[PExp], body: Option[PStmt])(val pos: (Position, Position)) extends PMember with PGlobalDeclaration {
case class PMethod(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], formalReturns: Seq[PFormalArgDecl], pres: Seq[PExp], posts: Seq[PExp], body: Option[PStmt])
(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PMember with PGlobalDeclaration {
def deepCopy(idndef: PIdnDef = this.idndef, formalArgs: Seq[PFormalArgDecl] = this.formalArgs, formalReturns: Seq[PFormalArgDecl] = this.formalReturns, pres: Seq[PExp] = this.pres, posts: Seq[PExp] = this.posts, body: Option[PStmt] = this.body): PMethod = {
StrategyBuilder.Slim[PNode]({
case p: PMethod => PMethod(idndef, formalArgs, formalReturns, pres, posts, body)(p.pos)
case p: PMethod => PMethod(idndef, formalArgs, formalReturns, pres, posts, body)(p.pos, p.annotations)
}).execute[PMethod](this)
}

def deepCopyWithNameSubstitution(idndef: PIdnDef = this.idndef, formalArgs: Seq[PFormalArgDecl] = this.formalArgs, formalReturns: Seq[PFormalArgDecl] = this.formalReturns, pres: Seq[PExp] = this.pres, posts: Seq[PExp] = this.posts, body: Option[PStmt] = this.body)
(idn_generic_name: String, idn_substitution: String): PMethod = {
StrategyBuilder.Slim[PNode]({
case p: PMethod => PMethod(idndef, formalArgs, formalReturns, pres, posts, body)(p.pos)
case p: PMethod => PMethod(idndef, formalArgs, formalReturns, pres, posts, body)(p.pos, p.annotations)
case p@PIdnDef(name) if name == idn_generic_name => PIdnDef(idn_substitution)(p.pos)
case p@PIdnUse(name) if name == idn_generic_name => PIdnUse(idn_substitution)(p.pos)
}).execute[PMethod](this)
}
}

case class PDomain(idndef: PIdnDef, typVars: Seq[PTypeVarDecl], funcs: Seq[PDomainFunction], axioms: Seq[PAxiom], interpretations: Option[Map[String, String]])(val pos: (Position, Position)) extends PMember with PGlobalDeclaration

case class PFunction(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], typ: PType, pres: Seq[PExp], posts: Seq[PExp], body: Option[PExp])(val pos: (Position, Position)) extends PAnyFunction {
case class PDomain(idndef: PIdnDef, typVars: Seq[PTypeVarDecl], funcs: Seq[PDomainFunction], axioms: Seq[PAxiom], interpretations: Option[Map[String, String]])
(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PMember with PGlobalDeclaration
case class PFunction(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], typ: PType, pres: Seq[PExp], posts: Seq[PExp], body: Option[PExp])
(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PAnyFunction {
def deepCopy(idndef: PIdnDef = this.idndef, formalArgs: Seq[PFormalArgDecl] = this.formalArgs, typ: PType = this.typ, pres: Seq[PExp] = this.pres, posts: Seq[PExp] = this.posts, body: Option[PExp] = this.body): PFunction = {
StrategyBuilder.Slim[PNode]({
case p: PFunction => PFunction(idndef, formalArgs, typ, pres, posts, body)(p.pos)
case p: PFunction => PFunction(idndef, formalArgs, typ, pres, posts, body)(p.pos, p.annotations)
}).execute[PFunction](this)
}
}

case class PDomainFunction(idndef: PIdnDef, formalArgs: Seq[PAnyFormalArgDecl], typ: PType, unique: Boolean, interpretation: Option[String])(val domainName: PIdnUse)(val pos: (Position, Position)) extends PAnyFunction

case class PAxiom(idndef: Option[PIdnDef], exp: PExp)(val domainName: PIdnUse)(val pos: (Position, Position)) extends PScope

case class PField(idndef: PIdnDef, typ: PType)(val pos: (Position, Position)) extends PMember with PTypedDeclaration with PGlobalDeclaration

case class PPredicate(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], body: Option[PExp])(val pos: (Position, Position)) extends PMember with PTypedDeclaration with PGlobalDeclaration {
case class PDomainFunction(idndef: PIdnDef, formalArgs: Seq[PAnyFormalArgDecl], typ: PType, unique: Boolean, interpretation: Option[String])
(val domainName:PIdnUse)(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PAnyFunction
case class PAxiom(idndef: Option[PIdnDef], exp: PExp)(val domainName:PIdnUse)(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PScope
case class PField(idndef: PIdnDef, typ: PType)(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PMember with PTypedDeclaration with PGlobalDeclaration
case class PPredicate(idndef: PIdnDef, formalArgs: Seq[PFormalArgDecl], body: Option[PExp])
(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])]) extends PMember with PTypedDeclaration with PGlobalDeclaration{
val typ = PPredicateType()()
}

case class PDomainFunction1(idndef: PIdnDef, formalArgs: Seq[PAnyFormalArgDecl], typ: PType, unique: Boolean, interpretation: Option[String])(val pos: (Position, Position))

case class PAxiom1(idndef: Option[PIdnDef], exp: PExp)(val pos: (Position, Position))
case class PDomainFunction1(idndef: PIdnDef, formalArgs: Seq[PAnyFormalArgDecl], typ: PType, unique: Boolean, interpretation: Option[String])(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])])
case class PAxiom1(idndef: Option[PIdnDef], exp: PExp)(val pos: (Position, Position), val annotations: Seq[(String, Seq[String])])

/**
* A entity represented by names for whom we have seen more than one
Expand Down Expand Up @@ -1536,6 +1545,8 @@ object Nodes {
case PDefine(idndef, optArgs, body) => Seq(idndef) ++ optArgs.getOrElse(Nil) ++ Seq(body)
case PQuasihavoc(lhs, e) => lhs.toSeq :+ e
case PQuasihavocall(vars, lhs, e) => vars ++ lhs.toSeq :+ e
case PAnnotatedExp(e, _) => Seq(e)
case PAnnotatedStmt(s, _) => Seq(s)
case t: PExtender => t.getSubnodes()
case _: PSkip => Nil
case _: PUnnamedFormalArgDecl => Nil
Expand Down
7 changes: 6 additions & 1 deletion src/main/scala/viper/silver/parser/Resolver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ case class TypeChecker(names: NameAnalyser) {

def check(stmt: PStmt): Unit = {
stmt match {
case PAnnotatedStmt(s, _) =>
check(s)
case PMacroRef(id) =>
messages ++= FastMessaging.message(stmt, "unknown macro used: " + id.name)
case s@PSeqn(ss) =>
Expand Down Expand Up @@ -622,7 +624,10 @@ case class TypeChecker(names: NameAnalyser) {

case t: PExtender => t.typecheck(this, names).getOrElse(Nil) foreach (message =>
messages ++= FastMessaging.message(t, message))
case psl: PSimpleLiteral =>
case PAnnotatedExp(e, _) =>
checkInternal(e)
setType(e.typ)
case psl: PSimpleLiteral=>
psl match {
case r@PResultLit() =>
if (resultAllowed)
Expand Down
Loading