Add extended environment, support for typechecking and evaluating decls

This is a checkpoint; it builds but doesn't yet work correctly!
This commit is contained in:
Adam C. Foltzer 2014-08-13 17:51:17 -07:00
parent 09974fbc64
commit 2b1380beed
11 changed files with 154 additions and 13 deletions

View File

@ -38,7 +38,7 @@ import qualified Cryptol.Eval.Value as E
import qualified Cryptol.Testing.Random as TestR import qualified Cryptol.Testing.Random as TestR
import qualified Cryptol.Testing.Exhaust as TestX import qualified Cryptol.Testing.Exhaust as TestX
import Cryptol.Parser import Cryptol.Parser
(parseExprWith,ParseError(),Config(..),defaultConfig,parseModName) (parseDeclsWith,parseExprWith,ParseError(),Config(..),defaultConfig,parseModName)
import Cryptol.Parser.Position (emptyRange,getLoc) import Cryptol.Parser.Position (emptyRange,getLoc)
import qualified Cryptol.TypeCheck.AST as T import qualified Cryptol.TypeCheck.AST as T
import qualified Cryptol.TypeCheck.Subst as T import qualified Cryptol.TypeCheck.Subst as T
@ -126,6 +126,7 @@ instance Ord CommandDescr where
data CommandBody data CommandBody
= ExprArg (String -> REPL ()) = ExprArg (String -> REPL ())
| DeclsArg (String -> REPL ())
| ExprTypeArg (String -> REPL ()) | ExprTypeArg (String -> REPL ())
| FilenameArg (FilePath -> REPL ()) | FilenameArg (FilePath -> REPL ())
| OptionArg (String -> REPL ()) | OptionArg (String -> REPL ())
@ -175,6 +176,8 @@ commandList =
"set the current working directory" "set the current working directory"
, CommandDescr ":module" (FilenameArg moduleCmd) , CommandDescr ":module" (FilenameArg moduleCmd)
"load a module" "load a module"
, CommandDescr ":let" (DeclsArg letCmd)
"bind Cryptol expressions to names"
, CommandDescr ":check" (ExprArg qcCmd) , CommandDescr ":check" (ExprArg qcCmd)
"use random testing to check that the argument always returns true" "use random testing to check that the argument always returns true"
@ -228,6 +231,9 @@ evalCmd str = do
ppOpts <- getPPValOpts ppOpts <- getPPValOpts
io $ rethrowEvalError $ print $ pp $ E.WithBase ppOpts val io $ rethrowEvalError $ print $ pp $ E.WithBase ppOpts val
letCmd :: String -> REPL ()
letCmd = replEvalDecls
qcCmd :: String -> REPL () qcCmd :: String -> REPL ()
qcCmd "" = qcCmd "" =
do xs <- getPropertyNames do xs <- getPropertyNames
@ -551,6 +557,9 @@ replParse parse str = case parse str of
replParseExpr :: String -> REPL P.Expr replParseExpr :: String -> REPL P.Expr
replParseExpr = replParse $ parseExprWith interactiveConfig replParseExpr = replParse $ parseExprWith interactiveConfig
replParseDecls :: String -> REPL [P.Decl]
replParseDecls = replParse $ parseDeclsWith interactiveConfig
interactiveConfig :: Config interactiveConfig :: Config
interactiveConfig = defaultConfig { cfgSource = "<interactive>" } interactiveConfig = defaultConfig { cfgSource = "<interactive>" }
@ -577,7 +586,14 @@ 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 = liftModuleCmd $ M.checkExpr e replCheckExpr e = do
eenv <- getExtEnv
liftModuleCmd $ M.checkExprWith eenv e
replCheckDecls :: [P.Decl] -> REPL [T.DeclGroup]
replCheckDecls ds = do
eenv <- getExtEnv
liftModuleCmd $ M.checkDeclsWith eenv ds
replSpecExpr :: T.Expr -> REPL T.Expr replSpecExpr :: T.Expr -> REPL T.Expr
replSpecExpr e = liftModuleCmd $ S.specialize e replSpecExpr e = liftModuleCmd $ S.specialize e
@ -597,13 +613,21 @@ 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))
val <- liftModuleCmd (M.evalExpr def1) eenv <- getExtEnv
val <- liftModuleCmd (M.evalExprWith eenv def1)
whenDebug (io (putStrLn (dump def1))) whenDebug (io (putStrLn (dump def1)))
return (val,ty) return (val,ty)
where where
warnDefault ns (x,t) = warnDefault ns (x,t) =
print $ text "Assuming" <+> ppWithNames ns x <+> text "=" <+> pp t print $ text "Assuming" <+> ppWithNames ns x <+> text "=" <+> pp t
replEvalDecls :: String -> REPL ()
replEvalDecls str = do
decls <- replParseDecls str
-- TODO: extend name environment for all the names declared in decls
dgs <- replCheckDecls decls
undefined
replEdit :: String -> REPL Bool replEdit :: String -> REPL Bool
replEdit file = do replEdit file = do
mb <- io (lookupEnv "EDITOR") mb <- io (lookupEnv "EDITOR")
@ -666,6 +690,7 @@ parseCommand findCmd line = do
case findCmd cmd of case findCmd cmd of
[c] -> case cBody c of [c] -> case cBody c of
ExprArg body -> Just (Command (body args')) ExprArg body -> Just (Command (body args'))
DeclsArg body -> Just (Command (body args'))
ExprTypeArg body -> Just (Command (body args')) ExprTypeArg body -> Just (Command (body args'))
FilenameArg body -> Just (Command (body =<< expandHome args')) FilenameArg body -> Just (Command (body =<< expandHome args'))
OptionArg body -> Just (Command (body args')) OptionArg body -> Just (Command (body args'))

View File

@ -136,6 +136,7 @@ cmdComp prefix c = Completion
cmdArgument :: CommandBody -> CompletionFunc REPL cmdArgument :: CommandBody -> CompletionFunc REPL
cmdArgument ct cursor@(l,_) = case ct of cmdArgument ct cursor@(l,_) = case ct of
ExprArg _ -> completeExpr cursor ExprArg _ -> completeExpr cursor
DeclsArg _ -> (completeExpr +++ completeType) cursor
ExprTypeArg _ -> (completeExpr +++ completeType) cursor ExprTypeArg _ -> (completeExpr +++ completeType) cursor
FilenameArg _ -> completeFilename cursor FilenameArg _ -> completeFilename cursor
ShellArg _ -> completeFilename cursor ShellArg _ -> completeFilename cursor

View File

@ -23,6 +23,7 @@ module REPL.Monad (
-- ** Environment -- ** Environment
, getModuleEnv, setModuleEnv , getModuleEnv, setModuleEnv
, getExtEnv, setExtEnv
, getTSyns, getNewtypes, getVars , getTSyns, getNewtypes, getVars
, whenDebug , whenDebug
, getExprNames , getExprNames
@ -61,6 +62,7 @@ import Control.Monad (unless,when)
import Data.IORef import Data.IORef
(IORef,newIORef,readIORef,modifyIORef) (IORef,newIORef,readIORef,modifyIORef)
import Data.List (isPrefixOf) import Data.List (isPrefixOf)
import Data.Monoid (Monoid(..))
import Data.Typeable (Typeable) import Data.Typeable (Typeable)
import System.Console.ANSI (setTitle) import System.Console.ANSI (setTitle)
import qualified Control.Exception as X import qualified Control.Exception as X
@ -80,6 +82,8 @@ 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@
, eUserEnv :: UserEnv , eUserEnv :: UserEnv
} }
@ -92,6 +96,7 @@ defaultRW isBatch = do
, eContinue = True , eContinue = True
, eIsBatch = isBatch , eIsBatch = isBatch
, eModuleEnv = env , eModuleEnv = env
, eExtEnv = mempty
, eUserEnv = mkUserEnv userOptions , eUserEnv = mkUserEnv userOptions
} }
@ -285,6 +290,11 @@ 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
getExtEnv = eExtEnv `fmap` getRW
setExtEnv :: M.ExtendedEnv -> REPL ()
setExtEnv eenv = modifyRW_ (\rw -> rw { eExtEnv = eenv })
-- User Environment Interaction ------------------------------------------------ -- User Environment Interaction ------------------------------------------------

