refactor dynamic environment into ModuleEnv

This just makes for a more consistent API; the "dynamic" environment
as extended by REPL commands is now part of the ModuleEnv. It's
actually more general than just for the REPL. We can use it in general
to add bindings on top of a loaded module context.
This commit is contained in:
Adam C. Foltzer 2014-08-18 13:28:21 -07:00
parent b2e83f8e27
commit 1dedf6d693
6 changed files with 104 additions and 104 deletions

View File

@ -325,22 +325,22 @@ proveCmd :: String -> REPL ()
proveCmd str = do proveCmd str = do
parseExpr <- replParseExpr str parseExpr <- replParseExpr str
(expr, schema) <- replCheckExpr parseExpr (expr, schema) <- replCheckExpr parseExpr
eenv <- getExtEnv denv <- getDynEnv
-- spexpr <- replSpecExpr expr -- spexpr <- replSpecExpr expr
EnvString proverName <- getUser "prover" EnvString proverName <- getUser "prover"
EnvBool iteSolver <- getUser "iteSolver" EnvBool iteSolver <- getUser "iteSolver"
EnvBool verbose <- getUser "debug" EnvBool verbose <- getUser "debug"
liftModuleCmd $ Cryptol.Symbolic.prove (proverName, iteSolver, verbose, str) (M.eeDecls eenv) (expr, schema) liftModuleCmd $ Cryptol.Symbolic.prove (proverName, iteSolver, verbose, str) (M.deDecls denv) (expr, schema)
satCmd :: String -> REPL () satCmd :: String -> REPL ()
satCmd str = do satCmd str = do
parseExpr <- replParseExpr str parseExpr <- replParseExpr str
(expr, schema) <- replCheckExpr parseExpr (expr, schema) <- replCheckExpr parseExpr
eenv <- getExtEnv denv <- getDynEnv
EnvString proverName <- getUser "prover" EnvString proverName <- getUser "prover"
EnvBool iteSolver <- getUser "iteSolver" EnvBool iteSolver <- getUser "iteSolver"
EnvBool verbose <- getUser "debug" EnvBool verbose <- getUser "debug"
liftModuleCmd $ Cryptol.Symbolic.sat (proverName, iteSolver, verbose, str) (M.eeDecls eenv) (expr, schema) liftModuleCmd $ Cryptol.Symbolic.sat (proverName, iteSolver, verbose, str) (M.deDecls denv) (expr, schema)
specializeCmd :: String -> REPL () specializeCmd :: String -> REPL ()
specializeCmd str = do specializeCmd str = do
@ -421,7 +421,7 @@ loadCmd path
{ lName = Just (T.mName m) { lName = Just (T.mName m)
, lPath = path , lPath = path
} }
setExtEnv mempty setDynEnv mempty
quitCmd :: REPL () quitCmd :: REPL ()
quitCmd = stop quitCmd = stop
@ -591,21 +591,22 @@ moduleCmdResult (res,ws0) = do
Left err -> raise (ModuleSystemError err) Left err -> raise (ModuleSystemError err)
replCheckExpr :: P.Expr -> REPL (T.Expr,T.Schema) replCheckExpr :: P.Expr -> REPL (T.Expr,T.Schema)
replCheckExpr e = do replCheckExpr e = liftModuleCmd $ M.checkExpr e
eenv <- getExtEnv
liftModuleCmd $ M.checkExprWith eenv e
replCheckDecls :: [P.Decl] -> REPL [T.DeclGroup] replCheckDecls :: [P.Decl] -> REPL [T.DeclGroup]
replCheckDecls ds = do replCheckDecls ds = do
npds <- liftModuleCmd $ M.noPat ds npds <- liftModuleCmd $ M.noPat ds
eenv <- getExtEnv denv <- getDynEnv
let dnames = M.namingEnv npds let dnames = M.namingEnv npds
ne' <- M.travNamingEnv uniqify dnames ne' <- M.travNamingEnv uniqify dnames
let eenv' = eenv { M.eeNames = ne' `M.shadowing` M.eeNames eenv } let denv' = denv { M.deNames = ne' `M.shadowing` M.deNames denv }
dgs <- liftModuleCmd $ M.checkDeclsWith eenv' npds undo exn = do
-- only update the REPL environment after a successful rename + typecheck -- if typechecking fails, we want to revert changes to the
setExtEnv eenv' -- dynamic environment and reraise
return dgs setDynEnv denv
raise exn
setDynEnv denv'
catch (liftModuleCmd $ M.checkDecls npds) undo
replSpecExpr :: T.Expr -> REPL T.Expr replSpecExpr :: T.Expr -> REPL T.Expr
replSpecExpr e = liftModuleCmd $ S.specialize e replSpecExpr e = liftModuleCmd $ S.specialize e
@ -625,8 +626,7 @@ replEvalExpr str =
let su = T.listSubst [ (T.tpVar a, t) | (a,t) <- tys ] let su = T.listSubst [ (T.tpVar a, t) | (a,t) <- tys ]
return (def1, T.apSubst su (T.sType sig)) return (def1, T.apSubst su (T.sType sig))
eenv <- getExtEnv val <- liftModuleCmd (M.evalExpr def1)
val <- liftModuleCmd (M.evalExprWith eenv def1)
whenDebug (io (putStrLn (dump def1))) whenDebug (io (putStrLn (dump def1)))
return (val,ty) return (val,ty)
where where
@ -637,9 +637,7 @@ replEvalDecls :: String -> REPL ()
replEvalDecls str = do replEvalDecls str = do
decls <- replParseDecls str decls <- replParseDecls str
dgs <- replCheckDecls decls dgs <- replCheckDecls decls
eenv <- getExtEnv liftModuleCmd (M.evalDecls dgs)
eenv' <- liftModuleCmd (M.evalDeclsWith eenv dgs)
setExtEnv eenv'
replEdit :: String -> REPL Bool replEdit :: String -> REPL Bool
replEdit file = do replEdit file = do

