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 pushScope, popScope, hide and reveal commands #891

Merged
merged 26 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
65d0345
Split code refactoring
keyboardDrummer Jun 10, 2024
9870fea
Use expect files for split test
keyboardDrummer Jun 10, 2024
9f0d713
Add new split related test
keyboardDrummer Jun 11, 2024
8a118c7
Add new prune mode
keyboardDrummer Jun 12, 2024
6ed64bf
Fixes
keyboardDrummer Jun 12, 2024
b4c04bb
IsBlind field for implementations
keyboardDrummer Jun 13, 2024
3b50887
Allow functions to be always revealed
keyboardDrummer Jun 13, 2024
68c8c95
Fix bug in FindReachableNodesInGraphWithMergeNodes
keyboardDrummer Jun 24, 2024
4c1cf1b
Incorrect intermediate state
keyboardDrummer Jun 28, 2024
425ad07
Save state
keyboardDrummer Jun 28, 2024
a8dd806
Reveal.bpl works again but with hide statements instead of blind impl…
keyboardDrummer Jun 28, 2024
d623f3d
Implement scoping for hide and reveal
keyboardDrummer Jul 1, 2024
ee992ed
Fixes
keyboardDrummer Jul 1, 2024
41fe76a
Move some classes into separate files
keyboardDrummer Jul 1, 2024
c1d20b9
Merge branch 'prepHideRevealRefactor' (early part) into splits
keyboardDrummer Jul 2, 2024
ed7da0b
Merge branch 'prepHideRevealRefactor' into splits
keyboardDrummer Jul 2, 2024
0f68c37
Merge remote-tracking branch 'origin/master' into splits
keyboardDrummer Jul 2, 2024
8e8fcd9
Work around keyword issue
keyboardDrummer Jul 2, 2024
8c9c1c1
Remove garbage
keyboardDrummer Jul 2, 2024
d33ec71
Fix whitespace
keyboardDrummer Jul 2, 2024
f875217
Add missing copy
keyboardDrummer Jul 2, 2024
ac628a1
Fixes
keyboardDrummer Jul 2, 2024
603f8ea
Add comments
keyboardDrummer Jul 2, 2024
c64b405
Refactoring
keyboardDrummer Jul 2, 2024
7bb898f
Refactoring
keyboardDrummer Jul 2, 2024
3c4de4d
Update version
keyboardDrummer Jul 2, 2024
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
MSBuild_Logs/

.lit_test_times.txt

# Nuget
Source/packages/

