Skip to content

Commit ac08070

Browse files
authored
Merge pull request #2473 from GaloisInc/interpreter-do-blocks
Fix handling of do-blocks in the SAWScript interpreter
2 parents 677070a + 65ba586 commit ac08070

File tree

8 files changed

+292
-97
lines changed

8 files changed

+292
-97
lines changed

intTests/test_sawscript_builtins/misc.log.good

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
("{| 2 |}","2")
1111
("{| [8] |}","[8]")
1212
("f","<<builtin>>")
13-
("do { return 0; }","<<monadic>>")
13+
("do { return 0; }","do {\n (return 0);\n}")
1414
("(record)","{x=3,y=\"abc\"}")
1515
("\\x -> 3","\\ (x : t.7) -> 3")
16-
("return 3","<<monadic>>")
16+
("return 3","return 3")
1717
("(TopLevel)","<<TopLevel>>")
1818
("(ProofScript)","<<proof script>>")
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
Loading file "undefined6.saw"
22
not dead yet
33
still not dead
4-
interpret: undefined
5-
CallStack (from HasCallStack):
6-
error, called at saw-script/src/SAWScript/Interpreter.hs
7-
FAILED
4+
still still not dead
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
// The current behavior of this is gross. Hopefully at some point
2-
// it'll change, so don't rely on it.
3-
//
4-
// We execute into do-blocks until the first actual bind, at which
5-
// point nothing further happens until the monad action is applied.
1+
// As of 20250707, we no longer execute partway into do-blocks at the
2+
// time they're let-bound. So these cases should not crash.
63

74
let m1 = do { undefined; return (); };
85
print "not dead yet";
96
let m2 = do { _ <- return 3; let x = undefined; return (); };
107
print "still not dead";
118
let m3 = do { let x = undefined; return (); };
12-
print "oops we didn't die";
9+
print "still still not dead";

intTests/test_sawscript_builtins/undefined7.log.good

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Loading file "undefined7.saw"
2+
not dead yet
23
interpret: undefined
34
CallStack (from HasCallStack):
45
error, called at saw-script/src/SAWScript/Interpreter.hs
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
// This, unlike the behavior in undefined6, is reasonable and expected.
1+
// This currently doesn't crash unless you execute m.
2+
//
3+
// This is somewhat unexpected, as in theory it should trip on
4+
// undefined evaluating the right hand side of "let m" in
5+
// interpretExpr... or having not done so, file x in the environment
6+
// and then never see it again and not crash at all.
7+
//
8+
// For the time being I'm going to let this pass as an acceptable
9+
// weirdness, and with luck it'll change when other things in the
10+
// interpreter get cleaned up.
211

312
let m = let x = undefined in do { return (); };
13+
print "not dead yet";
14+
m;
415
print "oops didn't die";