View File

@ -23,7 +23,7 @@ module REPL.Monad (
-- ** Environment -- ** Environment
, getModuleEnv, setModuleEnv , getModuleEnv, setModuleEnv
, getExtEnv, setExtEnv , getDynEnv, setDynEnv
, uniqify , uniqify
, getTSyns, getNewtypes, getVars , getTSyns, getNewtypes, getVars
, whenDebug , whenDebug
@ -52,6 +52,7 @@ import Cryptol.Prims.Syntax(ECon(..),ppPrefix)
import Cryptol.Eval (EvalError) import Cryptol.Eval (EvalError)
import qualified Cryptol.ModuleSystem as M import qualified Cryptol.ModuleSystem as M
import qualified Cryptol.ModuleSystem.Base as M import qualified Cryptol.ModuleSystem.Base as M
import qualified Cryptol.ModuleSystem.Env as M
import qualified Cryptol.ModuleSystem.NamingEnv as M import qualified Cryptol.ModuleSystem.NamingEnv as M
import Cryptol.Parser (ParseError,ppError) import Cryptol.Parser (ParseError,ppError)
import Cryptol.Parser.NoInclude (IncludeError,ppIncludeError) import Cryptol.Parser.NoInclude (IncludeError,ppIncludeError)
@ -86,8 +87,6 @@ data RW = RW
, eContinue :: Bool , eContinue :: Bool
, eIsBatch :: Bool , eIsBatch :: Bool
, eModuleEnv :: M.ModuleEnv , eModuleEnv :: M.ModuleEnv
, eExtEnv :: M.ExtendedEnv
-- ^ The dynamic environment for new bindings, eg @:let@
, eNameSupply :: Int , eNameSupply :: Int
, eUserEnv :: UserEnv , eUserEnv :: UserEnv
} }
@ -101,7 +100,6 @@ defaultRW isBatch = do
, eContinue = True , eContinue = True
, eIsBatch = isBatch , eIsBatch = isBatch
, eModuleEnv = env , eModuleEnv = env
, eExtEnv = mempty
, eNameSupply = 0 , eNameSupply = 0
, eUserEnv = mkUserEnv userOptions , eUserEnv = mkUserEnv userOptions
} }
@ -260,12 +258,12 @@ keepOne src as = case as of
getVars :: REPL (Map.Map P.QName M.IfaceDecl) getVars :: REPL (Map.Map P.QName M.IfaceDecl)
getVars = do getVars = do
me <- getModuleEnv me <- getModuleEnv
eenv <- getExtEnv denv <- getDynEnv
-- the subtle part here is removing the #Uniq prefix from -- the subtle part here is removing the #Uniq prefix from
-- interactively-bound variables, and also excluding any that are -- interactively-bound variables, and also excluding any that are
-- shadowed and thus can no longer be referenced -- shadowed and thus can no longer be referenced
let decls = M.focusedEnv me let decls = M.focusedEnv me
edecls = M.ifDecls (M.eeIfaceDecls eenv) edecls = M.ifDecls (M.deIfaceDecls denv)
-- is this QName something the user might actually type? -- is this QName something the user might actually type?
isShadowed (qn@(P.QName (Just (P.ModName ['#':_])) name), _) = isShadowed (qn@(P.QName (Just (P.ModName ['#':_])) name), _) =
case Map.lookup localName neExprs of case Map.lookup localName neExprs of
@ -273,7 +271,7 @@ getVars = do
Just uniqueNames -> isNamed uniqueNames Just uniqueNames -> isNamed uniqueNames
where localName = P.QName Nothing name where localName = P.QName Nothing name
isNamed us = any (== qn) (map M.qname us) isNamed us = any (== qn) (map M.qname us)
neExprs = M.neExprs (M.eeNames eenv) neExprs = M.neExprs (M.deNames denv)
isShadowed _ = False isShadowed _ = False
unqual ((P.QName _ name), ifds) = (P.QName Nothing name, ifds) unqual ((P.QName _ name), ifds) = (P.QName Nothing name, ifds)
edecls' = Map.fromList edecls' = Map.fromList
@ -321,11 +319,13 @@ getModuleEnv = eModuleEnv `fmap` getRW
setModuleEnv :: M.ModuleEnv -> REPL () setModuleEnv :: M.ModuleEnv -> REPL ()
setModuleEnv me = modifyRW_ (\rw -> rw { eModuleEnv = me }) setModuleEnv me = modifyRW_ (\rw -> rw { eModuleEnv = me })
getExtEnv :: REPL M.ExtendedEnv getDynEnv :: REPL M.DynamicEnv
getExtEnv = eExtEnv `fmap` getRW getDynEnv = (M.meDynEnv . eModuleEnv) `fmap` getRW
setExtEnv :: M.ExtendedEnv -> REPL () setDynEnv :: M.DynamicEnv -> REPL ()
setExtEnv eenv = modifyRW_ (\rw -> rw { eExtEnv = eenv }) setDynEnv denv = do
me <- getModuleEnv
setModuleEnv (me { M.meDynEnv = denv })
-- | Given an existing qualified name, prefix it with a -- | Given an existing qualified name, prefix it with a
-- relatively-unique string. We make it unique by prefixing with a -- relatively-unique string. We make it unique by prefixing with a

