List Iterator (Magic Wands)

An iterator protocol, for iterating over a linked list. The protocol has 3 states and some state-transitions are encoded using magic wands. Note: this example uses a feature which is currently only supported by the default verifier.

/* This example is based on the list iterator example, created by Blom and Huisman, which is available at * https://github.com/utwente-fmt/vercors/blob/master/examples/witnesses/ListIterator.java. * * This example encodes an iterator over a linked list. The iterator protocol consists of 3 states: * "ready" is the initial state * "ready for next" indicates that the iterator can advance a step * "ready for remove" indicates that the Iterator_current element can be removed from the list * * The protocol followed indicates, that the Iterator_hasNext() method of the iterator in the "ready" state can be used * to transition to the "ready for next" state iff there is a next element in the list. Furthermore the iterator's * Iterator_next() method can only be called in the "ready for next" state and transitions the iterator to the "ready for * remove" state. From the "ready for remove" state it is possible to transition to the "ready" state directly or * by calling the Iterator_remove() method to remove the current item. It is moreover possible to get back access to the * linked list by giving up access to the iterator in the "ready" state. */ // main method used as an example execution using the Iterator class method main(l: Ref) requires l!=null && List_state(l) ensures l!=null && List_state(l) { var b: Bool // add some values to the list List_put(l, 1) List_put(l, 0) List_put(l, -1) // create an iterator var i: Ref i := Iterator_new(l) // check if there is a first element b := Iterator_hasNext(i) // loop over the list using the iterator while(b) invariant b ==> Iterator_readyForNext(i) invariant !b ==> Iterator_ready(i) { // get the next value in the list var tmp: Int tmp := Iterator_next(i) // transition to the "ready" state by... if (tmp < 0) { // ... removing the element Iterator_remove(i) } else { // ... using the provided magic wand for a direct transition apply Iterator_readyForRemove(i) --* Iterator_ready(i) } // check if the end of the list has been reached b := Iterator_hasNext(i) } // get back access to the list, by giving up the iterator apply Iterator_ready(i) --* List_state(l) } ////////////////////// Iterator class ////////////////////// // fields of the iterator field Iterator_iteratee: Ref field Iterator_current: Ref field Iterator_last: Ref // encodes the "ready" state predicate Iterator_ready(this: Ref) { // needs a list to iterate over acc(this.Iterator_iteratee, 1/2) && this.Iterator_iteratee!=null && acc(this.Iterator_iteratee.List_sentinel) && this.Iterator_iteratee.List_sentinel!=null // needs access to the current and previous entry and the current entry cannot be null && acc(this.Iterator_current) && acc(this.Iterator_last) && this.Iterator_current!=null // needs access to the fields of the current node && acc(this.Iterator_current.Node_val) && acc(this.Iterator_current.Node_next)&&acc(this.Iterator_current.Node_prev) // only the sentinel node has no predecessor && (this.Iterator_current.Node_prev == null ==> this.Iterator_current == this.Iterator_iteratee.List_sentinel) // the predicate structure of the previous part of the list has been reversed && (this.Iterator_current.Node_prev != null ==> Node_reverse(this.Iterator_current.Node_prev) && Node_first(this.Iterator_current.Node_prev) == this.Iterator_iteratee.List_sentinel && Node_rev_next(this.Iterator_current.Node_prev) == this.Iterator_current) // the remainder of the list has not been reversed && (this.Iterator_current.Node_next != null ==> Node_state(this.Iterator_current.Node_next))} // encodes the "ready for next" state predicate Iterator_readyForNext(this: Ref) { // needs a list to iterate over acc(this.Iterator_iteratee, 1/2) && this.Iterator_iteratee!=null && acc(this.Iterator_iteratee.List_sentinel) && this.Iterator_iteratee.List_sentinel!=null // needs access to the current and previous entry and the current entry cannot be null && acc(this.Iterator_current) && acc(this.Iterator_last) && this.Iterator_current!=null // needs access to the fields of the current node && acc(this.Iterator_current.Node_val) && acc(this.Iterator_current.Node_next) && acc(this.Iterator_current.Node_prev) // only the sentinel node has no predecessor && (this.Iterator_current.Node_prev == null ==> this.Iterator_current == this.Iterator_iteratee.List_sentinel) // the predicate structure of the previous part of the list has been reversed && (this.Iterator_current.Node_prev!=null ==> Node_reverse(this.Iterator_current.Node_prev) && Node_first(this.Iterator_current.Node_prev) == this.Iterator_iteratee.List_sentinel && Node_rev_next(this.Iterator_current.Node_prev) == this.Iterator_current) // the remainder of the list has not been reversed && (this.Iterator_current.Node_next != null ==> Node_state(this.Iterator_current.Node_next)) // we now additionally know that there is a next element && this.Iterator_current.Node_next != null} // encodes the "ready for remove" state predicate Iterator_readyForRemove(this: Ref) { // needs a list to iterate over acc(this.Iterator_iteratee, 1/2) && this.Iterator_iteratee != null && acc(this.Iterator_iteratee.List_sentinel) && this.Iterator_iteratee.List_sentinel != null // needs access to the current and previous entry and the current entry cannot be null && acc(this.Iterator_current) && acc(this.Iterator_last) && this.Iterator_current!=null // needs access to the fields of the current node && acc(this.Iterator_current.Node_val) && acc(this.Iterator_current.Node_next) && acc(this.Iterator_current.Node_prev) // only the sentinel node has no predecessor && (this.Iterator_current.Node_prev == null ==> this.Iterator_current == this.Iterator_iteratee.List_sentinel) // the remainder of the list has not been reversed && (this.Iterator_current.Node_next != null ==> Node_state(this.Iterator_current.Node_next)) // the predecessor of current is last && this.Iterator_current.Node_prev == this.Iterator_last // there is a previous node, i.e. current is not the sentinel node and we have access to its fields && this.Iterator_last != null && acc(this.Iterator_last.Node_val) && acc(this.Iterator_last.Node_next) && acc(this.Iterator_last.Node_prev) // if the previous node has no predecessor it is the sentinel node && (this.Iterator_last.Node_prev == null ==> this.Iterator_last == this.Iterator_iteratee.List_sentinel) // the predicate structure of the part of the list before last has been reversed && (this.Iterator_last.Node_prev != null ==> Node_reverse(this.Iterator_last.Node_prev) && Node_first(this.Iterator_last.Node_prev) == this.Iterator_iteratee.List_sentinel && Node_rev_next(this.Iterator_last.Node_prev) == this.Iterator_last) // the next element after last is current && this.Iterator_last.Node_next == this.Iterator_current} // create an iterator for the list l method Iterator_new(l: Ref) returns (this: Ref) requires l!=null && List_state(l) ensures Iterator_ready(this) // the wand can be used to get back access to the list by giving up permissions to the iterator ensures Iterator_ready(this) --* List_state(l) { this := new(Iterator_iteratee,Iterator_current,Iterator_last) unfold List_state(l) this.Iterator_current := l.List_sentinel unfold Node_state(this.Iterator_current) this.Iterator_current.Node_prev := null this.Iterator_iteratee := l fold Iterator_ready(this) package Iterator_ready(this) --* List_state(l) { unfold Iterator_ready(this) fold Node_state(this.Iterator_current) // the predicate structure of the part of the list before current has been reversed. This needs to be undone. if (Node_get_prev(this.Iterator_current) != null){ Node_swap(Node_get_prev(this.Iterator_current), this.Iterator_iteratee.List_sentinel, this.Iterator_current) } /* transferring the remaining 1/2 permissions to this.Iterator_iteratee into the * footprint ensures, that its value cannot be changed, i.e. stays l. */ assert acc(this.Iterator_iteratee) fold List_state(l) } } // check whether there is a next node in the list and transition to the appropriate state method Iterator_hasNext(this: Ref) returns (res: Bool) requires Iterator_ready(this) // we only transition to the "ready for next" state of there is a next element ensures res ==> Iterator_readyForNext(this) // and stay in the "ready" state otherwise ensures !res ==> Iterator_ready(this) { unfold Iterator_ready(this) res := this.Iterator_current.Node_next != null if(!res) { fold Iterator_ready(this) } else { fold Iterator_readyForNext(this) } } // iterate method Iterator_next(this: Ref) returns (res: Int) requires Iterator_readyForNext(this) ensures Iterator_readyForRemove(this) // the wand can be used to transition ot the "ready" state directly, without removing the current element ensures Iterator_readyForRemove(this) --* Iterator_ready(this) { unfold Iterator_readyForNext(this) this.Iterator_last:=this.Iterator_current this.Iterator_current:=this.Iterator_current.Node_next unfold Node_state(this.Iterator_current) res := this.Iterator_current.Node_val this.Iterator_current.Node_prev:=this.Iterator_last fold Iterator_readyForRemove(this) package Iterator_readyForRemove(this) --* Iterator_ready(this) { unfold Iterator_readyForRemove(this) // adds the previous node to the reversed part of the list fold Node_reverse(this.Iterator_current.Node_prev) fold Iterator_ready(this) } } // remove the current node from the list method Iterator_remove(this: Ref) requires Iterator_readyForRemove(this) ensures Iterator_ready(this) { unfold Iterator_readyForRemove(this) this.Iterator_last.Node_next := this.Iterator_current.Node_next this.Iterator_current := this.Iterator_last fold Iterator_ready(this) } ////////////////////// List class ////////////////////// // the sentinel is a node prepended before the first element of the list and is not part of the list field List_sentinel: Ref // represents a valid list predicate List_state(this: Ref){ acc(this.List_sentinel) && this.List_sentinel != null && Node_state(this.List_sentinel)} // create a new empty list method List_new() returns (this: Ref) ensures List_state(this) { this := new(List_sentinel) var sent: Ref sent := Node_new(0,null) this.List_sentinel := sent fold List_state(this) } // add an element to the list method List_put(this: Ref, v: Int) requires List_state(this) ensures List_state(this) { unfold List_state(this) unfold Node_state(this.List_sentinel) var sentNode_next: Ref sentNode_next := Node_new(v,this.List_sentinel.Node_next) this.List_sentinel.Node_next := sentNode_next fold Node_state(this.List_sentinel) fold List_state(this) } ////////////////////// Node class of linked list ////////////////////// // fields of the node field Node_val: Int field Node_prev: Ref field Node_next: Ref // a valid list predicate Node_state(this: Ref) { acc(this.Node_val) && acc(this.Node_prev) && acc(this.Node_next) && (this.Node_next != null ==> Node_state(this.Node_next))} // a valid list, with a reversed predicate structure // i.e. the outer most predicate instance represents the last element of the list predicate Node_reverse(this: Ref) { acc(this.Node_val) && acc(this.Node_prev) && acc(this.Node_next) && (this.Node_prev != null ==> Node_reverse(this.Node_prev) && Node_rev_next(this.Node_prev) == this)} // getters function Node_get_next(this: Ref): Ref requires Node_state(this) { unfolding Node_state(this) in this.Node_next} function Node_get_prev(this: Ref): Ref requires Node_state(this) { unfolding Node_state(this) in this.Node_prev} function Node_rev_next(this: Ref): Ref requires Node_reverse(this) { unfolding Node_reverse(this) in this.Node_next} function Node_rev_prev(this: Ref): Ref requires Node_reverse(this) { unfolding Node_reverse(this) in this.Node_prev} // finds the first node of a list function Node_first(this: Ref): Ref requires Node_reverse(this) { unfolding Node_reverse(this) in (this.Node_prev==null) ? this : Node_first(this.Node_prev) } // create a new node method Node_new(v: Int, n: Ref) returns (this: Ref) requires n != null ==> Node_state(n) ensures Node_state(this) && Node_get_next(this) == n ensures this != null { this := new(Node_val, Node_prev, Node_next) this.Node_val := v this.Node_next := n fold Node_state(this) } // used to undo the reversal of the predicate structure method Node_swap(this: Ref, fst: Ref, nxt: Ref) requires fst != null && Node_reverse(this) && Node_rev_next(this) == nxt && (nxt != null ==> Node_state(nxt)) && Node_first(this) == fst ensures fst != null && Node_state(fst) { unfold Node_reverse(this) if (this.Node_prev == null) { // we have reached the beginning of the list => after undoing the reversal of the predicate we are done fold Node_state(this) } else { // we have not reached the beginning of the list, yet // => undo reversal of current predicate and recursively undo reversal of the remainder of the list var tmp: Ref := this.Node_prev fold Node_state(this) Node_swap(tmp, fst,this) } }