View File

@ -14,6 +14,7 @@ module Cryptol.Eval (
, EvalEnv() , EvalEnv()
, emptyEnv , emptyEnv
, evalExpr , evalExpr
, evalDecls
, EvalError(..) , EvalError(..)
, WithBase(..) , WithBase(..)
) where ) where

View File

@ -9,13 +9,16 @@
module Cryptol.ModuleSystem ( module Cryptol.ModuleSystem (
-- * Module System -- * Module System
ModuleEnv(..), initialModuleEnv ModuleEnv(..), initialModuleEnv
, ExtendedEnv(..)
, ModuleError(..), ModuleWarning(..) , ModuleError(..), ModuleWarning(..)
, ModuleCmd, ModuleRes , ModuleCmd, ModuleRes
, findModule , findModule
, loadModuleByPath , loadModuleByPath
, loadModule , loadModule
, checkExpr , checkExprWith
, evalExpr , evalExprWith
, checkDeclsWith
, evalDeclsWith
, focusedEnv , focusedEnv
-- * Interfaces -- * Interfaces
@ -59,11 +62,24 @@ loadModule m env = runModuleM env $ do
setFocusedModule (T.mName m') setFocusedModule (T.mName m')
return m' return m'
-- Extended Environments -------------------------------------------------------
-- These functions are particularly useful for interactive modes, as
-- they allow for expressions to be evaluated in an environment that
-- can extend dynamically outside of the context of a module.
-- | Check the type of an expression. -- | Check the type of an expression.
checkExpr :: P.Expr -> ModuleCmd (T.Expr,T.Schema) checkExprWith :: ExtendedEnv -> P.Expr -> ModuleCmd (T.Expr,T.Schema)
checkExpr e env = runModuleM env (interactive (Base.checkExpr e)) checkExprWith eenv e env = runModuleM env (interactive (Base.checkExprWith eenv e))
-- | Evaluate an expression. -- | Evaluate an expression.
evalExpr :: T.Expr -> ModuleCmd E.Value evalExprWith :: ExtendedEnv -> T.Expr -> ModuleCmd E.Value
evalExpr e env = runModuleM env (interactive (Base.evalExpr e)) evalExprWith eenv e env = runModuleM env (interactive (Base.evalExprWith eenv e))
-- | Typecheck declarations.
checkDeclsWith :: ExtendedEnv -> [P.Decl] -> ModuleCmd [T.DeclGroup]
checkDeclsWith eenv ds env = runModuleM env (interactive (Base.checkDeclsWith eenv 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))

View File

@ -8,6 +8,7 @@
module Cryptol.ModuleSystem.Base where module Cryptol.ModuleSystem.Base where
import Cryptol.ModuleSystem.Env (ExtendedEnv(..))
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
@ -31,6 +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 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,7 +69,6 @@ renameExpr e = do
env <- getFocusedEnv env <- getFocusedEnv
rename (R.namingEnv env) e rename (R.namingEnv env) e
-- NoPat ----------------------------------------------------------------------- -- NoPat -----------------------------------------------------------------------
-- | Run the noPat pass. -- | Run the noPat pass.
@ -223,6 +224,35 @@ checkExpr e = do
re <- renameExpr npe re <- renameExpr npe
typecheck T.tcExpr re =<< getQualifiedEnv 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 <- renameExpr npe
env <- getQualifiedEnv
let env' = env <> eeIfaceDecls eenv
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
npds <- noPat ds
rds <- rename (eeNames eenv) npds
env <- getQualifiedEnv
let env' = env <> eeIfaceDecls eenv
typecheck T.tcDecls rds env'
-- | Typecheck a module. -- | Typecheck a module.
checkModule :: P.Module -> ModuleM T.Module checkModule :: P.Module -> ModuleM T.Module
checkModule m = do checkModule m = do
@ -304,3 +334,17 @@ evalExpr :: T.Expr -> ModuleM E.Value
evalExpr e = do evalExpr e = do
env <- getEvalEnv env <- getEvalEnv
return (E.evalExpr env e) return (E.evalExpr env e)
evalExprWith :: ExtendedEnv -> T.Expr -> ModuleM E.Value
evalExprWith eenv e = 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' }

View File

@ -14,6 +14,7 @@ import Paths_cryptol (getDataDir)
import Cryptol.Eval (EvalEnv) import Cryptol.Eval (EvalEnv)
import Cryptol.ModuleSystem.Interface import Cryptol.ModuleSystem.Interface
import qualified Cryptol.ModuleSystem.NamingEnv as R
import Cryptol.Parser.AST import Cryptol.Parser.AST
import qualified Cryptol.TypeCheck as T import qualified Cryptol.TypeCheck as T
import qualified Cryptol.TypeCheck.AST as T import qualified Cryptol.TypeCheck.AST as T
@ -21,7 +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 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)
import qualified Data.List as List import qualified Data.List as List
@ -126,3 +127,28 @@ addLoadedModule tm lm
, lmInterface = genIface tm , lmInterface = genIface tm
, lmModule = tm , lmModule = tm
} }
-- Extended 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
}
instance Monoid ExtendedEnv where
mempty = EEnv
{ eeNames = mempty
, eeDecls = mempty
, eeEnv = mempty
}
mappend ee1 ee2 = EEnv
{ eeNames = eeNames ee1 <> eeNames ee2
, eeDecls = eeDecls ee1 <> eeDecls ee2
, eeEnv = eeEnv ee1 <> eeEnv ee2
}

