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

Private Specification, Partial Struct Encoding, and Constructor #619

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions src/main/antlr4/GobraLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ DOT_DOT : '..';
SHARED : 'shared';
EXCLUSIVE : 'exclusive';
PREDICATE : 'predicate';
PRIVATE : 'private';
WRITEPERM : 'writePerm' -> mode(NLSEMI);
NOPERM : 'noPerm' -> mode(NLSEMI);
TRUSTED : 'trusted' -> mode(NLSEMI);
Expand All @@ -88,3 +89,6 @@ PROOF : 'proof';
GHOST_EQUALS : '===';
GHOST_NOT_EQUALS : '!==';
WITH : 'with';
CONSTRUCT : 'construct';
DEREF : 'deref';
ASSIGN_STRUCT : 'assign';
24 changes: 22 additions & 2 deletions src/main/antlr4/GobraParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ 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 | PRIVATE privateSpec | PURE {$pure = true;} | TRUSTED {$trusted = true;}) eos)*? (PURE {$pure = true;})? // Non-greedily match PURE to avoid missing eos errors.
;

specStatement
Expand All @@ -165,12 +165,18 @@ specStatement
| kind=POST assertion
| kind=DEC terminationMeasure
;

terminationMeasure: expressionList? (IF expression)?;

assertion:
| expression
;

// Private specification
privateSpec: L_CURLY ((specStatement eos)*? privateEntailmentProof?)? R_CURLY;

privateEntailmentProof: PROOF block eos;

matchStmt: MATCH expression L_CURLY matchStmtClause* R_CURLY;
matchStmtClause: matchCase COLON statementList?;

Expand Down Expand Up @@ -220,7 +226,13 @@ new_: NEW L_PAREN type_ R_PAREN;

// Added specifications and parameter info

specMember: specification (functionDecl[$specification.trusted, $specification.pure] | methodDecl[$specification.trusted, $specification.pure]);
specMember: specification (
functionDecl[$specification.trusted, $specification.pure]
| methodDecl[$specification.trusted, $specification.pure]
| constructDecl
| derefDecl[$specification.pure]
| assignDecl
);

functionDecl[boolean trusted, boolean pure]: FUNC IDENTIFIER (signature blockWithBodyParameterInfo?);

Expand All @@ -236,6 +248,14 @@ predicateBody: L_CURLY expression eos R_CURLY;

mpredicateDecl: PRED receiver IDENTIFIER parameters predicateBody?;

// Struct Constructor
constructDecl: CONSTRUCT AMPERSAND? type_ (signature blockWithBodyParameterInfo?);
// Struct Dereference
derefDecl[boolean pure]: DEREF AMPERSAND? type_ (signature blockWithBodyParameterInfo?);
// Struct Assignment
assignDecl: ASSIGN_STRUCT AMPERSAND? type_ (signature blockWithBodyParameterInfo?);


// Addressability

varSpec:
Expand Down
1,480 changes: 748 additions & 732 deletions src/main/java/viper/gobra/frontend/GobraLexer.java

Large diffs are not rendered by default.