Expand Down
5 changes: 5 additions & 0 deletions Source/AbstractInterpretation/NativeLattice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@ NativeLattice.Element Step(NativeLattice lattice, Cmd cmd, NativeLattice.Element
{
// skip
}
else if (cmd is HideRevealCmd) {
// skip
} else if (cmd is ChangeScope) {
// skip
}
else
{
Contract.Assert(false); // unknown command
Expand Down
48 changes: 27 additions & 21 deletions Source/Core/AST/Absy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -576,13 +576,14 @@ public override void Emit(TokenTextWriter stream, int level)

public class Axiom : Declaration
{
public bool CanHide { get; set; }

public override string ToString()
{
return "Axiom: " + expression.ToString();
}

private Expr /*!*/
expression;
private Expr /*!*/ expression;

public Expr Expr
{
Expand All @@ -606,24 +607,25 @@ void ExprInvariant()

public string Comment;

public Axiom(IToken tok, Expr expr)
: this(tok, expr, null)
public Axiom(IToken tok, Expr expr, bool canHide = false)
: this(tok, expr, null, canHide)
{
Contract.Requires(expr != null);
Contract.Requires(tok != null);
}

public Axiom(IToken /*!*/ tok, Expr /*!*/ expr, string comment)
public Axiom(IToken /*!*/ tok, Expr /*!*/ expr, string comment, bool canHide = false)
: base(tok)
{
Contract.Requires(tok != null);
Contract.Requires(expr != null);
this.expression = expr;
Comment = comment;
CanHide = canHide;
}

public Axiom(IToken tok, Expr expr, string comment, QKeyValue kv)
: this(tok, expr, comment)
public Axiom(IToken tok, Expr expr, string comment, QKeyValue kv, bool canHide = false)
: this(tok, expr, comment, canHide)
{
Contract.Requires(expr != null);
Contract.Requires(tok != null);
Expand Down Expand Up @@ -3516,7 +3518,6 @@ public Block getBlock(string label)
}

public class Implementation : DeclWithFormals {

public List<Variable> LocVars;

[Rep] public StmtList StructuredStmts;
Expand Down Expand Up @@ -4447,26 +4448,31 @@ override public void ResetAbstractInterpretationState()
/// </summary>
public void ComputePredecessorsForBlocks()
{
foreach (Block b in this.Blocks)
var blocks = this.Blocks;
foreach (Block b in blocks)
{
b.Predecessors = new List<Block>();
}

foreach (Block b in this.Blocks)
{
GotoCmd gtc = b.TransferCmd as GotoCmd;
if (gtc != null)
ComputePredecessorsForBlocks(blocks);

this.BlockPredecessorsComputed = true;
}

public static void ComputePredecessorsForBlocks(List<Block> blocks)
{
foreach (var block in blocks) {
if (block.TransferCmd is not GotoCmd gtc) {
continue;
}

Contract.Assert(gtc.labelTargets != null);
foreach (var /*!*/ dest in gtc.labelTargets)
{
Contract.Assert(gtc.labelTargets != null);
foreach (Block /*!*/ dest in gtc.labelTargets)
{
Contract.Assert(dest != null);
dest.Predecessors.Add(b);
}
Contract.Assert(dest != null);
dest.Predecessors.Add(block);
}
}

this.BlockPredecessorsComputed = true;
}

public void PruneUnreachableBlocks(CoreOptions options)
Expand Down
16 changes: 12 additions & 4 deletions Source/Core/AST/AbsyCmd.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public string LabelName

[Rep] private List<Cmd> /*!*/ _simpleCmds;

/// <summary>
/// These come before the structured command
/// </summary>
public List<Cmd> /*!*/ simpleCmds
{
get
Expand Down Expand Up @@ -1189,8 +1192,7 @@ public override void Emit(TokenTextWriter stream, int level)
// Block
public sealed class Block : Absy
{
private string /*!*/
label; // Note, Label is mostly readonly, but it can change to the name of a nearby block during block coalescing and empty-block removal
private string /*!*/ label; // Note, Label is mostly readonly, but it can change to the name of a nearby block during block coalescing and empty-block removal

public string /*!*/ Label
{
Expand Down Expand Up @@ -1257,8 +1259,7 @@ public int
iterations; // Count the number of time we visited the block during fixpoint computation. Used to decide if we widen or not

// VC generation and SCC computation
public List<Block> /*!*/
Predecessors;
public List<Block> /*!*/ Predecessors;

// This field is used during passification to null-out entries in block2Incarnation dictionary early
public int succCount;
Expand Down Expand Up @@ -1548,6 +1549,13 @@ public static byte[] CombineChecksums(byte[] first, byte[] second, bool unordere
}
}

/// <summary>
/// Could have also been called a statement.
///
/// Does not include commands that contain other commands,
/// for those, look at StructuredCmd
///
/// </summary>
[ContractClass(typeof(CmdContracts))]
public abstract class Cmd : Absy
{
Expand Down
34 changes: 34 additions & 0 deletions Source/Core/AST/ChangeScope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#nullable enable
using System.Collections.Generic;

namespace Microsoft.Boogie;

/// <summary>
/// Allows pushing and popping scopes inside a Boogie implementation.
///
/// Right now these scopes only affect the state of what functions are hidden and revealed using the hide and reveal keywords.
/// However, in the future these scopes should also allow lexical scoping and variable shadowing.
/// </summary>
public class ChangeScope : Cmd {
public bool Push { get; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An enum of Push and Pop would be a bit nicer than a bool here.


public ChangeScope(IToken tok, bool push) : base(tok) {
Push = push;
}

public override void Resolve(ResolutionContext rc) {
}

public override void Typecheck(TypecheckingContext tc) {
}

public override void Emit(TokenTextWriter stream, int level) {
}

public override void AddAssignedVariables(List<Variable> vars) {
}

public override Absy StdDispatch(StandardVisitor visitor) {
return this;
}
}
4 changes: 2 additions & 2 deletions Source/Core/AST/Expression/FunctionCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void ObjectInvariant()
Contract.Invariant(name != null);
}

public FunctionCall createUnresolvedCopy()
public FunctionCall CreateUnresolvedCopy()
{
return new FunctionCall(new IdentifierExpr(name.tok, name.Name, name.Type));
}
Expand All @@ -72,7 +72,7 @@ public override int GetHashCode()
return Func.GetHashCode();
}

virtual public void Emit(IList<Expr> args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext)
public virtual void Emit(IList<Expr> args, TokenTextWriter stream, int contextBindingStrength, bool fragileContext)
{
//Contract.Requires(stream != null);
//Contract.Requires(args != null);
Expand Down
54 changes: 54 additions & 0 deletions Source/Core/AST/HideRevealCmd.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#nullable enable
using System.Collections.Generic;

namespace Microsoft.Boogie;

/// <summary>
/// Can be used to hide or reveal a specific function, or all functions
/// If pruning is turned on, a hidden function will be pruned despite being referenced in a Boogie implementation.
/// The function is only partially pruned though: the function definition itself is kept, and only axioms
/// that the function depends on, that are marked as hideable, are pruned.
///
/// Hide and revealing takes into account lexical scoping:
/// A popScope command will undo any hide and reveal operations that came after the last pushScope command.
/// </summary>
public class HideRevealCmd : Cmd {
public bool Hide { get; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to push/pop, an enum would be nicer than a bool here.

private readonly FunctionCall? functionCall;

public HideRevealCmd(IToken tok, bool hide) : base(tok) {
this.Hide = hide;
}

public HideRevealCmd(IdentifierExpr name, bool hide) : base(name.tok) {
this.Hide = hide;
this.functionCall = new FunctionCall(name);
}

public Function? Function => functionCall?.Func;

public override void Resolve(ResolutionContext rc)
{
functionCall?.Resolve(rc, null);
}

public override void Typecheck(TypecheckingContext tc)
{
}

public override void Emit(TokenTextWriter stream, int level)
{
stream.Write(this, level, Hide ? "hide " : "reveal ");
stream.Write(this, level, Function == null ? "*" : Function.Name);
stream.WriteLine(";");
}

public override void AddAssignedVariables(List<Variable> vars)
{
}

public override Absy StdDispatch(StandardVisitor visitor)
{
return visitor.VisitRevealCmd(this);
}
}
38 changes: 30 additions & 8 deletions Source/Core/BoogiePL.atg
Original file line number Diff line number Diff line change
Expand Up @@ -564,11 +564,16 @@ VarOrType<out TypedIdent/*!*/ tyd, out QKeyValue kv>

/*------------------------------------------------------------------------*/
Axiom<out Axiom/*!*/ m>
= (.Contract.Ensures(Contract.ValueAtReturn(out m) != null); Expr/*!*/ e; QKeyValue kv = null; .)
= (.
Contract.Ensures(Contract.ValueAtReturn(out m) != null);
Expr/*!*/ e;
QKeyValue kv = null;
bool canHide = false; .)
[ "hideable" (. canHide = true; .) ]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be more inclined to make this an attribute than a keyword, though I don't have a super strong opinion about that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that, especially since adding a parsing keyword is more difficult implementation wise, but I can't really defend introducing keywords for half a feature and not for the other half.

"axiom"
{ Attribute<ref kv> }
(. IToken/*!*/ x = t; .)
Proposition<out e> ";" (. m = new Axiom(x,e, null, kv); .)
Proposition<out e> ";" (. m = new Axiom(x,e, null, kv, canHide); .)
.

/*------------------------------------------------------------------------*/
Expand Down Expand Up @@ -1110,8 +1115,24 @@ LabelOrCmd<out Cmd c, out IToken label>
c = dummyCmd; label = null;
Cmd/*!*/ cn;
QKeyValue kv = null;
bool isHide;
IdentifierExpr hideRevealId = null;
.)
( LabelOrAssign<out c, out label>
( (
( "reveal" (. isHide = false; .)
| "hide" (. isHide = true; .)
)
( ident (. hideRevealId = new IdentifierExpr(t, t.val); .)
| "*"
)
(. c = hideRevealId == null ? new HideRevealCmd(t, isHide) : new HideRevealCmd(hideRevealId, isHide); .)
";"
)
| LabelOrAssign<out c, out label>
| "popScope" (. c = new ChangeScope(t, false); .)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think anything else in Boogie, the language, uses camel case like this. I'd maybe prefer just push and pop. The word Scope doesn't really tell you what kind of scope it is, so I'm not sure it adds much.

";"
| "pushScope" (. c = new ChangeScope(t, true); .)
";"
| "assert" (. x = t; .)
{ Attribute<ref kv> }
Proposition<out e> (. c = new AssertCmd(x, e, kv); .)
Expand Down Expand Up @@ -1682,17 +1703,17 @@ Attribute<ref QKeyValue kv>

AttributeOrTrigger<ref QKeyValue kv, ref Trigger trig>
= (. IToken/*!*/ tok; Expr/*!*/ e; List<Expr>/*!*/ es;
string key;
IToken id;
List<object/*!*/> parameters; object/*!*/ param;
.)
"{" (. tok = t; .)
(
":" ident (. key = t.val; parameters = new List<object/*!*/>(); .)
":" Ident<out id> (. parameters = new List<object/*!*/>(); .)
[ AttributeParameter<out param> (. parameters.Add(param); .)
{ "," AttributeParameter<out param> (. parameters.Add(param); .)
}
]
(. if (key == "nopats") {
(. if (id.val == "nopats") {
if (parameters.Count == 1 && parameters[0] is Expr) {
e = (Expr)parameters[0];
if(trig==null){
Expand All @@ -1705,9 +1726,9 @@ AttributeOrTrigger<ref QKeyValue kv, ref Trigger trig>
}
} else {
if (kv==null) {
kv = new QKeyValue(tok, key, parameters, null);
kv = new QKeyValue(tok, id.val, parameters, null);
} else {
kv.AddLast(new QKeyValue(tok, key, parameters, null));
kv.AddLast(new QKeyValue(tok, id.val, parameters, null));
}
}
.)
Expand Down Expand Up @@ -1812,6 +1833,7 @@ Ident<out IToken/*!*/ x>
| "both" (. t.kind = _ident; .) // convert to ident
| "left" (. t.kind = _ident; .) // convert to ident
| "right" (. t.kind = _ident; .) // convert to ident
| "hide" (. t.kind = _ident; .) // convert to ident
)
(.
x = t;
Expand Down
1 change: 0 additions & 1 deletion Source/Core/CoreOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

namespace Microsoft.Boogie
{

/// <summary>
/// Boogie command-line options (other tools can subclass this class in order to support a
/// superset of Boogie's options).
Expand Down
5 changes: 5 additions & 0 deletions Source/Core/DeadVarElim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,11 @@ public void Propagate(Cmd cmd, HashSet<Variable /*!*/> /*!*/ liveSet)
else if (cmd is CommentCmd)
{
// comments are just for debugging and don't affect verification
} else if (cmd is HideRevealCmd)
{
// reveal references no variables
} else if (cmd is ChangeScope)
{
}
else if (cmd is SugaredCmd)
{
Expand Down
Loading
Loading