View File

@ -12,7 +12,7 @@ module Cryptol.ModuleSystem.Interface (
, IfaceDecls(..) , IfaceDecls(..)
, IfaceTySyn, ifTySynName , IfaceTySyn, ifTySynName
, IfaceNewtype , IfaceNewtype
, IfaceDecl(..) , IfaceDecl(..), mkIfaceDecl
, shadowing , shadowing
, interpImport , interpImport

View File

@ -5,6 +5,7 @@ module Cryptol.Parser
, parseProgram, parseProgramWith , parseProgram, parseProgramWith
, parseExpr, parseExprWith , parseExpr, parseExprWith
, parseDecl, parseDeclWith , parseDecl, parseDeclWith
, parseDecls, parseDeclsWith
, parseModName , parseModName
, ParseError(..), ppError , ParseError(..), ppError
, Layout(..) , Layout(..)
@ -140,6 +141,7 @@ import Paths_cryptol
%name programLayout program_layout %name programLayout program_layout
%name expr expr %name expr expr
%name decl decl %name decl decl
%name decls decls
%name modName modName %name modName modName
%tokentype { Located Token } %tokentype { Located Token }
%monad { ParseM } %monad { ParseM }
@ -722,5 +724,11 @@ parseDeclWith cfg = parse cfg { cfgModuleScope = False } decl
parseDecl :: String -> Either ParseError Decl parseDecl :: String -> Either ParseError Decl
parseDecl = parseDeclWith defaultConfig parseDecl = parseDeclWith defaultConfig
parseDeclsWith :: Config -> String -> Either ParseError [Decl]
parseDeclsWith cfg = parse cfg { cfgModuleScope = False } decls
parseDecls :: String -> Either ParseError [Decl]
parseDecls = parseDeclsWith defaultConfig
-- vim: ft=haskell -- vim: ft=haskell
} }