4,689 changes: 2,561 additions & 2,128 deletions src/main/java/viper/gobra/frontend/GobraParser.java

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions src/main/java/viper/gobra/frontend/GobraParserBaseVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,20 @@ public class GobraParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAssertion(GobraParser.AssertionContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPrivateSpec(GobraParser.PrivateSpecContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitPrivateEntailmentProof(GobraParser.PrivateEntailmentProofContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
Expand Down Expand Up @@ -564,6 +578,27 @@ public class GobraParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitMpredicateDecl(GobraParser.MpredicateDeclContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitConstructDecl(GobraParser.ConstructDeclContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitDerefDecl(GobraParser.DerefDeclContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAssignDecl(GobraParser.AssignDeclContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/viper/gobra/frontend/GobraParserVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,18 @@ public interface GobraParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitAssertion(GobraParser.AssertionContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#privateSpec}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPrivateSpec(GobraParser.PrivateSpecContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#privateEntailmentProof}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitPrivateEntailmentProof(GobraParser.PrivateEntailmentProofContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#matchStmt}.
* @param ctx the parse tree
Expand Down Expand Up @@ -491,6 +503,24 @@ public interface GobraParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitMpredicateDecl(GobraParser.MpredicateDeclContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#constructDecl}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitConstructDecl(GobraParser.ConstructDeclContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#derefDecl}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitDerefDecl(GobraParser.DerefDeclContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#assignDecl}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAssignDecl(GobraParser.AssignDeclContext ctx);
/**
* Visit a parse tree produced by {@link GobraParser#varSpec}.
* @param ctx the parse tree
Expand Down
37 changes: 37 additions & 0 deletions src/main/scala/viper/gobra/ast/frontend/Ast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class PositionManager(val positions: Positions) extends Messaging(positions) {
messages.sorted map { m =>
errorFactory(
formatMessage(m),
if (positions.getStart(m.value).isEmpty) None else //TODO: position of private members in private specifications
Some(translate(positions.getStart(m.value).get, positions.getFinish(m.value).get))
)
}
Expand Down Expand Up @@ -194,6 +195,31 @@ case class PTypeDef(right: PType, left: PIdnDef) extends PTypeDecl

case class PTypeAlias(right: PType, left: PIdnDef) extends PTypeDecl

case class PConstructDecl(
typ: PType,
args: Vector[PParameter],
posts: Vector[PExpression],
Felalolf marked this conversation as resolved.
Show resolved Hide resolved
body: Option[(PBodyParameterInfo, PBlock)],
isShared: Boolean
) extends PGhostMember with PScope

case class PDerefDecl(
typ: PType,
args: Vector[PParameter],
result: PResult,
pres: Vector[PExpression],
Felalolf marked this conversation as resolved.
Show resolved Hide resolved
body: Option[(PBodyParameterInfo, PBlock)],
isShared: Boolean,
isPure: Boolean
vizual1 marked this conversation as resolved.
Show resolved Hide resolved
) extends PGhostMember with PScope with PCodeRootWithResult

case class PAssignDecl(
typ: PType,
args: Vector[PParameter],
spec: PFunctionSpec,
body: Option[(PBodyParameterInfo, PBlock)],
isShared: Boolean
) extends PGhostMember with PScope

/**
* Statements
Expand Down Expand Up @@ -867,6 +893,7 @@ case class PFunctionSpec(
preserves: Vector[PExpression],
posts: Vector[PExpression],
terminationMeasures: Vector[PTerminationMeasure],
privateSpec: Option[PPrivateSpec],
isPure: Boolean = false,
isTrusted: Boolean = false
) extends PSpecification
Expand All @@ -887,6 +914,14 @@ case class PLoopSpec(
) extends PSpecification


case class PPrivateSpec(
pres: Vector[PExpression],
preserves: Vector[PExpression],
posts: Vector[PExpression],
terminationMeasures: Vector[PTerminationMeasure],
proof: Option[PPrivateEntailmentProof]
) extends PSpecification

/**
* Ghost Member
*/
Expand Down Expand Up @@ -927,6 +962,8 @@ case class PMethodImplementationProof(

case class PImplementationProofPredicateAlias(left: PIdnUse, right: PNameOrDot) extends PGhostMisc

case class PPrivateEntailmentProof(block: PBlock) extends PGhostStatement with PScope

sealed trait PNameOrDot extends PExpression

/**
Expand Down
30 changes: 28 additions & 2 deletions src/main/scala/viper/gobra/ast/frontend/PrettyPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
if (ip.alias.isEmpty && ip.memberProofs.isEmpty) emptyDoc
else block(ssep(ip.alias map showMisc, line) <> line <> ssep(ip.memberProofs map showMisc, line))
)
case PConstructDecl(typ, args, posts, body, isShared) =>
hcat(posts map (showPost(_) <> line)) <> "construct" <+> (if (isShared) "&" else emptyDoc) <> showType(typ) <>
parens(showParameterList(args)) <> opt(body)(b => space <> showBodyParameterInfoWithBlock(b._1, b._2))
case PDerefDecl(typ, args, _, pres, body, isShared, _) =>
hcat(pres map (showPre(_) <> line)) <> "pure deref" <+> (if (isShared) "&" else emptyDoc) <> showType(typ) <>
parens(showParameterList(args)) <> opt(body)(b => space <> showBodyParameterInfoWithBlock(b._1, b._2))
case PAssignDecl(typ, args, spec, body, isShared) =>
showSpec(spec) <> "assign" <+> (if (isShared) "&" else emptyDoc) <> showType(typ) <>
parens(showParameterList(args)) <> opt(body)(b => space <> showBodyParameterInfoWithBlock(b._1, b._2))
}
}

Expand All @@ -132,16 +141,25 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
}

def showSpec(spec: PSpecification): Doc = spec match {
case PFunctionSpec(pres, preserves, posts, measures, isPure, isTrusted) =>
case PFunctionSpec(pres, preserves, posts, measures, privateSpec, 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(measures map (showTerminationMeasure(_) <> line)) <>
opt(privateSpec)(showSpec)

case PLoopSpec(inv, measure) =>
hcat(inv map (showInv(_) <> line)) <> opt(measure)(showTerminationMeasure) <> line

case PPrivateSpec(pres, preserves, posts, measures, proof) =>
"private" <+> block(
hcat(pres map (showPre(_) <> line)) <>
hcat(preserves map (showPreserves(_) <> line)) <>
hcat(posts map (showPost(_) <> line)) <>
hcat(measures map (showTerminationMeasure(_) <> line)) <>
opt(proof)(showStmt)) <> line
}

def showBodyParameterInfoWithBlock(info: PBodyParameterInfo, block: PBlock): Doc = {
Expand Down Expand Up @@ -279,6 +297,7 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
case PMatchStatement(exp, clauses, _) => "match" <+>
showExpr(exp) <+> block(ssep(clauses map showMatchClauseStatement, line))
case PClosureImplProof(impl, PBlock(stmts)) => "proof" <+> showExpr(impl) <> block(showStmtList(stmts))
case PPrivateEntailmentProof(PBlock(stmts)) => "proof" <+> block(showStmtList(stmts))
}
}

Expand Down Expand Up @@ -508,6 +527,7 @@ class DefaultPrettyPrinter extends PrettyPrinter with kiama.output.PrettyPrinter
case n: PExpression if perm == PFullPerm() => "acc" <> parens(showExpr(n))
case n: PExpression => "acc" <> parens(showExpr(n) <> "," <+> showExpr(perm))
}

case PMagicWand(left, right) => showSubExpr(expr, left) <+> "--*" <+> showSubExpr(expr, right)
case PClosureImplements(closure, spec) => showExpr(closure) <+> "implements" <+> showMisc(spec)

Expand Down Expand Up @@ -742,6 +762,12 @@ class ShortPrettyPrinter extends DefaultPrettyPrinter {
"pred" <+> showReceiver(recv) <+> showId(id) <> parens(showParameterList(args))
case ip: PImplementationProof =>
showType(ip.subT) <+> "implements" <+> showType(ip.superT)
case PConstructDecl(typ, args, posts, _, isShared) =>
hcat(posts map (showPost(_) <> line)) <> "construct" <+> (if (isShared) "&" else emptyDoc) <> showType(typ) <> parens(showParameterList(args))
case PDerefDecl(typ, args, _, pres, _, isShared, _) =>
hcat(pres map (showPre(_) <> line)) <> "pure deref" <+> (if (isShared) "&" else emptyDoc) <> showType(typ) <> parens(showParameterList(args))
case PAssignDecl(typ, args, spec, _, isShared) =>
showSpec(spec) <> "assign" <+> (if (isShared) "&" else emptyDoc) <> showType(typ) <> parens(showParameterList(args))
}
}

Expand Down
Loading