Skip to content

Commit d2c73d8

Browse files
committed
SAWScript: Add an extra global environment for "let rebindable".
This makes the new "let rebindable" functionality work, fixing the test05 and test14 cases of test1646, and finally closes #1646.
1 parent 34b159d commit d2c73d8

File tree

11 files changed

+158
-56
lines changed

11 files changed

+158
-56
lines changed

intTests/test1646/test05.log.good

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Loading file "test05.saw"
22
x=a
3-
x=a
3+
x=b

intTests/test1646/test05.saw

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// The second f call will print x=b.
2-
// XXX currently it prints x=a
32

43
let rebindable x = "a";
54

intTests/test1646/test14.log.good

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Loading file "test14.saw"
22
x=a
3-
x=a
4-
test14.saw:12:5-12:6: Warning: Redeclaration of x
5-
test14.saw:9:16-9:17: Warning: Previous declaration was here
6-
x=a
3+
x=b
4+
test14.saw:11:5-11:6: Warning: Redeclaration of x
5+
test14.saw:8:16-8:17: Warning: Previous declaration was here
6+
x=b

intTests/test1646/test14.saw

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// The second f call should print x=b. So should the third.
2-
// XXX: currently all print x=a.
32

43
let rebindable x = "a";
54

intTests/test1646/test15.log.good

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<stdin>:1:5-1:6: Warning: Redeclaration of y
22
<stdin>:1:16-1:17: Warning: Previous declaration was here
3+
x : rebindable Int
4+
y : rebindable Int
5+
36
abc : ProofScript ()
47
abstract_symbolic : Term -> Term
58
add_cryptol_defs : [String] -> Simpset -> Simpset
@@ -345,5 +348,4 @@ write_smtlib2_w4 : String -> Term -> TopLevel ()
345348
yices : ProofScript ()
346349
z3 : ProofScript ()
347350

348-
x : Int
349351
y : Int

saw-central/src/SAWCentral/Builtins.hs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,10 +1705,21 @@ envCmd = do
17051705
opts <- getOptions
17061706
avail <- gets rwPrimsAvail
17071707
SV.Environ varenv _tyenv <- gets rwEnviron
1708-
let printItem (x, (_pos, _lc, _rb, ty, _v, _doc)) =
1708+
rbenv <- gets rwRebindables
1709+
1710+
-- print rebindables first if there are any
1711+
unless (Map.null rbenv) $ do
1712+
io $ printOutLn opts Info $ "Rebindable globals:"
1713+
io $ printOutLn opts Info $ ""
1714+
let printRB (x, (_pos, ty, _v)) = do
1715+
let str = x <> " : rebindable " <> PPS.pShowText ty
1716+
printOutLn opts Info $ Text.unpack str
1717+
io $ mapM_ printRB $ Map.assocs rbenv
1718+
1719+
let printItem (x, (_pos, _lc, ty, _v, _doc)) =
17091720
printOutLn opts Info $ Text.unpack (x <> " : " <> PPS.pShowText ty)
17101721
-- Print only the visible objects
1711-
keep (_x, (_pos, lc, _rb, _ty, _v, _doc)) = Set.member lc avail
1722+
keep (_x, (_pos, lc, _ty, _v, _doc)) = Set.member lc avail
17121723
-- Insert a blank line in the output where there's a scope boundary
17131724
printScope mItems = case mItems of
17141725
Nothing -> printOutLn opts Info ""

saw-central/src/SAWCentral/Value.hs

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -746,14 +746,25 @@ evaluateTypedTerm _sc (TypedTerm tp _) =
746746
-- TopLevel Monad --------------------------------------------------------------
747747

