packages feed

hakaru-0.4.0: commands/HkMaple.hs

{-# LANGUAGE CPP
           , OverloadedStrings
           , DataKinds
           , GADTs
           , RecordWildCards
           , ScopedTypeVariables
           #-}

module Main where

import           Language.Hakaru.Pretty.Concrete  
import           Language.Hakaru.Syntax.AST.Transforms
import           Language.Hakaru.Syntax.TypeCheck
import           Language.Hakaru.Command (parseAndInfer, readFromFile, Term)

import           Language.Hakaru.Syntax.Rename
import           Language.Hakaru.Simplify
import           Language.Hakaru.Maple 
import           Language.Hakaru.Parser.Maple 


#if __GLASGOW_HASKELL__ < 710
import           Control.Applicative   (Applicative(..), (<$>))
#endif

import           Data.Monoid ((<>), mconcat)
import           Data.Text (Text, unpack, pack)
import qualified Data.Text as Text 
import qualified Data.Text.IO as IO
import           System.IO (stderr)
import           Data.List (intercalate) 
import           Text.Read (readMaybe)
import           Control.Exception(throw)
import qualified Options.Applicative as O
import qualified Data.Map as M 


data Options a 
  = Options
    { moptions      :: MapleOptions String
    , no_unicode    :: Bool
    , program       :: a } 
  | ListCommands 


parseKeyVal :: O.ReadM (String, String) 
parseKeyVal = 
  O.maybeReader $ (\str -> 
    case map Text.strip $ Text.splitOn "," str of 
      [k,v] -> return (unpack k, unpack v)
      _     -> Nothing) . pack 

options :: O.Parser (Options FilePath)
options = (Options
  <$> (MapleOptions <$> 
        O.option O.str
        ( O.long "command" <>
          O.help ("Command to send to Maple. You may enter a prefix of the command string if "
                 ++"it uniquely identifies a command. "
                 ++"Default: Simplify") <>
          O.short 'c' <> 
          O.value "Simplify" ) 
    <*> O.switch
        ( O.long "debug" <>
          O.help "Prints output that is sent to Maple." )
    <*> O.option O.auto
        ( O.long "timelimit" <>
          O.help "Set Maple to timeout in N seconds." <>
          O.showDefault <>
          O.value 90 <>
          O.metavar "N")
    <*> (M.fromList <$> 
          O.many (O.option parseKeyVal
        ( O.long "maple-opt" <> 
          O.short 'm' <> 
          O.help ( "Extra options to send to Maple\neach options is of the form KEY=VAL\n"
                 ++"where KEY is a Maple name, and VAL is a Maple expression.")
        ))))
  <*> O.switch 
      ( O.long "no-unicode" <> 
        O.short 'u' <> 
        O.help "Removes unicode characters from names in the Maple output.")
  <*> O.strArgument
      ( O.metavar "PROGRAM" <> 
        O.help "Filename containing program to be simplified, or \"-\" to read from input." )) O.<|> 
  ( O.flag' ListCommands  
      ( O.long "list-commands" <>
        O.help "Get list of available commands from Maple." <>
        O.short 'l') )

parseOpts :: IO (Options FilePath)
parseOpts = O.execParser $ O.info (O.helper <*> options)
      (O.fullDesc <> O.progDesc progDesc)

progDesc :: String 
progDesc = unwords  
  ["hk-maple: invokes a Maple command on a Hakaru program. "
  ,"Given a Hakaru program in concrete syntax and a Maple-Hakaru command,"
  ,"typecheck the program"
  ,"invoke the Maple command on the program and its type"
  ,"pretty print, parse and typecheck the program resulting from Maple"
  ]

et (TypedAST t (x :: Term a)) = TypedAST t (expandTransformations x)

main :: IO ()
main = parseOpts >>= runMaple

runMaple :: Options FilePath -> IO ()
runMaple ListCommands = 
  listCommands >>= \cs -> putStrLn $ "Available Hakaru Maple commands:\n\t"++ intercalate ", " cs

runMaple Options{..} = readFromFile program >>= \prog -> 
  case parseAndInfer prog of
    Left  err  -> IO.hPutStrLn stderr err
    Right ast  -> do 
      TypedAST _ ast' <- sendToMaple' moptions (et ast)
      print $ pretty 
            $ (if no_unicode then renameAST removeUnicodeChars else id) 
            $ ast'

listCommands :: IO [String] 
listCommands = do 
    let toMaple_ = "use Hakaru, NewSLO in lprint(map(curry(sprintf,`%s`),NewSLO:-Commands)) end use;"
    fromMaple <- maple toMaple_
    maybe (throw $ MapleInterpreterException fromMaple toMaple_)
          return 
          (readMaybe fromMaple)