@@ -3,23 +3,25 @@ package org.usvm
33import org.usvm.StepScope.StepScopeState.CANNOT_BE_PROCESSED
44import org.usvm.StepScope.StepScopeState.CAN_BE_PROCESSED
55import org.usvm.StepScope.StepScopeState.DEAD
6+ import org.usvm.forkblacklists.UForkBlackList
67
78/* *
8- * An auxiliary class, which carefully maintains forks and asserts via [fork ] and [assert].
9+ * An auxiliary class, which carefully maintains forks and asserts via [forkWithBlackList ] and [assert].
910 * It should be created on every step in an interpreter.
1011 * You can think about an instance of [StepScope] as a monad `ExceptT null (State [T])`.
1112 *
1213 * This scope is considered as [DEAD], iff the condition in [assert] was unsatisfiable or unknown.
1314 * The underlying state cannot be processed further (see [CANNOT_BE_PROCESSED]),
14- * if the first passed to [fork ] or [forkMulti ] condition was unsatisfiable or unknown.
15+ * if the first passed to [forkWithBlackList ] or [forkMultiWithBlackList ] condition was unsatisfiable or unknown.
1516 *
1617 * To execute some function on a state, you should use [doWithState] or [calcOnState]. `null` is returned, when
1718 * this scope cannot be processed on the current step - see [CANNOT_BE_PROCESSED].
1819 *
1920 * @param originalState an initial state.
2021 */
21- class StepScope <T : UState <Type , * , * , Context , * , T >, Type , Context : UContext >(
22+ class StepScope <T : UState <Type , * , Statement , Context , * , T >, Type , Statement , Context : UContext >(
2223 private val originalState : T ,
24+ private val forkBlackList : UForkBlackList <T , Statement >
2325) {
2426 private val forkedStates = mutableListOf<T >()
2527
@@ -145,6 +147,66 @@ class StepScope<T : UState<Type, *, *, Context, *, T>, Type, Context : UContext>
145147 return posState?.let { }
146148 }
147149
150+ /* *
151+ * [forkWithBlackList] version which doesn't fork to the branches with statements
152+ * banned by underlying [forkBlackList].
153+ *
154+ * @param trueStmt statement to fork on [condition].
155+ * @param falseStmt statement to fork on ![condition].
156+ */
157+ fun forkWithBlackList (
158+ condition : UBoolExpr ,
159+ trueStmt : Statement ,
160+ falseStmt : Statement ,
161+ blockOnTrueState : T .() -> Unit = {},
162+ blockOnFalseState : T .() -> Unit = {},
163+ ): Unit? {
164+ check(canProcessFurtherOnCurrentStep)
165+
166+ val shouldForkOnTrue = forkBlackList.shouldForkTo(originalState, trueStmt)
167+ val shouldForkOnFalse = forkBlackList.shouldForkTo(originalState, falseStmt)
168+
169+ if (! shouldForkOnTrue && ! shouldForkOnFalse) {
170+ stepScopeState = DEAD
171+ // TODO: should it be null?
172+ return null
173+ }
174+
175+ if (shouldForkOnTrue && shouldForkOnFalse) {
176+ return fork(condition, blockOnTrueState, blockOnFalseState)
177+ }
178+
179+ // TODO: asserts are implemented via forkMulti and create an unused copy of state
180+ if (shouldForkOnTrue) {
181+ return assert (condition, blockOnTrueState)
182+ }
183+
184+ return assert (condition.uctx.mkNot(condition), blockOnFalseState)
185+ }
186+
187+ /* *
188+ * [forkMultiWithBlackList] version which doesn't fork to the branches with statements
189+ * banned by underlying [forkBlackList].
190+ */
191+ fun forkMultiWithBlackList (forkCases : List <ForkCase <T , Statement >>) {
192+ check(canProcessFurtherOnCurrentStep)
193+
194+ val filteredConditionsWithBlockOnStates = forkCases
195+ .mapNotNull { case ->
196+ if (! forkBlackList.shouldForkTo(originalState, case.stmt)) {
197+ return @mapNotNull null
198+ }
199+ case.condition to case.block
200+ }
201+
202+ if (filteredConditionsWithBlockOnStates.isEmpty()) {
203+ stepScopeState = DEAD
204+ return
205+ }
206+
207+ return forkMulti(filteredConditionsWithBlockOnStates)
208+ }
209+
148210 /* *
149211 * Represents the current state of this [StepScope].
150212 */
@@ -154,12 +216,12 @@ class StepScope<T : UState<Type, *, *, Context, *, T>, Type, Context : UContext>
154216 */
155217 DEAD ,
156218 /* *
157- * Cannot be forked or asserted using [fork ], [forkMulti ] or [assert],
219+ * Cannot be forked or asserted using [forkWithBlackList ], [forkMultiWithBlackList ] or [assert],
158220 * but is considered as alive from the Machine's point of view.
159221 */
160222 CANNOT_BE_PROCESSED ,
161223 /* *
162- * Can be forked using [fork ] or [forkMulti ] and asserted using [assert].
224+ * Can be forked using [forkWithBlackList ] or [forkMultiWithBlackList ] and asserted using [assert].
163225 */
164226 CAN_BE_PROCESSED ;
165227 }
@@ -176,3 +238,18 @@ class StepResult<T>(
176238 operator fun component1 () = forkedStates
177239 operator fun component2 () = originalStateAlive
178240}
241+
242+ data class ForkCase <T , Statement >(
243+ /* *
244+ * Condition to branch on.
245+ */
246+ val condition : UBoolExpr ,
247+ /* *
248+ * Statement to branch on.
249+ */
250+ val stmt : Statement ,
251+ /* *
252+ * Block to execute on state after branch.
253+ */
254+ val block : T .() -> Unit
255+ )
0 commit comments