View File

@ -10,6 +10,7 @@
-- patterns. It also eliminates pattern bindings by de-sugaring them -- patterns. It also eliminates pattern bindings by de-sugaring them
-- into `Bind`. Furthermore, here we associate signatures and pragmas -- into `Bind`. Furthermore, here we associate signatures and pragmas
-- with the names to which they belong. -- with the names to which they belong.
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RecordWildCards #-}
module Cryptol.Parser.NoPat (RemovePatterns(..),Error(..)) where module Cryptol.Parser.NoPat (RemovePatterns(..),Error(..)) where
@ -39,6 +40,8 @@ instance RemovePatterns Expr where
instance RemovePatterns Module where instance RemovePatterns Module where
removePatterns m = runNoPatM (noPatModule m) removePatterns m = runNoPatM (noPatModule m)
instance RemovePatterns [Decl] where
removePatterns ds = runNoPatM (noPatDs ds)
simpleBind :: Located QName -> Expr -> Bind simpleBind :: Located QName -> Expr -> Bind
simpleBind x e = Bind { bName = x, bParams = [], bDef = e simpleBind x e = Bind { bName = x, bParams = [], bDef = e

View File

@ -9,6 +9,7 @@
module Cryptol.TypeCheck module Cryptol.TypeCheck
( tcModule ( tcModule
, tcExpr , tcExpr
, tcDecls
, InferInput(..) , InferInput(..)
, InferOutput(..) , InferOutput(..)
, NameSeeds , NameSeeds
@ -22,6 +23,7 @@ module Cryptol.TypeCheck
import qualified Cryptol.Parser.AST as P import qualified Cryptol.Parser.AST as P
import Cryptol.Parser.Position(Range) import Cryptol.Parser.Position(Range)
import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.AST
import Cryptol.TypeCheck.Depends (FromDecl)
import Cryptol.TypeCheck.Monad import Cryptol.TypeCheck.Monad
( runInferM ( runInferM
, InferInput(..) , InferInput(..)
@ -31,7 +33,7 @@ import Cryptol.TypeCheck.Monad
, lookupVar , lookupVar
) )
import Cryptol.Prims.Types(typeOf) import Cryptol.Prims.Types(typeOf)
import Cryptol.TypeCheck.Infer (inferModule, inferBinds) import Cryptol.TypeCheck.Infer (inferModule, inferBinds, inferDs)
import Cryptol.TypeCheck.InferTypes(Error(..),Warning(..),VarType(..)) import Cryptol.TypeCheck.InferTypes(Error(..),Warning(..),VarType(..))
import Cryptol.TypeCheck.Solve(simplifyAllConstraints) import Cryptol.TypeCheck.Solve(simplifyAllConstraints)
import Cryptol.Utils.PP import Cryptol.Utils.PP
@ -81,6 +83,11 @@ tcExpr e0 inp = runInferM inp
: map show res : map show res
) )
tcDecls :: FromDecl d => [d] -> InferInput -> IO (InferOutput [DeclGroup])
tcDecls ds inp = runInferM inp $ inferDs ds $ \dgs -> do
simplifyAllConstraints
return dgs
ppWarning :: (Range,Warning) -> Doc ppWarning :: (Range,Warning) -> Doc
ppWarning (r,w) = text "[warning] at" <+> pp r <> colon $$ nest 2 (pp w) ppWarning (r,w) = text "[warning] at" <+> pp r <> colon $$ nest 2 (pp w)