packages feed

CSPM-cspm-0.4.0.0: src/Main.hs

----------------------------------------------------------------------------
-- |
-- Module      :  Main
-- Copyright   :  (c) Fontaine 2010
-- License     :  BSD
-- 
-- Maintainer  :  Fontaine@cs.uni-duesseldorf.de
-- Stability   :  experimental
-- Portability :  GHC-only
--
-- Comand line interface for the CSPM tools.
----------------------------------------------------------------------------
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE RecordWildCards #-}

module Main
where

import CSPM.Interpreter
import CSPM.Interpreter.Test.CLI (evalEnv)
import CSPM.FiringRules.Trace (trace)
import CSPM.FiringRules.HelperClasses

import CSPM.LTS.MkLtsPar (mkLtsPar)
import CSPM.LTS.ToCsp (ltsToCsp)
import CSPM.LTS.ToDot (mkDotFile)

import Language.CSPM.Frontend (LexError(..),ParseError(..),RenameError(..))
import Language.CSPM.Token (pprintAlexPosn, Token(..))

import System.Console.CmdArgs
import Control.Exception
import System.Exit (exitSuccess, exitFailure)

instance EqOrd INT
instance CSP1 INT
instance CSP2 INT
instance FShow INT

-- | main-funtion for the command line.
main :: IO ()
main = do
  arguments <- cmdArgsRun argParser
  handleException $ execCommand arguments
  exitSuccess

-- definition of the command line parser
argParser :: Mode (CmdArgs Args)
argParser = cmdArgsMode $ modes [evalMode, traceMode, fdrMode, dotMode ]
  &= program "cspm"
  &= summary "cspm command line utility V0.4.0.0"

data Args = 
   Eval {
     evalContext :: Maybe FilePath
    ,evalExpr :: String
    }
  |Trace {
     src    :: FilePath
    ,entry  :: String
    }
  |FDR {
     src    :: FilePath
    ,entry  :: String
    ,out :: Maybe FilePath
    }
  |Dot {
     src    :: FilePath
    ,entry  :: String
    ,out :: Maybe FilePath
    } deriving (Data,Typeable,Show,Eq)

evalMode :: Args
evalMode = Eval {
   evalContext = def
       &= help "optional: CSPM specification to load into context"
       &= typFile 
       &= explicit &= name "s" &= name "src"
  ,evalExpr = def 
       &= help "the expression to evaluate"
       &= typ "EXPR"
       &= argPos 0
  } &= program "evaluate an expression"

traceMode :: Args
traceMode = Trace {
  src = def
    &= help "CSPM specification"
    &= typFile
    &= argPos 0
  ,entry = "MAIN"
    &= help "optional: the main process" 
    &= typ "PROCESS"
    &= explicit &= name "main" &= name "m"
  } &= program "trace a process"

fdrMode :: Args
fdrMode = FDR {
  src = def
    &= help "CSPM specification"
    &= typFile
    &= argPos 0
  ,entry = "MAIN"
    &= help "optional: the main process" 
    &= typ "PROCESS"
    &= explicit &= name "main" &= name "m"
  ,out = def
    &= help "optional: name of the generated fdr file"
    &= typFile
    &= explicit &= name "out" &= name "o"
  } &= program "compute the LTS and dump it as fdr script"

dotMode :: Args
dotMode = Dot {
  src = def
    &= help "CSPM specification"
    &= typFile
    &= argPos 0
  ,entry = "MAIN"
    &= help "optional: the main process" 
    &= typ "PROCESS"
    &= explicit &= name "main" &= name "m"
  ,out = def
    &= help "optional: name of the generated dot file"
    &= typFile
    &= explicit &= name "out" &= name "o"
  } &= program "compute the LTS and dump it as dot graph"

-- execute the command according to command line arguments
execCommand :: Args -> IO ()
execCommand Eval {..} = do
  isVerbose <- isLoud
  (val,_) <- evalEnv isVerbose evalContext evalExpr
  print val

execCommand Trace {..} = do
  (proc,sigma) <- mkProcess src entry
  trace sigma proc

execCommand FDR {..} = do
  (proc,sigma) <- mkProcess src entry
  let
    lts = mkLtsPar sigma proc
    outFile = case out of
      Just f -> f
      Nothing -> src  ++ ".fdr"
  ltsToCsp proc lts outFile
  return ()

execCommand Dot {..} = do
  (proc,sigma) <- mkProcess src entry
  let
    lts = mkLtsPar sigma proc
    outFile = case out of
      Just f -> f
      Nothing -> src ++ ".dot"
  mkDotFile outFile lts
  return ()

mkProcess :: FilePath -> String -> IO (Process, ClosureSet)
mkProcess file expr = do
  isVerbose <- isLoud
  (proc, env) <- evalEnv isVerbose (Just file) expr
  case proc of
    VProcess p -> return (p, getAllEvents env)
    _ -> error "type-error : entry-point is not a process"

-- example exception handler
handleException :: IO () -> IO ()
handleException x
  = x `catches` allHandler
  where
    allHandler = [
        Handler lexError, Handler parseError, Handler renameError
       ,Handler errCall
       ,Handler async  -- pressing CTRL c
       ,Handler ioExc  -- file not found etc
       ,Handler someExc ]
    lexError :: LexError -> IO ()
    lexError LexError {..} = do
      putStrLn "lexError"
      putStrLn $ pprintAlexPosn lexEPos
      putStrLn $ lexEMsg
      exitFailure
    parseError :: ParseError -> IO ()
    parseError ParseError {..}  = do
      putStrLn "parseError"
      putStrLn $ parseErrorMsg
      putStrLn $ pprintAlexPosn parseErrorPos
      putStrLn $ "at token : " ++ (show $ tokenString parseErrorToken)
      exitFailure
    renameError :: RenameError -> IO ()
    renameError RenameError {..} = do
      putStrLn "renameError"
      putStrLn $ renameErrorMsg
      putStrLn $ show renameErrorLoc
      exitFailure
    ioExc :: IOException -> IO ()
    ioExc err = do
      putStrLn $ show err
      exitFailure
    errCall :: ErrorCall -> IO ()
    errCall err = flip catches allHandler $ do
      putStrLn "unexpected error call"
      putStrLn $ show err
      exitFailure
    async :: AsyncException -> IO ()
    async err = do
      putStrLn "AsyncException (Pressing CRTL C ?)"
      putStrLn $ show err
      exitFailure
    someExc :: SomeException -> IO ()
    someExc err = do
      putStrLn $ show err
      exitFailure