saw-central/src/SAWCentral/Value.hs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ module SAWCentral.Value (
167167
runProofScript,
168168
-- used by SAWCentral.Builtins, SAWScript.Interpreter
169169
scriptTopLevel,
170+
llvmTopLevel,
171+
jvmTopLevel,
172+
mirTopLevel,
170173
-- used in SAWScript.Interpreter
171174
-- XXX: probably belongs in SAWSupport
172175
underStateT,
@@ -295,10 +298,18 @@ data Value
295298
| VBuiltin (Value -> TopLevel Value)
296299
| VTerm TypedTerm
297300
| VType Cryptol.Schema
298-
| VReturn Value -- Returned value in unspecified monad
299-
| VBind SS.Pos Value Value
300-
-- ^ Monadic bind in unspecified monad. Requires a source position because
301-
-- operations in these monads can fail at runtime.
301+
-- | Returned value in unspecified monad
302+
| VReturn Value
303+
-- | Not-yet-executed do-block in unspecified monad
304+
--
305+
-- The string is a hack hook for the current implementation of
306+
-- stack traces. See the commit message that added it for further
307+
-- information. XXX: to be removed along with the stack trace code
308+
| VDo SS.Pos (Maybe String) LocalEnv [SS.Stmt]
309+
-- | Single monadic bind in unspecified monad.
310+
-- This exists only to support the "for" builtin; see notes there
311+
-- for why this is so. XXX: remove it once that's no longer needed
312+
| VBindOnce Value Value
302313
| VTopLevel (TopLevel Value)
303314
| VProofScript (ProofScript Value)
304315
| VSimpset SAWSimpset
@@ -443,6 +454,7 @@ showRefnset opts ss =
443454
ppFunAssumpRHS ctx (RewriteFunAssump rhs) =
444455
SAWCorePP.ppTermInCtx opts (map fst $ mrVarCtxInnerToOuter ctx) rhs
445456

457+
-- XXX the precedence in here needs to be cleaned up
446458
showsPrecValue :: PPS.Opts -> DisplayNameEnv -> Int -> Value -> ShowS
447459
showsPrecValue opts nenv p v =
448460
case v of
@@ -467,8 +479,15 @@ showsPrecValue opts nenv p v =
467479
VBuiltin {} -> showString "<<builtin>>"
468480
VTerm t -> showString (SAWCorePP.showTermWithNames opts nenv (ttTerm t))
469481
VType sig -> showString (pretty sig)
470-
VReturn {} -> showString "<<monadic>>"
471-
VBind {} -> showString "<<monadic>>"
482+
VReturn v' -> showString "return " . showsPrecValue opts nenv (p + 1) v'
483+
VDo pos _name _env stmts ->
484+
let e = SS.Block pos stmts in
485+
shows (PP.pretty e)
486+
VBindOnce v1 v2 ->
487+
let v1' = showsPrecValue opts nenv 0 v1
488+
v2' = showsPrecValue opts nenv 0 v2
489+
in
490+
v1' . showString " >>= " . v2'
472491
VTopLevel {} -> showString "<<TopLevel>>"
473492
VSimpset ss -> showString (showSimpset opts ss)
474493
VRefnset ss -> showString (showRefnset opts ss)
@@ -922,6 +941,11 @@ instance Monad LLVMCrucibleSetupM where
922941
LLVMCrucibleSetupM m >>= f =
923942
LLVMCrucibleSetupM (m >>= \x -> runLLVMCrucibleSetupM (f x))
924943

944+
-- XXX this is required for the moment in the interpreter, and should
945+
-- be removed when we clean out error handling.
946+
instance MonadFail LLVMCrucibleSetupM where
947+
fail msg = LLVMCrucibleSetupM $ lift $ lift $ fail msg
948+
925949
throwCrucibleSetup :: ProgramLoc -> String -> CrucibleSetup ext a
926950
throwCrucibleSetup loc msg = X.throw $ SS.CrucibleSetupException loc msg
927951

@@ -946,13 +970,23 @@ type JVMSetup = CrucibleSetup CJ.JVM
946970
newtype JVMSetupM a = JVMSetupM { runJVMSetupM :: JVMSetup a }
947971
deriving (Applicative, Functor, Monad)
948972

973+
-- XXX this is required for the moment in the interpreter, and should
974+
-- be removed when we clean out error handling.
975+
instance MonadFail JVMSetupM where
976+
fail msg = JVMSetupM $ lift $ lift $ fail msg
977+
949978
--
950979

951980
type MIRSetup = CrucibleSetup MIR
952981

953982
newtype MIRSetupM a = MIRSetupM { runMIRSetupM :: MIRSetup a }
954983
deriving (Applicative, Functor, Monad)
955984

985+
-- XXX this is required for the moment in the interpreter, and should
986+
-- be removed when we clean out error handling.
987+
instance MonadFail MIRSetupM where
988+
fail msg = MIRSetupM $ lift $ lift $ fail msg
989+
956990
--
957991
newtype ProofScript a = ProofScript { unProofScript :: ExceptT (SolverStats, CEX) (StateT ProofState TopLevel) a }
958992
deriving (Functor, Applicative, Monad)
@@ -986,6 +1020,15 @@ runProofScript (ProofScript m) concl gl ploc rsn recordThm useSequentGoals =
9861020
scriptTopLevel :: TopLevel a -> ProofScript a
9871021
scriptTopLevel m = ProofScript (lift (lift m))
9881022

1023+
llvmTopLevel :: TopLevel a -> LLVMCrucibleSetupM a
1024+
llvmTopLevel m = LLVMCrucibleSetupM (lift (lift m))
1025+
1026+
jvmTopLevel :: TopLevel a -> JVMSetupM a
1027+
jvmTopLevel m = JVMSetupM (lift (lift m))
1028+
1029+
mirTopLevel :: TopLevel a -> MIRSetupM a
1030+
mirTopLevel m = MIRSetupM (lift (lift m))
1031+
9891032
instance MonadIO ProofScript where
9901033
liftIO m = ProofScript (liftIO m)
9911034

0 commit comments

Comments
 (0)