Skip to content

Commit c233296

Browse files
committed
Eval option in debugger and better eval of field accesses for basic chunks
1 parent 44ae57a commit c233296

7 files changed

+67
-27
lines changed

src/main/scala/debugger/SiliconDebugger.scala

+37-11
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,8 @@ class SiliconDebugger(verificationResults: List[VerificationResult],
280280
while (true) {
281281
println(s"\nEnter 'q' to quit, 'z' to zoom in on (i.e., show all children of) an assumption, " +
282282
s"'r' to reset the proof obligation, 'ra' to remove assumptions, 'af' to add free assumptions, " +
283-
s"'ap' prove additional assumptions, 'p' to execute proof, 'c' to change print configuration, " +
284-
s"'s' to change the SMT solver, 't' to change the timeout")
283+
s"'ap' prove additional assumptions, 'e' to evaluate an expression, 'p' to execute proof, " +
284+
s"'c' to change print configuration, 's' to change the SMT solver, 't' to change the timeout")
285285
try {
286286
val userInput = readLine()
287287
userInput.toLowerCase match {
@@ -306,6 +306,8 @@ class SiliconDebugger(verificationResults: List[VerificationResult],
306306
// obl = chooseAssertion(obl)
307307
// println(s"Current obligation:\n$obl")
308308
// assertProofObligation(obl)
309+
case "e" | "eval" =>
310+
obl = evalExpr(obl)
309311
case "p" | "prove" =>
310312
assertProofObligation(obl)
311313
case "c" | "config" =>
@@ -399,8 +401,8 @@ class SiliconDebugger(verificationResults: List[VerificationResult],
399401
if (userInput.isEmpty || userInput.equalsIgnoreCase("s") || userInput.equalsIgnoreCase("skip")) {
400402
obl
401403
} else {
402-
val assumptionE = translateStringToExp(userInput, obl)
403-
evalAssumption(assumptionE, obl, free, obl.v) match {
404+
val assumptionE = translateStringToExp(userInput, obl, true)
405+
evalAssumption(assumptionE, obl, true, free, obl.v) match {
404406
case Some((resS, resT, resE, evalAssumptions)) =>
405407
val allAssumptions = obl.assumptionsExp ++ evalAssumptions + DebugExp.createInstance(assumptionE, resE).withTerm(resT)
406408
obl.copy(s = resS, assumptionsExp = allAssumptions)
@@ -410,13 +412,32 @@ class SiliconDebugger(verificationResults: List[VerificationResult],
410412
}
411413
}
412414

415+
private def evalExpr(obl: ProofObligation): ProofObligation = {
416+
println(s"Enter the expression you want to evaluate:")
417+
val userInput = readLine()
418+
if (userInput.isEmpty || userInput.equalsIgnoreCase("s") || userInput.equalsIgnoreCase("skip")) {
419+
obl
420+
} else {
421+
val assumptionE = translateStringToExp(userInput, obl, false)
422+
evalAssumption(assumptionE, obl, false, false, obl.v) match {
423+
case Some((resS, resT, resE, evalAssumptions)) =>
424+
println("Evaluation successful!")
425+
println("Result: " + resE.toString)
426+
println("Internal result term:" + resT.toString)
427+
obl.copy(s = resS)
428+
case None =>
429+
obl
430+
}
431+
}
432+
}
433+
413434
private def chooseAssertion(obl: ProofObligation): ProofObligation = {
414435
println(s"Enter the assertion or s(skip) to assert the previous assertion again:")
415436
val userInput = readLine()
416437
if (userInput.equalsIgnoreCase("s") || userInput.equalsIgnoreCase("skip")) {
417438
obl
418439
} else {
419-
val assertionE = translateStringToExp(userInput, obl)
440+
val assertionE = translateStringToExp(userInput, obl, true)
420441
var resT: Term = null
421442
var resE: ast.Exp = null
422443
var resV: Verifier = null
@@ -436,7 +457,7 @@ class SiliconDebugger(verificationResults: List[VerificationResult],
436457
}
437458
}
438459

439-
private def translateStringToExp(str: String, obl: ProofObligation): ast.Exp ={
460+
private def translateStringToExp(str: String, obl: ProofObligation, expectBool: Boolean): ast.Exp ={
440461
def parseToPExp(): PExp = {
441462
try {
442463
val fp = new DebugParser()
@@ -453,7 +474,10 @@ class SiliconDebugger(verificationResults: List[VerificationResult],
453474
def typecheckPExp(pexp: PExp): Unit = {
454475
try {
455476
obl.resolver.typechecker.names.check(pexp, None, obl.resolver.typechecker.curMember)
456-
obl.resolver.typechecker.check(pexp, PPrimitiv(PReserved(PKw.Bool)((NoPosition, NoPosition)))())
477+
if (expectBool)
478+
obl.resolver.typechecker.check(pexp, PPrimitiv(PReserved(PKw.Bool)((NoPosition, NoPosition)))())
479+
else
480+
obl.resolver.typechecker.checkTopTyped(pexp, None)
457481
} catch {
458482
case e: Throwable => println(s"Error while typechecking $str: ${e.getMessage}")
459483
throw e
@@ -480,7 +504,7 @@ class SiliconDebugger(verificationResults: List[VerificationResult],
480504
translatePExp(pexp)
481505
}
482506

483-
private def evalAssumption(e: ast.Exp, obl: ProofObligation, isFree: Boolean, v: Verifier): Option[(State, Term, ast.Exp, InsertionOrderedSet[DebugExp])] = {
507+
private def evalAssumption(e: ast.Exp, obl: ProofObligation, assume: Boolean, isFree: Boolean, v: Verifier): Option[(State, Term, ast.Exp, InsertionOrderedSet[DebugExp])] = {
484508
var resT: Term = null
485509
var resS: State = null
486510
var resE: ast.Exp = null
@@ -499,10 +523,12 @@ class SiliconDebugger(verificationResults: List[VerificationResult],
499523

500524
verificationResult match {
501525
case Success() =>
502-
val proved = isFree || resV.decider.prover.assert(resT, None)
526+
val proved = !assume || isFree || resV.decider.prover.assert(resT, None)
503527
if (proved) {
504-
println("Assumption was added successfully!")
505-
resV.asInstanceOf[WorkerVerifier].decider.debuggerAssume(Seq(resT), null)
528+
if (assume) {
529+
println("Assumption was added successfully!")
530+
resV.asInstanceOf[WorkerVerifier].decider.debuggerAssume(Seq(resT), null)
531+
}
506532
Some((resS, resT, resE, evalPcs.assumptionExps))
507533
} else {
508534
println("Fail! Could not prove assumption. Skipping")

src/main/scala/interfaces/state/Chunks.scala

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ trait NonQuantifiedChunk extends GeneralChunk {
2929
val args: Seq[Term]
3030
val argsExp: Option[Seq[ast.Exp]]
3131
val snap: Term
32+
val snapExp: Option[ast.Exp]
3233
override def applyCondition(newCond: Term, newCondExp: Option[ast.Exp]): NonQuantifiedChunk
3334
override def permMinus(perm: Term, permExp: Option[ast.Exp]): NonQuantifiedChunk
3435
override def permPlus(perm: Term, permExp: Option[ast.Exp]): NonQuantifiedChunk

src/main/scala/rules/ChunkSupporter.scala

+7-7
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ trait ChunkSupportRules extends SymbolicExecutionRules {
4747
argsExp: Option[Seq[ast.Exp]],
4848
ve: VerificationError,
4949
v: Verifier)
50-
(Q: (State, Heap, Term, Verifier) => VerificationResult)
50+
(Q: (State, Heap, Term, Option[ast.Exp], Verifier) => VerificationResult)
5151
: VerificationResult
5252

5353
def findChunk[CH <: NonQuantifiedChunk: ClassTag]
@@ -222,15 +222,15 @@ object chunkSupporter extends ChunkSupportRules {
222222
argsExp: Option[Seq[ast.Exp]],
223223
ve: VerificationError,
224224
v: Verifier)
225-
(Q: (State, Heap, Term, Verifier) => VerificationResult)
225+
(Q: (State, Heap, Term, Option[ast.Exp], Verifier) => VerificationResult)
226226
: VerificationResult = {
227227

228-
executionFlowController.tryOrFail2[Heap, Term](s.copy(h = h), v)((s1, v1, QS) => {
228+
executionFlowController.tryOrFail3[Heap, Term, Option[ast.Exp]](s.copy(h = h), v)((s1, v1, QS) => {
229229
val lookupFunction =
230230
if (s1.moreCompleteExhale) moreCompleteExhaleSupporter.lookupComplete _
231231
else lookupGreedy _
232-
lookupFunction(s1, s1.h, resource, args, argsExp, ve, v1)((s2, tSnap, v2) =>
233-
QS(s2.copy(h = s.h), s2.h, tSnap, v2))
232+
lookupFunction(s1, s1.h, resource, args, argsExp, ve, v1)((s2, tSnap, eSnap, v2) =>
233+
QS(s2.copy(h = s.h), s2.h, tSnap, eSnap, v2))
234234
})(Q)
235235
}
236236

@@ -241,14 +241,14 @@ object chunkSupporter extends ChunkSupportRules {
241241
argsExp: Option[Seq[ast.Exp]],
242242
ve: VerificationError,
243243
v: Verifier)
244-
(Q: (State, Term, Verifier) => VerificationResult)
244+
(Q: (State, Term, Option[ast.Exp], Verifier) => VerificationResult)
245245
: VerificationResult = {
246246

247247
val id = ChunkIdentifier(resource, s.program)
248248
val findRes = findChunk[NonQuantifiedChunk](h.values, id, args, v)
249249
findRes match {
250250
case Some(ch) if v.decider.check(IsPositive(ch.perm), Verifier.config.checkTimeout()) =>
251-
Q(s, ch.snap, v)
251+
Q(s, ch.snap, ch.snapExp, v)
252252
case _ if v.decider.checkSmoke(true) =>
253253
Success() // TODO: Mark branch as dead?
254254
case _ =>

src/main/scala/rules/Evaluator.scala

+12-7
Original file line numberDiff line numberDiff line change
@@ -314,15 +314,20 @@ object evaluator extends EvaluationRules {
314314
evalLocationAccess(s, fa, pve, v)((s1, _, tArgs, eArgs, v1) => {
315315
val ve = pve dueTo InsufficientPermission(fa)
316316
val resource = fa.res(s.program)
317-
chunkSupporter.lookup(s1, s1.h, resource, tArgs, eArgs, ve, v1)((s2, h2, tSnap, v2) => {
317+
chunkSupporter.lookup(s1, s1.h, resource, tArgs, eArgs, ve, v1)((s2, h2, tSnap, eSnap, v2) => {
318318
val fr = s2.functionRecorder.recordSnapshot(fa, v2.decider.pcs.branchConditions, tSnap)
319319
val s3 = s2.copy(h = h2, functionRecorder = fr)
320-
val (debugHeapName, debugLabel) = v2.getDebugOldLabel(s3, fa.pos)
321-
val newFa = Option.when(withExp)({
322-
if (s3.isEvalInOld) ast.FieldAccess(eArgs.get.head, fa.field)(e.pos, e.info, e.errT)
323-
else ast.DebugLabelledOld(ast.FieldAccess(eArgs.get.head, fa.field)(), debugLabel)(e.pos, e.info, e.errT)
324-
})
325-
val s4 = if (Verifier.config.enableDebugging() && !s3.isEvalInOld) s3.copy(oldHeaps = s3.oldHeaps + (debugHeapName -> magicWandSupporter.getEvalHeap(s3))) else s3
320+
val (newFa, s4) = if (withExp && eSnap.isEmpty) {
321+
val (debugHeapName, debugLabel) = v2.getDebugOldLabel(s3, fa.pos)
322+
val newFa = Option.when(withExp)({
323+
if (s3.isEvalInOld) ast.FieldAccess(eArgs.get.head, fa.field)(e.pos, e.info, e.errT)
324+
else ast.DebugLabelledOld(ast.FieldAccess(eArgs.get.head, fa.field)(), debugLabel)(e.pos, e.info, e.errT)
325+
})
326+
val s4 = if (Verifier.config.enableDebugging() && !s3.isEvalInOld) s3.copy(oldHeaps = s3.oldHeaps + (debugHeapName -> magicWandSupporter.getEvalHeap(s3))) else s3
327+
(newFa, s4)
328+
} else {
329+
(eSnap, s3)
330+
}
326331
Q(s4, tSnap, newFa, v1)
327332
})
328333
})

src/main/scala/rules/ExecutionFlowController.scala

+7
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,11 @@ object executionFlowController extends ExecutionFlowRules {
172172
: VerificationResult =
173173

174174
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))
175+
176+
def tryOrFail3[R1, R2, R3](s: State, v: Verifier)
177+
(action: (State, Verifier, (State, R1, R2, R3, Verifier) => VerificationResult) => VerificationResult)
178+
(Q: (State, R1, R2, R3, Verifier) => VerificationResult)
179+
: VerificationResult =
180+
181+
tryOrFailWithResult[(R1, R2, R3)](s, v)((s1, v1, QS) => action(s1, v1, (s2, r21, r22, r23, v2) => QS(s2, (r21, r22, r23), v2)))((s2, r, v2) => Q(s2, r._1, r._2, r._3, v2))
175182
}

src/main/scala/rules/MoreCompleteExhaleSupporter.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ object moreCompleteExhaleSupporter extends SymbolicExecutionRules {
197197
argsExp: Option[Seq[ast.Exp]],
198198
ve: VerificationError,
199199
v: Verifier)
200-
(Q: (State, Term, Verifier) => VerificationResult)
200+
(Q: (State, Term, Option[ast.Exp], Verifier) => VerificationResult)
201201
: VerificationResult = {
202202

203203
val id = ChunkIdentifier(resource, s.program)
@@ -213,7 +213,7 @@ object moreCompleteExhaleSupporter extends SymbolicExecutionRules {
213213
summarise(s, relevantChunks, resource, args, argsExp, None, v)((s1, snap, permSum, permSumExp, v1) =>
214214
v.decider.assert(IsPositive(permSum)) {
215215
case true =>
216-
Q(s1, snap, v1)
216+
Q(s1, snap, None, v1)
217217
case false =>
218218
createFailure(ve, v, s1, IsPositive(permSum), permSumExp.map(IsPositive(_)()))
219219
})

src/main/scala/state/Chunks.scala

+1
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ case class MagicWandChunk(id: MagicWandIdentifier,
231231
require(perm.sort == sorts.Perm, s"Permissions $perm must be of sort Perm, but found ${perm.sort}")
232232

233233
override val resourceID = MagicWandID
234+
override val snapExp = None
234235

235236
override def applyCondition(newCond: Term, newCondExp: Option[ast.Exp]) =
236237
withPerm(Ite(newCond, perm, NoPerm), newCondExp.map(nce => ast.CondExp(nce, permExp.get, ast.NoPerm()())()))

0 commit comments

Comments
 (0)