copilot-3.14: src/Language/Copilot/Main.hs
-- | Create Copilot executables that generate code or interpret streams and
-- print the results to stdout.
module Language.Copilot.Main ( copilotMain, defaultMain ) where
import qualified Copilot.Core as C (Spec)
import Copilot.Language (interpret)
import Copilot.Language.Reify (reify)
import Copilot.Language (Spec)
import qualified Copilot.PrettyPrint as PP
import Options.Applicative
import Data.Semigroup ((<>))
import Control.Monad (when)
-- | An interpreter of Copilot specifications for a given
-- number of simulation steps.
type Interpreter = Integer -> Spec -> IO ()
-- | A compiler from
-- <https://hackage.haskell.org/package/copilot-core Copilot Core>
-- specifications.
type Compiler = FilePath -> C.Spec -> IO ()
-- | A pretty printer of Copilot specifications.
type Printer = Spec -> IO ()
-- | Command line arguments supported by all commands in 'cmdargs'.
data CmdArgs = CmdArgs
{ aoutput :: String
, acompile :: Bool
, apretty :: Bool
, ainterpret :: Int
}
-- | Command line arguments handled by the Copilot main function.
cmdargs :: Parser CmdArgs
cmdargs = CmdArgs
<$> strOption (long "output" <> short 'o' <> value "."
<> help "Output directory of C files")
<*> switch (long "justrun" <> short 'c'
<> help "Do NOT produce *.c and *.h files as output")
<*> switch (long "print" <> short 'p'
<> help "Pretty print the specification")
<*> option auto (long "interpret" <> short 'i' <> value 0
<> metavar "INT" <> showDefault
<> help "Interpret specification and write result to output")
-- | Create a main to either compile or interpret a copilot specification.
--
-- This function must be provided an auxiliary function capable of compiling
-- <https://hackage.haskell.org/package/copilot-core Copilot Core>
-- specifications for some target.
--
-- The command line program supports four main commands:
--
-- * @--output/-o@: use the given compiler to produce C code.
--
-- * @--justrun/-c@: execute a dry-run, which parses and converts the
-- specification to core but does not produce any output.
--
-- * @--print/-p@: pretty print the specification.
--
-- * @--interpret/-i NUM@: interpret the specification for a given number
-- of steps.
copilotMain :: Interpreter -> Printer -> Compiler -> Spec -> IO ()
copilotMain interp pretty comp spec = main =<< execParser opts
where
opts = info (cmdargs <**> helper) fullDesc
main :: CmdArgs -> IO ()
main args = do
let iters = ainterpret args
when (apretty args) $ pretty spec
when (iters Prelude.> 0) $ interp (fromIntegral iters) spec
when (not $ acompile args) $ do
spec' <- reify spec
comp (aoutput args) spec'
-- | Create a main function with a default interpreter and pretty printer.
--
-- This function must be provided an auxiliary function capable of compiling
-- <https://hackage.haskell.org/package/copilot-core Copilot Core>
-- specifications for some target.
--
-- This function relies on 'copilotMain', please refer to that function for the
-- command line options.
defaultMain :: Compiler -> Spec -> IO ()
defaultMain = copilotMain interpret prettyPrint
where
-- Transform a high-level Copilot Language specification into a low-level
-- Copilot Core specification and pretty-print it to stdout.
prettyPrint :: Spec -> IO ()
prettyPrint e = fmap PP.prettyPrint (reify e) >>= putStr