summaryrefslogtreecommitdiff
path: root/Chalice/tests/examples/lseg.chalice
blob: c7b6421ab134a8a6e4b225c3f860dc168ac3252e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class Node {
  var next : Node;
  var val : int;
  /* ghost */ var length : int;

  predicate lseg {
    acc(length) && length > 0 && acc(next) && acc(val) && (length > 1 ==> next != null && next.lseg && next.lseg_length() + 1 == this.length)
  }

  function lseg_length() : int
    requires lseg
	{
	  unfolding lseg in length
	}

  function elems() : seq<int>
    requires lseg
	{
	  unfolding lseg in (length == 1 ? [val] : [val] ++ next.elems())
	}

  function end() : Node
    requires lseg
	{
	  unfolding lseg in (length == 1 ? next : next.end())
	}

  /* ghost */ method addAtEndRec(n:Node)
    requires lseg && acc(n.*)
    ensures lseg
    ensures elems() == old(elems()) ++ [old(n.val)]
    ensures end() == old(n.next)
	ensures lseg_length() == old(lseg_length()) + 1
    {
      unfold this.lseg;
      if (length == 1) {
        this.next := n
        n.length := 1
        fold n.lseg
	  } else {
        call this.next.addAtEndRec(n)
      }
      this.length := this.length + 1
      fold this.lseg
    }

	method addAtEnd(v: int)
		requires lseg
		requires this.end() == null
		ensures lseg
		ensures elems() == old(elems()) ++ [v]
	{
		var cur: Node := this
		unfold lseg
		while (cur.next != null)
			invariant acc(cur.*)
			invariant this != cur ==> this.lseg && this.end() == cur
			invariant cur.length > 0 && (cur.length > 1 ==> cur.next != null && cur.next.lseg) && (cur.length == 1 ? cur.next : cur.next.end()) == null
			invariant ((this == cur ? [] : this.elems())
						++ [cur.val]
						++ (cur.next == null ? [] : cur.next.elems())) == old(this.elems())
		{
			/* ghost */ var temp: Node := cur
			cur := cur.next 
			if (this == temp) {
				this.length := 1
				fold lseg
			} else {
				call addAtEndRec(temp)
			}
			unfold cur.lseg
		}

	  var n: Node := new Node
	  n.val := v
	  n.next := null
	  cur.next := n
	  if(cur == this) {
		this.length := 1
		fold lseg
	  } else {
		call addAtEndRec(cur)
	  }
	  call addAtEndRec(n)			
	}
}