-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathExecutionFlowController.scala
More file actions
162 lines (131 loc) · 6.99 KB
/
Copy pathExecutionFlowController.scala
File metadata and controls
162 lines (131 loc) · 6.99 KB
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2011-2019 ETH Zurich.
package viper.silicon.rules
import viper.silicon.Config.ExhaleMode
import viper.silicon.interfaces._
import viper.silicon.logger.records.data.CommentRecord
import viper.silicon.state.State
import viper.silicon.verifier.Verifier
trait ExecutionFlowRules extends SymbolicExecutionRules {
def locallyWithResult[R](s: State, v: Verifier)
(block: (State, Verifier, R => VerificationResult) => VerificationResult)
(Q: R => VerificationResult)
: VerificationResult
def locally(s: State, v: Verifier)
(block: (State, Verifier) => VerificationResult)
: VerificationResult
// def tryOrFailWithResult[R](s: State, v: Verifier)
// (block: (State, Verifier, (State, R, Verifier) => VerificationResult, Failure => VerificationResult) => VerificationResult)
// (Q: (State, R, Verifier) => VerificationResult)
// : VerificationResult
//
// def tryOrFail(s: State, v: Verifier)
// (block: (State, Verifier, (State, Verifier) => VerificationResult, Failure => VerificationResult) => VerificationResult)
// (Q: (State, Verifier) => VerificationResult)
// : VerificationResult
def tryOrFail0(s: State, v: Verifier)
(action: (State, Verifier, (State, Verifier) => VerificationResult) => VerificationResult)
(Q: (State, Verifier) => VerificationResult)
: VerificationResult
def tryOrFail1[R1](s: State, v: Verifier)
(action: (State, Verifier, (State, R1, Verifier) => VerificationResult) => VerificationResult)
(Q: (State, R1, Verifier) => VerificationResult)
: VerificationResult
def tryOrFail2[R1, R2](s: State, v: Verifier)
(action: (State, Verifier, (State, R1, R2, Verifier) => VerificationResult) => VerificationResult)
(Q: (State, R1, R2, Verifier) => VerificationResult)
: VerificationResult
}
object executionFlowController extends ExecutionFlowRules {
def locallyWithResult[R](s: State, v: Verifier)
(block: (State, Verifier, R => VerificationResult) => VerificationResult)
(Q: R => VerificationResult)
: VerificationResult = {
var optBlockData: Option[R] = None
v.decider.pushScope()
val blockResult: VerificationResult =
block(s, v, blockData => {
Predef.assert(optBlockData.isEmpty,
"Unexpectedly found more than one block data result. Note that the local "
+ "block is not expected to branch (non-locally)")
optBlockData = Some(blockData)
Success()})
v.decider.popScope()
blockResult match {
case _: FatalResult =>
/* If the local block yielded a fatal result, then the continuation Q
* will not be invoked. That is, the current execution path will be
* terminated.
*/
blockResult
case _: NonFatalResult =>
/* If the local block yielded a non-fatal result, then the continuation
* will only be invoked if the execution of the block yielded data
* that the continuation Q can be invoked with, i.e. a result of type D.
* If the block's execution did not yield such a result, then the
* current execution path will be terminated.
*/
optBlockData match {
case Some(localData) => blockResult && Q(localData)
case None => blockResult
}
}
}
def locally(s: State, v: Verifier)
(block: (State, Verifier) => VerificationResult)
: VerificationResult =
locallyWithResult[VerificationResult](s, v)((s1, v1, QL) => QL(block(s1, v1)))(Predef.identity)
private def tryOrFailWithResult[R](s: State, v: Verifier)
(action: (State, Verifier, (State, R, Verifier) => VerificationResult) => VerificationResult)
(Q: (State, R, Verifier) => VerificationResult)
: VerificationResult = {
var localActionSuccess = false
/* TODO: Consider how to handle situations where the action branches and the first branch
* succeeds, i.e. localActionSuccess has been set to true, but the second fails.
* Currently, the verification will fail without attempting to remedy the situation,
* e.g. by performing a state consolidation.
*/
val firstActionResult = {
action(
s.copy(retryLevel = s.retryLevel + 1),
v,
(s1, r, v1) => {
localActionSuccess = true
Q(s1.copy(retryLevel = s.retryLevel), r, v1)})
}
val finalActionResult =
if ( localActionSuccess /* Action succeeded locally */
|| !firstActionResult.isFatal) /* Action yielded non-fatal result (e.g. because the
* current branch turned out to be infeasible) */
firstActionResult
else {
val s0 = v.stateConsolidator.consolidate(s, v)
val comLog = new CommentRecord("Retry", s0, v.decider.pcs)
val sepIdentifier = v.symbExLog.openScope(comLog)
val temporaryMCE = Verifier.config.exhaleMode != ExhaleMode.Greedy
action(s0.copy(retrying = true, retryLevel = s.retryLevel, moreCompleteExhale = temporaryMCE), v, (s1, r, v1) => {
v1.symbExLog.closeScope(sepIdentifier)
Q(s1.copy(retrying = false, moreCompleteExhale = s0.moreCompleteExhale), r, v1)
})
}
finalActionResult
}
def tryOrFail0(s: State, v: Verifier)
(action: (State, Verifier, (State, Verifier) => VerificationResult) => VerificationResult)
(Q: (State, Verifier) => VerificationResult)
: VerificationResult =
tryOrFailWithResult[scala.Null](s, v)((s1, v1, QS) => action(s1, v1, (s2, v2) => QS(s2, null, v2)))((s2, _, v2) => Q(s2, v2))
def tryOrFail1[R1](s: State, v: Verifier)
(action: (State, Verifier, (State, R1, Verifier) => VerificationResult) => VerificationResult)
(Q: (State, R1, Verifier) => VerificationResult)
: VerificationResult =
tryOrFailWithResult[R1](s, v)(action)(Q)
def tryOrFail2[R1, R2](s: State, v: Verifier)
(action: (State, Verifier, (State, R1, R2, Verifier) => VerificationResult) => VerificationResult)
(Q: (State, R1, R2, Verifier) => VerificationResult)
: VerificationResult =
tryOrFailWithResult[(R1, R2)](s, v)((s1, v1, QS) => action(s1, v1, (s2, r21, r22, v2) => QS(s2, (r21, r22), v2)))((s2, r, v2) => Q(s2, r._1, r._2, v2))
}