{-# LANGUAGE FlexibleInstances, FlexibleContexts, ScopedTypeVariables, GADTs, TypeFamilies, DeriveDataTypeable #-} module Language.HERMIT.Shell.Command ( -- * The HERMIT Command-line Shell commandLine , unicodeConsole ) 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.Context import Language.HERMIT.Monad import Language.HERMIT.Kure import Language.HERMIT.Dictionary import Language.HERMIT.External import Language.HERMIT.Interp import Language.HERMIT.Kernel (queryK) import Language.HERMIT.Kernel.Scoped import Language.HERMIT.Parser import Language.HERMIT.PrettyPrinter.Common import Language.HERMIT.Primitive.GHC import Language.HERMIT.Primitive.Inline import Language.HERMIT.Primitive.Navigation 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 -- GADTs can't have docs on constructors. See Haddock ticket #43. -- | AstEffects are things that are recorded in our log and saved files. -- - Apply a rewrite (giving a whole new lower-level AST). -- - Change the current location using a computed path. -- - Change the currect location using directions. -- - Begin or end a scope. -- - Add a tag. -- - Run a precondition or other predicate that must not fail. data AstEffect :: * where Apply :: (Injection GHC.ModGuts g, Walker HermitC g) => RewriteH g -> AstEffect Pathfinder :: (Injection GHC.ModGuts g, Walker HermitC g) => TranslateH g PathH -> AstEffect Direction :: Direction -> AstEffect -- PushFocus Path -- This changes the current location using a give path BeginScope :: AstEffect EndScope :: AstEffect Tag :: String -> AstEffect CorrectnessCritera :: (Injection GHC.ModGuts g, Walker HermitC g) => TranslateH g () -> AstEffect 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 QueryString :: (Injection GHC.ModGuts g, Walker HermitC g) => TranslateH g String -> QueryFun QueryDocH :: (PrettyH CoreTC -> TranslateH CoreTC DocH) -> 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 | Delete SAST 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 $ \ (RewriteCoreTCBox rr) -> AstEffect (Apply rr) , interp $ \ (BiRewriteCoreBox br) -> AstEffect (Apply $ forewardT br) , interp $ \ (CrumbBox cr) -> AstEffect (Pathfinder (return [cr] :: TranslateH CoreTC PathH)) , interp $ \ (PathBox p) -> AstEffect (Pathfinder (return p :: TranslateH CoreTC PathH)) , interp $ \ (TranslateCorePathBox tt) -> AstEffect (Pathfinder tt) , interp $ \ (StringBox str) -> QueryFun (Message str) , interp $ \ (TranslateCoreStringBox tt) -> QueryFun (QueryString tt) , interp $ \ (TranslateCoreTCStringBox tt) -> QueryFun (QueryString tt) , interp $ \ (TranslateCoreTCDocHBox tt) -> QueryFun (QueryDocH $ unTranslateDocH 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 "gc" (Delete . SAST) [ "garbage-collect a given AST; does not remove from command log" ] , external "gc" (SessionStateEffect gc) [ "garbage-collect all ASTs except for the initial and current AST" ] , 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 node"] , external "down" (deprecatedIntToPathT 0 :: TranslateH Core PathH) -- TODO: short-term solution [ "move to the first child"] , external "tag" Tag [ "tag