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

View File

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

View File

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

View File

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

View File

@ -22,6 +22,7 @@ import qualified Cryptol.TypeCheck.AST as T
import Control.Monad (guard)
import Data.Foldable (fold)
import Data.Function (on)
import qualified Data.Map as Map
import Data.Monoid ((<>), Monoid(..))
import System.Environment.Executable(splitExecutablePath)
import System.FilePath ((</>), normalise, joinPath, splitPath)
@ -36,6 +37,7 @@ data ModuleEnv = ModuleEnv
, meEvalEnv :: EvalEnv
, meFocusedModule :: Maybe ModName
, meSearchPath :: [FilePath]
, meDynEnv :: DynamicEnv
}
initialModuleEnv :: IO ModuleEnv
@ -49,6 +51,7 @@ initialModuleEnv = do
, meEvalEnv = mempty
, meFocusedModule = Nothing
, meSearchPath = [dataDir </> "lib", instDir </> "lib", "."]
, meDynEnv = mempty
}
-- | Try to focus a loaded module in the module environment.
@ -128,27 +131,43 @@ addLoadedModule tm lm
, lmModule = tm
}
-- Extended Environments -------------------------------------------------------
-- Dynamic Environments --------------------------------------------------------
-- | Extra information we need to carry around to dynamically extend
-- an environment outside the context of a single module. Particularly
-- useful when dealing with interactive declarations as in @:let@ or
-- @it@.
data ExtendedEnv = EEnv
{ eeNames :: R.NamingEnv
, eeDecls :: [T.DeclGroup]
, eeEnv :: EvalEnv
data DynamicEnv = DEnv
{ deNames :: R.NamingEnv
, deDecls :: [T.DeclGroup]
, deEnv :: EvalEnv
}
instance Monoid ExtendedEnv where
mempty = EEnv
{ eeNames = mempty
, eeDecls = mempty
, eeEnv = mempty
instance Monoid DynamicEnv where
mempty = DEnv
{ deNames = mempty
, deDecls = mempty
, deEnv = mempty
}
mappend ee1 ee2 = EEnv
{ eeNames = eeNames ee1 <> eeNames ee2
, eeDecls = eeDecls ee1 <> eeDecls ee2
, eeEnv = eeEnv ee1 <> eeEnv ee2
mappend de1 de2 = DEnv
{ deNames = deNames de1 <> deNames de2
, deDecls = deDecls de1 <> deDecls de2
, 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 = 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 }