Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for exhaleMode annotation #710

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/main/antlr4/GobraLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,6 @@ PROOF : 'proof';
GHOST_EQUALS : '===';
GHOST_NOT_EQUALS : '!==';
WITH : 'with';
EXHALEMODE : 'exhaleMode' -> mode(NLSEMI);
MCE : 'mce';
GREEDY : 'greedy';
7 changes: 6 additions & 1 deletion src/main/antlr4/GobraParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,12 @@ sqType: (kind=(SEQ | SET | MSET | OPT) L_BRACKET type_ R_BRACKET)
// Specifications

specification returns[boolean trusted = false, boolean pure = false;]:
((specStatement | PURE {$pure = true;} | TRUSTED {$trusted = true;}) eos)*? (PURE {$pure = true;})? // Non-greedily match PURE to avoid missing eos errors.
((specStatement | PURE {$pure = true;} | (EXHALEMODE L_PAREN exhaleMode R_PAREN) | TRUSTED {$trusted = true;}) eos)*? (PURE {$pure = true;})? // Non-greedily match PURE to avoid missing eos errors.
;

exhaleMode
: MCE
| GREEDY
;

specStatement
Expand Down
2,164 changes: 1,092 additions & 1,072 deletions src/main/java/viper/gobra/frontend/GobraLexer.java

Large diffs are not rendered by default.

5,091 changes: 2,591 additions & 2,500 deletions src/main/java/viper/gobra/frontend/GobraParser.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from src/main/antlr4/GobraParser.g4 by ANTLR 4.13.0
// Generated from /Users/joao/code/gobra/src/main/antlr4/GobraParser.g4 by ANTLR 4.13.1
package viper.gobra.frontend;
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;

Expand Down Expand Up @@ -376,6 +376,13 @@ public class GobraParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitSpecification(GobraParser.SpecificationContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitExhaleMode(GobraParser.ExhaleModeContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/viper/gobra/frontend/GobraParserVisitor.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated from src/main/antlr4/GobraParser.g4 by ANTLR 4.13.0
// Generated from /Users/joao/code/gobra/src/main/antlr4/GobraParser.g4 by ANTLR 4.13.1
package viper.gobra.frontend;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;

Expand Down Expand Up @@ -326,6 +326,12 @@ public interface GobraParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitSpecification(GobraParser.SpecificationContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#exhaleMode}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitExhaleMode(GobraParser.ExhaleModeContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#specStatement}.
* @param ctx the parse tree
Expand Down
7 changes: 6 additions & 1 deletion src/main/scala/viper/gobra/ast/frontend/Ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -876,13 +876,18 @@ case class PTupleTerminationMeasure(tuple: Vector[PExpression], cond: Option[PEx

sealed trait PSpecification extends PGhostNode

sealed trait PExhaleMode extends PNode
case class PGreedy() extends PExhaleMode
case class PMce() extends PExhaleMode

case class PFunctionSpec(
pres: Vector[PExpression],
preserves: Vector[PExpression],
posts: Vector[PExpression],
terminationMeasures: Vector[PTerminationMeasure],
exhaleMode: Vector[PExhaleMode],
isPure: Boolean = false,
isTrusted: Boolean = false
isTrusted: Boolean = false,
) extends PSpecification

case class PBodyParameterInfo(
Expand Down
15 changes: 11 additions & 4 deletions src/main/scala/viper/gobra/ast/frontend/PrettyPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
case n: PInterfaceClause => showInterfaceClause(n)
case n: PBodyParameterInfo => showBodyParameterInfo(n)
case n: PTerminationMeasure => showTerminationMeasure(n)
case n: PExhaleMode => showExhaleMode(n)
case PPos(_) => emptyDoc
}

Expand Down Expand Up @@ -142,14 +143,20 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
"decreases" <+> measureDoc(measure)
}

def showExhaleMode(mode: PExhaleMode): Doc = mode match {
case PGreedy() => "greedy"
case PMce() => "mce"
}

def showSpec(spec: PSpecification): Doc = spec match {
case PFunctionSpec(pres, preserves, posts, measures, isPure, isTrusted) =>
case PFunctionSpec(pres, preserves, posts, measures, exhaleMode, isPure, isTrusted) =>
(if (isPure) showPure else emptyDoc) <>
(if (isTrusted) showTrusted else emptyDoc) <>
hcat(pres map (showPre(_) <> line)) <>
hcat(preserves map (showPreserves(_) <> line)) <>
hcat(posts map (showPost(_) <> line)) <>
hcat(measures map (showTerminationMeasure(_) <> line))
hcat(preserves map (showPreserves(_) <> line)) <>
hcat(posts map (showPost(_) <> line)) <>
hcat(measures map (showTerminationMeasure(_) <> line)) <>
hcat(exhaleMode map (showExhaleMode(_) <> line))

case PLoopSpec(inv, measure) =>
hcat(inv map (showInv(_) <> line)) <> opt(measure)(showTerminationMeasure) <> line
Expand Down
64 changes: 37 additions & 27 deletions src/main/scala/viper/gobra/ast/internal/PrettyPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import viper.silver.ast.{Position => GobraPosition}

import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import viper.gobra.util.Violation.violation

trait PrettyPrinter {
def format(node : Node): String
Expand Down Expand Up @@ -144,28 +143,36 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
}
}

def showExhaleMode(mode: ExhaleMode): Doc = {
val modDoc = mode match {
case Mce => "mce"
case Greedy => "greedy"
}
"exhaleMode" <> parens(modDoc) <> line
}

def showFunction(f: Function): Doc = f match {
case Function(name, args, results, pres, posts, measures, body) =>
case Function(name, args, results, pres, posts, measures, exhaleMode, body) =>
"func" <+> name.name <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block(showStmt(b)))
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block(showStmt(b)))
}

def showPureFunction(f: PureFunction): Doc = f match {
case PureFunction(name, args, results, pres, posts, measures, body) =>
case PureFunction(name, args, results, pres, posts, measures, exhaleMode, body) =>
"pure func" <+> name.name <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block("return" <+> showExpr(b)))
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block("return" <+> showExpr(b)))
}