748748
-- | Type names for the interpreter environment components.
749-
type VarEnv = ScopedMap SS.Name (SS.Pos, SS.PrimitiveLifecycle, SS.Rebindable,
749+
--
750+
-- Note: because no builtins are rebindable, the rebindable
751+
-- environment doesn't have lifecycle or help text fields. There is,
752+
-- currently at least, no way to populate those for non-builtins.
753+
type VarEnv = ScopedMap SS.Name (SS.Pos, SS.PrimitiveLifecycle,
750754
SS.Schema, Value, Maybe [Text])
751755
type TyEnv = ScopedMap SS.Name (SS.PrimitiveLifecycle, SS.NamedType)
752756

753-
-- | Type for the full interpreter environment.
757+
type RebindableEnv = Map SS.Name (SS.Pos, SS.Schema, Value)
758+
759+
-- | Type for the ordinary interpreter environment.
760+
--
761+
-- There's one environment that maps variable names to values, and
762+
-- one that maps type names to types. Both get closed in with
763+
-- lambdas and do-blocks at the appropriate times.
754764
--
755-
-- There's one environment that maps variable names to values,
756-
-- and one that maps type names to types.
765+
-- Note that rebindable variables are sold separately. This is so
766+
-- they don't get closed in; references to rebindable variables
767+
-- always retrieve the most recent version.
757768
data Environ = Environ {
758769
eVarEnv :: VarEnv,
759770
eTyEnv :: TyEnv
@@ -877,6 +888,7 @@ data TopLevelRW =
877888
-- rwValueInfo :: Map SS.Name (SS.Pos, SS.PrimitiveLifecycle, SS.Rebindable,
878889
-- SS.Schema, Value, Maybe [Text])
879890
rwEnviron :: Environ
891+
, rwRebindables :: RebindableEnv
880892

881893
-- | The type environment: a map from type names to:
882894
-- - the lifecycle setting (experimental/current/deprecated/etc)
@@ -1213,7 +1225,22 @@ extendEnv pos name rb ty doc v = do
12131225

12141226
-- Update the SAWScript environment.
12151227
Environ varenv tyenv <- gets rwEnviron
1216-
let varenv' = ScopedMap.insert name (pos, SS.Current, rb, ty, v, doc) varenv
1228+
rbenv <- gets rwRebindables
1229+
let (varenv', rbenv') = case rb of
1230+
SS.ReadOnlyVar ->
1231+
-- If we replace a rebindable variable at the top level with a
1232+
-- readonly one, the readonly version in varenv will hide it
1233+
-- ever after. We ought to remove it from rbenv; however, it's
1234+
-- not easy to know here whether we're at the top level or not.
1235+
-- FUTURE: maybe this will become easier in the long run.
1236+
let ve' = ScopedMap.insert name (pos, SS.Current, ty, v, doc) varenv in
1237+
(ve', rbenv)
1238+
SS.RebindableVar ->
1239+
-- The typechecker restricts this to happen only at the
1240+
-- top level and only if any existing variable is already
1241+
-- rebindable, so we don't have to update varenv.
1242+
let re' = M.insert name (pos, ty, v) rbenv in
1243+
(varenv, re')
12171244

12181245
-- Mirror the value into the Cryptol environment if appropriate.
12191246
ce <- gets rwCryptol
@@ -1237,7 +1264,11 @@ extendEnv pos name rb ty doc v = do
12371264
pure ce
12381265

12391266
-- Drop the new bits into place.
1240-
modify (\rw -> rw { rwCryptol = ce', rwEnviron = Environ varenv' tyenv })
1267+
modify (\rw -> rw {
1268+
rwCryptol = ce',
1269+
rwEnviron = Environ varenv' tyenv,
1270+
rwRebindables = rbenv'
1271+
})
12411272

12421273
extendEnvMulti :: [(SS.Pos, SS.Name, SS.Rebindable, SS.Schema, Maybe [Text], Environ -> Value)] -> TopLevel ()
12431274
extendEnvMulti bindings = do
@@ -1262,10 +1293,19 @@ extendEnvMulti bindings = do
12621293
VLambda{} -> v
12631294
_ ->
12641295
panic "extendEnvMulti" [
1265-
"Non-lambda value: " <> Text.pack (show v)
1296+
"Non-lambda value: " <> Text.pack (show v),
1297+
"Source position: " <> Text.pack (show pos)
1298+
]
1299+
v'' = case rb of
1300+
SS.ReadOnlyVar -> v'
1301+
SS.RebindableVar ->
1302+
-- "rec" declarations can't be rebindable
1303+
panic "extendEnvMulti" [
1304+
"Rebindable variable: " <> name,
1305+
"Source position: " <> Text.pack (show pos)
12661306
]
12671307
in
1268-
ScopedMap.insert name (pos, SS.Current, rb, ty, v', doc) tmpenv
1308+
ScopedMap.insert name (pos, SS.Current, ty, v'', doc) tmpenv
12691309
varenv' = foldr insert varenv bindings
12701310
environ' = Environ varenv' tyenv
12711311

saw-script/src/SAWScript/Interpreter.hs

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -510,22 +510,30 @@ interpretExpr expr =
510510
SS.Var pos x -> do
511511
avail <- gets rwPrimsAvail
512512
Environ varenv _tyenv <- gets rwEnviron
513-
case ScopedMap.lookup x varenv of
514-
Nothing ->
515-
-- This should be rejected by the typechecker, so panic
516-
panic "interpretExpr" [
517-
"Read of unknown variable " <> x
518-
]
519-
Just (_defpos, lc, _rebindable, _ty, v, _doc)
520-
| Set.member lc avail -> do
521-
let v' = injectPositionIntoMonadicValue pos v
522-
v'' = insertRefChain pos x v'
523-
return v''
524-
| otherwise ->
525-
-- This case is also rejected by the typechecker
526-
panic "interpretExpr" [
527-
"Read of inaccessible variable " <> x
528-
]
513+
rbenv <- gets rwRebindables
514+
let info = case ScopedMap.lookup x varenv of
515+
Nothing ->
516+
-- Try the rebindable environment
517+
case Map.lookup x rbenv of
518+
Nothing -> Nothing
519+
Just (_defpos, _ty, v) -> Just (Current, v)
520+
Just (_defpos, lc, _ty, v, _doc) -> Just (lc, v)
521+
case info of
522+
Nothing ->
523+
-- This should be rejected by the typechecker; panic
524+
panic "interpretExpr" [
525+
"Read of unknown variable " <> x
526+
]
527+
Just (lc, v)
528+
| Set.member lc avail -> do
529+
let v' = injectPositionIntoMonadicValue pos v
530+
v'' = insertRefChain pos x v'
531+
return v''
532+
| otherwise ->
533+
-- This case is also rejected by the typechecker
534+
panic "interpretExpr" [
535+
"Read of inaccessible variable " <> x
536+
]
529537
SS.Lambda _pos mname pat e -> do
530538
env <- gets rwEnviron
531539
return $ VLambda env mname pat e
@@ -912,9 +920,15 @@ interpretTopStmt printBinds stmt = do
912920
-- - shouldn't have to flatten the environments
913921
-- - shouldn't be typechecking one statement at a time regardless
914922
Environ varenv tyenv <- liftTopLevel $ gets rwEnviron
915-
let varenv' = Map.map (\(pos, lc, rb, ty, _v, _doc) -> (pos, lc, rb, ty)) $ ScopedMap.flatten varenv
923+
rbenv <- liftTopLevel $ gets rwRebindables
924+
925+
let varenv' = Map.map (\(pos, lc, ty, _v, _doc) -> (pos, lc, SS.ReadOnlyVar, ty)) $ ScopedMap.flatten varenv
926+
rbenv' = Map.map (\(pos, ty, _v) -> (pos, SS.Current, SS.RebindableVar, ty)) rbenv
927+
-- If anything appears in both, favor the real environment
928+
varenv'' = Map.union varenv' rbenv'
929+
916930
let tyenv' = ScopedMap.flatten tyenv
917-
stmt' <- processTypeCheck $ checkStmt avail varenv' tyenv' ctx stmt
931+
stmt' <- processTypeCheck $ checkStmt avail varenv'' tyenv' ctx stmt
918932

919933
case stmt' of
920934

@@ -995,6 +1009,7 @@ interpretMain :: TopLevel ()
9951009
interpretMain = do
9961010
avail <- gets rwPrimsAvail
9971011
Environ varenv tyenv <- gets rwEnviron
1012+
rbenv <- gets rwRebindables
9981013
let pos = SS.PosInternal "entry"
9991014
-- We need the type to be "TopLevel a", not just "TopLevel ()".
10001015
-- There are several (old) tests in the test suite whose main
@@ -1004,11 +1019,19 @@ interpretMain = do
10041019
tyRet = SS.TyVar pos "a"
10051020
tyMonadic = SS.tBlock pos (SS.tContext pos SS.TopLevel) tyRet
10061021
tyExpected = SS.Forall [(pos, "a")] tyMonadic
1007-
case ScopedMap.lookup "main" varenv of
1022+
let main = case ScopedMap.lookup "main" varenv of
1023+
Just (_defpos, lc, tyFound, v, _doc) -> Just (lc, tyFound, v)
1024+
-- Having main be rebindable doesn't make much sense, but
1025+
-- it's easier to have this code than to spend time
1026+
-- explaining that it's not allowed.
1027+
Nothing -> case Map.lookup "main" rbenv of
1028+
Nothing -> Nothing
1029+
Just (_defpos, tyFound, v) -> Just (Current, tyFound, v)
1030+
case main of
10081031
Nothing ->
10091032
-- Don't fail or complain if there's no main.
10101033
return ()
1011-
Just (_defpos, Current, _rebindable, tyFound, v, _doc) -> case tyFound of
1034+
Just (Current, tyFound, v) -> case tyFound of
10121035
SS.Forall _ (SS.TyCon _ SS.BlockCon [_, _]) ->
10131036
-- XXX shouldn't have to do this
10141037
let tyenv' = ScopedMap.flatten tyenv in
@@ -1026,7 +1049,7 @@ interpretMain = do
10261049
-- If the type is something entirely random, like a Term or a
10271050
-- String or something, just ignore it.
10281051
return ()
1029-
Just (_defpos, lc, _rebindable, _ty, _v, _doc) ->
1052+
Just (lc, _ty, _v) ->
10301053
-- There is no way for things other than primitives to get marked
10311054
-- experimental or deprecated, so this isn't possible. If we allow
10321055
-- users to deprecate their own functions in the future, change
@@ -1093,6 +1116,7 @@ buildTopLevelEnv proxy opts scriptArgv =
10931116

10941117
let rw0 = TopLevelRW
10951118
{ rwEnviron = primEnviron opts bic
1119+
, rwRebindables = Map.empty
10961120
, rwCryptol = ce0
10971121
, rwPosition = SS.Unknown
10981122
, rwStackTrace = Trace.empty
@@ -6455,7 +6479,7 @@ primNamedTypeEnv = fmap extract primTypes
64556479
primValueEnv ::
64566480
Options ->
64576481
BuiltinContext ->
6458-
Map SS.Name (SS.Pos, PrimitiveLifecycle, SS.Rebindable, SS.Schema, Value, Maybe [Text])
6482+
Map SS.Name (SS.Pos, PrimitiveLifecycle, SS.Schema, Value, Maybe [Text])
64596483
primValueEnv opts bic = Map.mapWithKey extract primitives
64606484
where
64616485
header = [
@@ -6476,7 +6500,7 @@ primValueEnv opts bic = Map.mapWithKey extract primitives
64766500
header <> tag p <> name n p <> primitiveDoc p
64776501
extract n p =
64786502
let pos = SS.PosInternal "<<builtin>>" in
6479-
(pos, primitiveLife p, SS.ReadOnlyVar, primitiveType p,
6503+
(pos, primitiveLife p, primitiveType p,
64806504
(primitiveFn p) opts bic, Just $ doc n p)
64816505

64826506
primEnviron :: Options -> BuiltinContext -> Environ

saw-script/src/SAWScript/REPL/Command.hs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import SAWScript.Token (Token)
4444

4545
import Cryptol.Parser (ParseError())
4646

47-
import Control.Monad (guard, void)
47+
import Control.Monad (guard, unless, void)
4848

4949
import Data.Char (isSpace,isPunctuation,isSymbol)
5050
import Data.Function (on)
@@ -77,7 +77,7 @@ import SAWScript.Interpreter (interpretTopStmt)
7777
import qualified SAWScript.Lexer (lexSAW)
7878
import qualified SAWScript.Parser (parseStmtSemi, parseExpression, parseSchemaPattern)
7979
import SAWCentral.TopLevel (TopLevelRW(..))
80-
import SAWCentral.AST (PrimitiveLifecycle(..), everythingAvailable)
80+
import SAWCentral.AST (PrimitiveLifecycle(..), everythingAvailable, Rebindable(..))
8181

8282

8383
-- Commands --------------------------------------------------------------------
@@ -205,11 +205,16 @@ typeOfCmd str
205205
rw <- getTopLevelRW
206206
decl' <- do
207207
let primsAvail = rwPrimsAvail rw
208+
-- XXX it should not be necessary to do this munging
208209
Environ varenv tyenv = rwEnviron rw
209-
squash (defpos, lc, rb, ty, _val, _doc) = (defpos, lc, rb, ty)
210+
squash (defpos, lc, ty, _val, _doc) = (defpos, lc, ReadOnlyVar, ty)
210211
varenv' = Map.map squash $ ScopedMap.flatten varenv
211212
tyenv' = ScopedMap.flatten tyenv
212-
let (errs_or_results, warns) = checkDecl primsAvail varenv' tyenv' decl
213+
rbenv = rwRebindables rw
214+
rbsquash (defpos, ty, _val) = (defpos, Current, RebindableVar, ty)
215+
rbenv' = Map.map rbsquash rbenv
216+
varenv'' = Map.union varenv' rbenv'
217+
let (errs_or_results, warns) = checkDecl primsAvail varenv'' tyenv' decl
213218
let issueWarning (msgpos, msg) =
214219
-- XXX the print functions should be what knows how to show positions...
215220
putStrLn (show msgpos ++ ": Warning: " ++ msg)
@@ -243,11 +248,16 @@ searchCmd str
243248
-- for deprecated functions that take Terms.
244249

245250
let primsAvail = rwPrimsAvail rw
251+
-- XXX it should not be necessary to do this munging
246252
Environ varenv tyenv = rwEnviron rw
247-
squash (pos, lc, rb, ty, _val, _doc) = (pos, lc, rb, ty)
253+
rbenv = rwRebindables rw
254+
squash (pos, lc, ty, _val, _doc) = (pos, lc, ReadOnlyVar, ty)
248255
varenv' = Map.map squash $ ScopedMap.flatten varenv
249256
tyenv' = ScopedMap.flatten tyenv
250-
(errs_or_results, warns) = checkSchemaPattern everythingAvailable varenv' tyenv' pat
257+
rbsquash (pos, ty, _val) = (pos, Current, RebindableVar, ty)
258+
rbenv' = Map.map rbsquash rbenv
259+
varenv'' = Map.union varenv' rbenv'
260+
(errs_or_results, warns) = checkSchemaPattern everythingAvailable varenv'' tyenv' pat
251261
let issueWarning (msgpos, msg) =
252262
-- XXX the print functions should be what knows how to show positions...
253263
putStrLn (show msgpos ++ ": Warning: " ++ msg)
@@ -343,13 +353,24 @@ quitCmd = stop
343353
envCmd :: REPL ()
344354
envCmd = do
345355
rw <- getTopLevelRW
346-
let avail = rwPrimsAvail rw
347-
Environ varenv _tyenv = rwEnviron rw
348-
say (x, (_pos, _lc, _rb, ty, _v, _doc)) = do
356+
let Environ varenv _tyenv = rwEnviron rw
357+
rbenv = rwRebindables rw
358+
avail = rwPrimsAvail rw
359+
360+
-- print the rebindable globals first, if any
361+
unless (Map.null rbenv) $ do
362+
let rbsay (x, (_pos, ty, _v)) = do
363+
let ty' = PPS.pShowText ty
364+
TextIO.putStrLn (x <> " : rebindable " <> ty')
365+
io $ mapM_ rbsay $ Map.assocs rbenv
366+
io $ TextIO.putStrLn ""
367+
368+
-- print the normal environment
369+
let say (x, (_pos, _lc, ty, _v, _doc)) = do
349370
let ty' = PPS.pShowText ty
350371
TextIO.putStrLn (x <> " : " <> ty')
351372
-- Print only the visible objects
352-
keep (_x, (_pos, lc, _rb, _ty, _v, _doc)) = Set.member lc avail
373+
keep (_x, (_pos, lc, _ty, _v, _doc)) = Set.member lc avail
353374
-- Insert a blank line in the output where there's a scope boundary
354375
printScope mItems = case mItems of
355376
Nothing -> TextIO.putStrLn ""
@@ -383,11 +404,14 @@ helpCmd cmd
383404
| null cmd = io (mapM_ putStrLn (genHelp commandList))
384405
| otherwise =
385406
do rw <- getTopLevelRW
407+
-- Note: there's no rebindable builtins and thus no way to
408+
-- attach help text to anything rebindable, so we can ignore
409+
-- the rebindables.
386410
let Environ varenv _tyenv = rwEnviron rw
387411
case ScopedMap.lookup (Text.pack cmd) varenv of
388-
Just (_pos, _lc, _rb, _ty, _v, Just doc) ->
412+
Just (_pos, _lc, _ty, _v, Just doc) ->
389413
io $ mapM_ TextIO.putStrLn doc
390-
Just (_pos, _lc, _rb, _ty, _v, Nothing) -> do
414+
Just (_pos, _lc, _ty, _v, Nothing) -> do
391415
io $ putStrLn $ "// No documentation is available."
392416
typeOfCmd cmd
393417
Nothing ->

0 commit comments

Comments
 (0)