View File

@ -9,16 +9,16 @@
module Cryptol.ModuleSystem ( module Cryptol.ModuleSystem (
-- * Module System -- * Module System
ModuleEnv(..), initialModuleEnv ModuleEnv(..), initialModuleEnv
, ExtendedEnv(..) , DynamicEnv(..)
, ModuleError(..), ModuleWarning(..) , ModuleError(..), ModuleWarning(..)
, ModuleCmd, ModuleRes , ModuleCmd, ModuleRes
, findModule , findModule
, loadModuleByPath , loadModuleByPath
, loadModule , loadModule
, checkExprWith , checkExpr
, evalExprWith , evalExpr
, checkDeclsWith , checkDecls
, evalDeclsWith , evalDecls
, noPat , noPat
, focusedEnv , focusedEnv
@ -71,20 +71,20 @@ loadModule m env = runModuleM env $ do
-- can extend dynamically outside of the context of a module. -- can extend dynamically outside of the context of a module.
-- | Check the type of an expression. -- | Check the type of an expression.
checkExprWith :: ExtendedEnv -> P.Expr -> ModuleCmd (T.Expr,T.Schema) checkExpr :: P.Expr -> ModuleCmd (T.Expr,T.Schema)
checkExprWith eenv e env = runModuleM env (interactive (Base.checkExprWith eenv e)) checkExpr e env = runModuleM env (interactive (Base.checkExpr e))
-- | Evaluate an expression. -- | Evaluate an expression.
evalExprWith :: ExtendedEnv -> T.Expr -> ModuleCmd E.Value evalExpr :: T.Expr -> ModuleCmd E.Value
evalExprWith eenv e env = runModuleM env (interactive (Base.evalExprWith eenv e)) evalExpr e env = runModuleM env (interactive (Base.evalExpr e))
-- | Typecheck declarations. -- | Typecheck declarations.
checkDeclsWith :: ExtendedEnv -> [P.Decl] -> ModuleCmd [T.DeclGroup] checkDecls :: [P.Decl] -> ModuleCmd [T.DeclGroup]
checkDeclsWith eenv ds env = runModuleM env (interactive (Base.checkDeclsWith eenv ds)) checkDecls ds env = runModuleM env (interactive (Base.checkDecls ds))
-- | Evaluate declarations and add them to the extended environment. -- | Evaluate declarations and add them to the extended environment.
evalDeclsWith :: ExtendedEnv -> [T.DeclGroup] -> ModuleCmd ExtendedEnv evalDecls :: [T.DeclGroup] -> ModuleCmd ()
evalDeclsWith eenv dgs env = runModuleM env (interactive (Base.evalDeclsWith eenv dgs)) evalDecls dgs env = runModuleM env (interactive (Base.evalDecls dgs))
noPat :: RemovePatterns a => a -> ModuleCmd a noPat :: RemovePatterns a => a -> ModuleCmd a
noPat a env = runModuleM env (interactive (Base.noPat a)) noPat a env = runModuleM env (interactive (Base.noPat a))

View File

@ -8,7 +8,7 @@
module Cryptol.ModuleSystem.Base where module Cryptol.ModuleSystem.Base where
import Cryptol.ModuleSystem.Env (ExtendedEnv(..)) import Cryptol.ModuleSystem.Env (DynamicEnv(..), deIfaceDecls)
import Cryptol.ModuleSystem.Interface import Cryptol.ModuleSystem.Interface
import Cryptol.ModuleSystem.Monad import Cryptol.ModuleSystem.Monad
import qualified Cryptol.Eval as E import qualified Cryptol.Eval as E
@ -32,7 +32,7 @@ import Data.Foldable (foldMap)
import Data.Function (on) import Data.Function (on)
import Data.List (nubBy) import Data.List (nubBy)
import Data.Maybe (mapMaybe,fromMaybe) import Data.Maybe (mapMaybe,fromMaybe)
import Data.Monoid ((<>), mconcat) import Data.Monoid ((<>))
import System.Directory (doesFileExist) import System.Directory (doesFileExist)
import System.FilePath (addExtension,joinPath,(</>)) import System.FilePath (addExtension,joinPath,(</>))
import qualified Data.Map as Map import qualified Data.Map as Map
@ -67,14 +67,8 @@ renameModule m = do
renameExpr :: P.Expr -> ModuleM P.Expr renameExpr :: P.Expr -> ModuleM P.Expr
renameExpr e = do renameExpr e = do
env <- getFocusedEnv env <- getFocusedEnv
rename (R.namingEnv env) e denv <- getDynEnv
rename (deNames denv `R.shadowing` R.namingEnv env) e
-- | Rename an expression in the context of the focused module and an
-- extended environment.
renameExprWith :: ExtendedEnv -> P.Expr -> ModuleM P.Expr
renameExprWith eenv e = do
env <- getFocusedEnv
rename (eeNames eenv `R.shadowing` R.namingEnv env) e
-- NoPat ----------------------------------------------------------------------- -- NoPat -----------------------------------------------------------------------
@ -228,36 +222,20 @@ loadDeps m
checkExpr :: P.Expr -> ModuleM (T.Expr,T.Schema) checkExpr :: P.Expr -> ModuleM (T.Expr,T.Schema)
checkExpr e = do checkExpr e = do
npe <- noPat e npe <- noPat e
denv <- getDynEnv
re <- renameExpr npe re <- renameExpr npe
typecheck T.tcExpr re =<< getQualifiedEnv
-- | Typecheck a single expression in an extended environment.
checkExprWith :: ExtendedEnv -> P.Expr -> ModuleM (T.Expr,T.Schema)
checkExprWith eenv e = do
npe <- noPat e
re <- renameExprWith eenv npe
env <- getQualifiedEnv env <- getQualifiedEnv
let env' = env <> eeIfaceDecls eenv let env' = env <> deIfaceDecls denv
typecheck T.tcExpr re env' typecheck T.tcExpr re env'
eeIfaceDecls :: ExtendedEnv -> IfaceDecls -- | Typecheck a group of declarations.
eeIfaceDecls EEnv { eeDecls = dgs } = checkDecls :: [P.Decl] -> ModuleM [T.DeclGroup]
mconcat [ IfaceDecls checkDecls ds = do
{ ifTySyns = Map.empty
, ifNewtypes = Map.empty
, ifDecls = Map.singleton (ifDeclName ifd) [ifd]
}
| decl <- concatMap T.groupDecls dgs
, let ifd = mkIfaceDecl decl
]
-- | Typecheck a group of declarations in an extended environment.
checkDeclsWith :: ExtendedEnv -> [P.Decl] -> ModuleM [T.DeclGroup]
checkDeclsWith eenv ds = do
-- nopat must already be run -- nopat must already be run
rds <- rename (eeNames eenv) ds denv <- getDynEnv
rds <- rename (deNames denv) ds
env <- getQualifiedEnv env <- getQualifiedEnv
let env' = env <> eeIfaceDecls eenv let env' = env <> deIfaceDecls denv
typecheck T.tcDecls rds env' typecheck T.tcDecls rds env'
-- | Typecheck a module. -- | Typecheck a module.
@ -340,18 +318,15 @@ genInferInput r env = do
evalExpr :: T.Expr -> ModuleM E.Value evalExpr :: T.Expr -> ModuleM E.Value
evalExpr e = do evalExpr e = do
env <- getEvalEnv env <- getEvalEnv
return (E.evalExpr env e) denv <- getDynEnv
return (E.evalExpr (env <> deEnv denv) e)
evalExprWith :: ExtendedEnv -> T.Expr -> ModuleM E.Value evalDecls :: [T.DeclGroup] -> ModuleM ()
evalExprWith eenv e = do evalDecls dgs = do
env <- getEvalEnv env <- getEvalEnv
return (E.evalExpr (env <> eeEnv eenv) e) denv <- getDynEnv
let env' = env <> deEnv denv
-- | Evaluate typechecked declarations in an extended environment. The denv' = denv { deDecls = deDecls denv ++ dgs
-- result of this is a new environment whose 'EvalEnv' is extended , deEnv = E.evalDecls dgs env'
-- with the new declarations and their values. }
evalDeclsWith :: ExtendedEnv -> [T.DeclGroup] -> ModuleM ExtendedEnv setDynEnv denv'
evalDeclsWith eenv dgs = do
env <- getEvalEnv
let env' = env <> eeEnv eenv
return $ eenv { eeDecls = eeDecls eenv ++ dgs, eeEnv = E.evalDecls dgs env' }

View File

@ -22,6 +22,7 @@ import qualified Cryptol.TypeCheck.AST as T
import Control.Monad (guard) import Control.Monad (guard)
import Data.Foldable (fold) import Data.Foldable (fold)
import Data.Function (on) import Data.Function (on)
import qualified Data.Map as Map
import Data.Monoid ((<>), Monoid(..)) import Data.Monoid ((<>), Monoid(..))
import System.Environment.Executable(splitExecutablePath) import System.Environment.Executable(splitExecutablePath)
import System.FilePath ((</>), normalise, joinPath, splitPath) import System.FilePath ((</>), normalise, joinPath, splitPath)
@ -36,6 +37,7 @@ data ModuleEnv = ModuleEnv
, meEvalEnv :: EvalEnv , meEvalEnv :: EvalEnv
, meFocusedModule :: Maybe ModName , meFocusedModule :: Maybe ModName
, meSearchPath :: [FilePath] , meSearchPath :: [FilePath]
, meDynEnv :: DynamicEnv
} }
initialModuleEnv :: IO ModuleEnv initialModuleEnv :: IO ModuleEnv
@ -49,6 +51,7 @@ initialModuleEnv = do
, meEvalEnv = mempty , meEvalEnv = mempty
, meFocusedModule = Nothing , meFocusedModule = Nothing
, meSearchPath = [dataDir </> "lib", instDir </> "lib", "."] , meSearchPath = [dataDir </> "lib", instDir </> "lib", "."]
, meDynEnv = mempty
} }
-- | Try to focus a loaded module in the module environment. -- | Try to focus a loaded module in the module environment.
@ -128,27 +131,43 @@ addLoadedModule tm lm
, lmModule = tm , lmModule = tm
} }
-- Extended Environments ------------------------------------------------------- -- Dynamic Environments --------------------------------------------------------
-- | Extra information we need to carry around to dynamically extend -- | Extra information we need to carry around to dynamically extend
-- an environment outside the context of a single module. Particularly -- an environment outside the context of a single module. Particularly
-- useful when dealing with interactive declarations as in @:let@ or -- useful when dealing with interactive declarations as in @:let@ or
-- @it@. -- @it@.
data ExtendedEnv = EEnv data DynamicEnv = DEnv
{ eeNames :: R.NamingEnv { deNames :: R.NamingEnv
, eeDecls :: [T.DeclGroup] , deDecls :: [T.DeclGroup]
, eeEnv :: EvalEnv , deEnv :: EvalEnv
} }
instance Monoid ExtendedEnv where instance Monoid DynamicEnv where
mempty = EEnv mempty = DEnv
{ eeNames = mempty { deNames = mempty
, eeDecls = mempty , deDecls = mempty
, eeEnv = mempty , deEnv = mempty
} }
mappend ee1 ee2 = EEnv mappend de1 de2 = DEnv
{ eeNames = eeNames ee1 <> eeNames ee2 { deNames = deNames de1 <> deNames de2
, eeDecls = eeDecls ee1 <> eeDecls ee2 , deDecls = deDecls de1 <> deDecls de2
, eeEnv = eeEnv ee1 <> eeEnv ee2 , deEnv = deEnv de1 <> deEnv de2
} }
-- | Build 'IfaceDecls' that correspond to all of the bindings in the
-- dynamic environment.
--
-- XXX: if we ever add type synonyms or newtypes at the REPL, revisit
-- this.
deIfaceDecls :: DynamicEnv -> IfaceDecls
deIfaceDecls DEnv { deDecls = dgs } =
mconcat [ IfaceDecls
{ ifTySyns = Map.empty
, ifNewtypes = Map.empty
, ifDecls = Map.singleton (ifDeclName ifd) [ifd]
}
| decl <- concatMap T.groupDecls dgs
, let ifd = mkIfaceDecl decl
]

View File

@ -328,3 +328,11 @@ getFocusedEnv = ModuleT (focusedEnv `fmap` get)
getQualifiedEnv :: ModuleM IfaceDecls getQualifiedEnv :: ModuleM IfaceDecls
getQualifiedEnv = ModuleT (qualifiedEnv `fmap` get) getQualifiedEnv = ModuleT (qualifiedEnv `fmap` get)
getDynEnv :: ModuleM DynamicEnv
getDynEnv = ModuleT (meDynEnv `fmap` get)
setDynEnv :: DynamicEnv -> ModuleM ()
setDynEnv denv = ModuleT $ do
me <- get
set $! me { meDynEnv = denv }