{-# LANGUAGE FlexibleInstances, ScopedTypeVariables, GADTs, KindSignatures, TypeFamilies, DeriveDataTypeable #-} module Language.HERMIT.Shell.Command ( -- * The HERMIT Command-line Shell commandLine ) where import qualified GhcPlugins as GHC import Control.Applicative import Control.Arrow hiding (loop) import Control.Concurrent import Control.Concurrent.STM import Control.Exception.Base hiding (catch) import Control.Monad.State import Control.Monad.Error import Data.Char import Data.Monoid import Data.List (intercalate, isPrefixOf, nub) import Data.Default (def) import Data.Dynamic import qualified Data.Map as M import Data.Maybe import Language.HERMIT.Core import Language.HERMIT.Monad import Language.HERMIT.Kure import Language.HERMIT.Dictionary import Language.HERMIT.Expr import Language.HERMIT.External import Language.HERMIT.Interp import Language.HERMIT.Kernel.Scoped import Language.HERMIT.PrettyPrinter import Language.HERMIT.Primitive.Navigation import Language.HERMIT.Primitive.Inline -- import Language.HERMIT.Primitive.GHC import System.Console.ANSI import System.IO import qualified Text.PrettyPrint.MarkedHughesPJ as PP import System.Console.Haskeline hiding (catch) -- There are 4 types of commands, AST effect-ful, Shell effect-ful, Queries, and Meta-commands. data ShellCommand = AstEffect AstEffect | ShellEffect ShellEffect | QueryFun QueryFun | MetaCommand MetaCommand -- | AstEffects are things that are recorded in our log and saved files. data AstEffect -- | This applys a rewrite (giving a whole new lower-level AST) = Apply (RewriteH Core) -- | This changes the current location using a computed path | Pathfinder (TranslateH Core Path) -- | This changes the currect location using directions | Direction Direction -- | This changes the current location using a give path -- | PushFocus Path | BeginScope | EndScope | Tag String -- ^ Adding a tag -- | A precondition or other predicate that must not fail | CorrectnessCritera (TranslateH Core ()) deriving Typeable instance Extern AstEffect where type Box AstEffect = AstEffect box i = i unbox i = i data ShellEffect :: * where SessionStateEffect :: (CommandLineState -> SessionState -> IO SessionState) -> ShellEffect deriving Typeable data QueryFun :: * where QueryT :: TranslateH Core String -> QueryFun -- These two be can generalized into -- (CommandLineState -> IO String) Display :: QueryFun Message :: String -> QueryFun Inquiry ::(CommandLineState -> SessionState -> IO String) -> QueryFun deriving Typeable instance Extern QueryFun where type Box QueryFun = QueryFun box i = i unbox i = i data MetaCommand = Resume | Abort | Dump String String String Int | LoadFile String -- load a file on top of the current node | SaveFile String deriving Typeable instance Extern MetaCommand where type Box MetaCommand = MetaCommand box i = i unbox i = i -- TODO: Use another word, Navigation is a more general concept -- Perhaps VersionNavigation data Navigation = Back -- back (up) the derivation tree | Step -- down one step; assumes only one choice | Goto Int -- goto a specific node, if possible | GotoTag String -- goto a specific named tag deriving Show data ShellCommandBox = ShellCommandBox ShellCommand deriving Typeable instance Extern ShellEffect where type Box ShellEffect = ShellEffect box i = i unbox i = i instance Extern ShellCommand where type Box ShellCommand = ShellCommandBox box = ShellCommandBox unbox (ShellCommandBox i) = i interpShellCommand :: [Interp ShellCommand] interpShellCommand = [ interp $ \ (ShellCommandBox cmd) -> cmd , interp $ \ (RewriteCoreBox rr) -> AstEffect (Apply rr) , interp $ \ (TranslateCorePathBox tt) -> AstEffect (Pathfinder tt) , interp $ \ (StringBox str) -> QueryFun (Message str) , interp $ \ (TranslateCoreStringBox tt) -> QueryFun (QueryT tt) , interp $ \ (TranslateCoreCheckBox tt) -> AstEffect (CorrectnessCritera tt) , interp $ \ (effect :: AstEffect) -> AstEffect effect , interp $ \ (effect :: ShellEffect) -> ShellEffect effect , interp $ \ (query :: QueryFun) -> QueryFun query , interp $ \ (meta :: MetaCommand) -> MetaCommand meta ] -- TODO: move this into the shell, it is completely specific to the way -- the shell works. What about list, for example? --interpKernelCommand :: [Interp KernelCommand] --interpKernelCommand = -- [ Interp $ \ (KernelCommandBox cmd) -> cmd -- ] shell_externals :: [External] shell_externals = map (.+ Shell) [ external "resume" Resume -- HERMIT Kernel Exit [ "stops HERMIT; resumes compile" ] , external "abort" Abort -- UNIX Exit [ "hard UNIX-style exit; does not return to GHC; does not save" ] , external "display" Display [ "redisplays current state" ] , external "left" (Direction L) [ "move to the next child"] , external "right" (Direction R) [ "move to the previous child"] , external "up" (Direction U) [ "move to the parent"] , external "down" (Direction D) [ "move to the first child"] , external "tag" Tag [ "tag