def showMethod(m: Method): Doc = m match {
case Method(receiver, name, args, results, pres, posts, measures, body) =>
case Method(receiver, name, args, results, pres, posts, measures, exhaleMode, body) =>
"func" <+> parens(showVarDecl(receiver)) <+> name.name <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block(showStmt(b)))
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block(showStmt(b)))
}

def showPureMethod(m: PureMethod): Doc = m match {
case PureMethod(receiver, name, args, results, pres, posts, measures, body) =>
case PureMethod(receiver, name, args, results, pres, posts, measures, exhaleMode, body) =>
"pure func" <+> parens(showVarDecl(receiver)) <+> name.name <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block("return" <+> showExpr(b)))
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block("return" <+> showExpr(b)))
}

def showMethodSubtypeProof(m: MethodSubtypeProof): Doc = m match {
Expand Down Expand Up @@ -350,8 +357,8 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
showVar(resTarget) <> "," <+> showVar(successTarget) <+> "=" <+> showExpr(mapLookup)
case PredExprFold(base, args, p) => "fold" <+> "acc" <> parens(showExpr(base) <> parens(showExprList(args)) <> "," <+> showExpr(p))
case PredExprUnfold(base, args, p) => "unfold" <+> "acc" <> parens(showExpr(base) <> parens(showExprList(args)) <> "," <+> showExpr(p))
case Outline(_, pres, posts, measures, body, trusted) =>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <>
case Outline(_, pres, posts, measures, exhaleMode, body, trusted) =>
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <>
"outline" <> (if (trusted) emptyDoc else parens(nest(line <> showStmt(body)) <> line))
case Continue(l, _) => "continue" <+> opt(l)(text)
case Break(l, _) => "break" <+> opt(l)(text)
Expand Down Expand Up @@ -602,14 +609,17 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
case BoolLit(b) => if (b) "true" else "false"
case NilLit(t) => parens("nil" <> ":" <> showType(t))

case FunctionLit(name, args, captured, results, pres, posts, measures, body) =>
"func" <+> showProxy(name) <> showCaptured(captured) <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <>
case FunctionLit(name, args, captured, results, pres, posts, measures, exhaleMode, body) =>
"func" <+> showProxy(name) <> showCaptured(captured) <> parens(showFormalArgList(args)) <+>
parens(showVarDeclList(results)) <>
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <>
opt(body)(b => block(showStmt(b)))

case PureFunctionLit(name, args, captured, results, pres, posts, measures, body) =>
"pure func" <+> showProxy(name) <> showCaptured(captured) <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <> opt(body)(b => block("return" <+> showExpr(b)))
case PureFunctionLit(name, args, captured, results, pres, posts, measures, exhaleMode, body) =>
"pure func" <+> showProxy(name) <> showCaptured(captured) <> parens(showFormalArgList(args)) <+>
parens(showVarDeclList(results)) <>
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <>
opt(body)(b => block("return" <+> showExpr(b)))

case ArrayLit(len, typ, elems) => {
val lenP = brackets(len.toString)
Expand Down Expand Up @@ -675,27 +685,27 @@ class ShortPrettyPrinter extends DefaultPrettyPrinter {


override def showFunction(f: Function): Doc = f match {
case Function(name, args, results, pres, posts, measures, _) =>
case Function(name, args, results, pres, posts, measures, exhaleMode, _) =>
"func" <+> name.name <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures))
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures))
}

