module Language.Hakaru.Command where
import Language.Hakaru.Syntax.ABT
import qualified Language.Hakaru.Syntax.AST as T
import Language.Hakaru.Parser.Import (expandImports)
import Language.Hakaru.Parser.Parser hiding (style)
import Language.Hakaru.Parser.SymbolResolve (resolveAST)
import Language.Hakaru.Syntax.TypeCheck
import Control.Monad.Trans.Except
import Control.Monad (when)
import qualified Data.Text as Text
import qualified Data.Text.IO as IO
import qualified Data.Text.Utf8 as U
import qualified Options.Applicative as O
import Data.Vector
import System.IO (stderr)
import System.Environment (getArgs)
import Data.Monoid ((<>),mconcat)
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative (Applicative(..), (<$>))
#endif
type Term a = TrivialABT T.Term '[] a
parseAndInfer :: Text.Text
-> Either Text.Text (TypedAST (TrivialABT T.Term))
parseAndInfer x =
case parseHakaru x of
Left err -> Left (Text.pack . show $ err)
Right past ->
let m = inferType (resolveAST past) in
runTCM m (splitLines x) LaxMode
parseAndInfer' :: Text.Text
-> IO (Either Text.Text (TypedAST (TrivialABT T.Term)))
parseAndInfer' x =
case parseHakaruWithImports x of
Left err -> return . Left $ Text.pack . show $ err
Right past -> do
past' <- runExceptT (expandImports past)
case past' of
Left err -> return . Left $ Text.pack . show $ err
Right past'' -> do
let m = inferType (resolveAST past'')
return (runTCM m (splitLines x) LaxMode)
parseAndInferWithDebug
:: Bool
-> Text.Text
-> IO (Either Text.Text (TypedAST (TrivialABT T.Term)))
parseAndInferWithDebug debug x =
case parseHakaru x of
Left err -> return $ Left (Text.pack . show $ err)
Right past -> do
when debug $ putErrorLn $ hrule "Parsed AST"
when debug $ putErrorLn . Text.pack . show $ past
let resolved = resolveAST past
let inferred = runTCM (inferType resolved) (splitLines x) LaxMode
when debug $ putErrorLn $ hrule "Inferred AST"
when debug $ putErrorLn . Text.pack . show $ inferred
return $ inferred
where hrule s = Text.concat ["\n<=======================| "
,s," |=======================>\n"]
putErrorLn = IO.hPutStrLn stderr
splitLines :: Text.Text -> Maybe (Vector Text.Text)
splitLines = Just . fromList . Text.lines
readFromFile :: String -> IO Text.Text
readFromFile "-" = U.getContents
readFromFile x = U.readFile x
simpleCommand :: (Text.Text -> IO ()) -> Text.Text -> IO ()
simpleCommand k fnName =
let parser =
O.info (O.helper <*> opts)
(O.fullDesc <> O.progDesc
(mconcat["Hakaru:", Text.unpack fnName, " command"]))
opts =
O.strArgument
( O.metavar "PROGRAM" <>
O.showDefault <> O.value "-" <>
O.help "Filepath to Hakaru program OR \"-\"" )
in O.execParser parser >>= readFromFile >>= k
writeToFile :: String -> (Text.Text -> IO ())
writeToFile "-" = U.putStrLn
writeToFile x = U.writeFile x