override def showPureFunction(f: PureFunction): Doc = f match {
case PureFunction(name, args, results, pres, posts, measures, _) =>
case PureFunction(name, args, results, pres, posts, measures, exhaleMode, _) =>
"pure func" <+> name.name <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures))
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures))
}

override def showMethod(m: Method): Doc = m match {
case Method(receiver, name, args, results, pres, posts, measures, _) =>
case Method(receiver, name, args, results, pres, posts, measures, exhaleMode, _) =>
"func" <+> parens(showVarDecl(receiver)) <+> name.name <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures))
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures))
}

override def showPureMethod(m: PureMethod): Doc = m match {
case PureMethod(receiver, name, args, results, pres, posts, measures, _) =>
case PureMethod(receiver, name, args, results, pres, posts, measures, exhaleMode, _) =>
"pure func" <+> parens(showVarDecl(receiver)) <+> name.name <> parens(showFormalArgList(args)) <+> parens(showVarDeclList(results)) <>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures))
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures))
}

override def showFPredicate(predicate: FPredicate): Doc = predicate match {
Expand Down Expand Up @@ -787,8 +797,8 @@ class ShortPrettyPrinter extends DefaultPrettyPrinter {
case PredExprUnfold(base, args, p) => "unfold" <+> "acc" <> parens(showExpr(base) <> parens(showExprList(args)) <> "," <+> showExpr(p))
case Continue(l, _) => "continue" <+> opt(l)(text)
case Break(l, _) => "break" <+> opt(l)(text)
case Outline(_, pres, posts, measures, _, _) =>
spec(showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <>
case Outline(_, pres, posts, measures, exhaleMode, _, _) =>
spec(opt(exhaleMode)(showExhaleMode) <> showPreconditions(pres) <> showPostconditions(posts) <> showTerminationMeasures(measures)) <>
"outline"
}
}
22 changes: 18 additions & 4 deletions src/main/scala/viper/gobra/ast/internal/Program.scala
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ sealed trait BuiltInMember extends Member {
def argsT: Vector[Type]
}

sealed trait ExhaleMode
case object Greedy extends ExhaleMode
case object Mce extends ExhaleMode

sealed trait MethodLikeMember extends Member {
def name: MethodProxy
}
Expand All @@ -146,6 +150,7 @@ sealed trait MethodMember extends MethodLikeMember {
def results: Vector[Parameter.Out]
def pres: Vector[Assertion]
def posts: Vector[Assertion]
def exhaleMode: Option[ExhaleMode]
def terminationMeasures: Vector[TerminationMeasure]
}

Expand All @@ -158,6 +163,7 @@ sealed trait FunctionLikeMemberOrLit extends Node {
def results: Vector[Parameter.Out]
def pres: Vector[Assertion]
def posts: Vector[Assertion]
def exhaleMode: Option[ExhaleMode]
def terminationMeasures: Vector[TerminationMeasure]
}

Expand Down Expand Up @@ -185,7 +191,8 @@ case class Method(
override val pres: Vector[Assertion],
override val posts: Vector[Assertion],
override val terminationMeasures: Vector[TerminationMeasure],
body: Option[MethodBody]
override val exhaleMode: Option[ExhaleMode],
body: Option[MethodBody],
)(val info: Source.Parser.Info) extends Member with MethodMember

case class PureMethod(
Expand All @@ -196,7 +203,8 @@ case class PureMethod(
override val pres: Vector[Assertion],
override val posts: Vector[Assertion],
override val terminationMeasures: Vector[TerminationMeasure],
body: Option[Expr]
override val exhaleMode: Option[ExhaleMode],
body: Option[Expr],
)(val info: Source.Parser.Info) extends Member with MethodMember {
require(results.size <= 1)
}
Expand Down Expand Up @@ -241,6 +249,7 @@ case class Function(
override val pres: Vector[Assertion],
override val posts: Vector[Assertion],
override val terminationMeasures: Vector[TerminationMeasure],
override val exhaleMode: Option[ExhaleMode],
body: Option[MethodBody]
)(val info: Source.Parser.Info) extends Member with FunctionMember

Expand All @@ -251,6 +260,7 @@ case class PureFunction(
override val pres: Vector[Assertion],
override val posts: Vector[Assertion],
override val terminationMeasures: Vector[TerminationMeasure],
override val exhaleMode: Option[ExhaleMode],
body: Option[Expr]
)(val info: Source.Parser.Info) extends Member with FunctionMember {
require(results.size <= 1)
Expand Down Expand Up @@ -449,6 +459,7 @@ case class Outline(
pres: Vector[Assertion],
posts: Vector[Assertion],
terminationMeasures: Vector[TerminationMeasure],
exhaleMode: Option[ExhaleMode],
body: Stmt,
trusted: Boolean,
)(val info: Source.Parser.Info) extends Stmt
Expand Down Expand Up @@ -1112,7 +1123,8 @@ case class FunctionLit(
override val pres: Vector[Assertion],
override val posts: Vector[Assertion],
override val terminationMeasures: Vector[TerminationMeasure],
body: Option[MethodBody]
override val exhaleMode: Option[ExhaleMode],
body: Option[MethodBody],
)(val info: Source.Parser.Info) extends FunctionLitLike {
override def typ: Type = FunctionT(args.map(_.typ), results.map(_.typ), Addressability.literal)
}
Expand All @@ -1125,7 +1137,9 @@ case class PureFunctionLit(
override val pres: Vector[Assertion],
override val posts: Vector[Assertion],
override val terminationMeasures: Vector[TerminationMeasure],
body: Option[Expr]
// TODO: encoding, and clean warnings everywhere
override val exhaleMode: Option[ExhaleMode],
body: Option[Expr],
)(val info: Source.Parser.Info) extends FunctionLitLike {
override def typ: Type = FunctionT(args.map(_.typ), results.map(_.typ), Addressability.literal)
require(results.size <= 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ object CGEdgesTerminationTransform extends InternalTransform {
stmts = assumeFalse +: optCallsToImpls
)(src)
}
val newMember = in.Method(m.receiver, m.name, m.args, m.results, m.pres, m.posts, m.terminationMeasures, Some(newBody.toMethodBody))(src)
val newMember = in.Method(m.receiver, m.name, m.args, m.results, m.pres, m.posts, m.terminationMeasures, None, Some(newBody.toMethodBody))(src)
methodsToRemove += m
methodsToAdd += newMember
definedMethodsDelta += proxy -> newMember
Expand Down
Loading
Loading