module GF.Command.Parse(readCommandLine, pCommand) where
import PGF(pExpr,pIdent)
import GF.Grammar.Parser(runPartial,pTerm)
import GF.Command.Abstract
import Data.Char(isDigit,isSpace)
import Control.Monad(liftM2)
import Text.ParserCombinators.ReadP
readCommandLine :: String -> Maybe CommandLine
readCommandLine s =
case [x | (x,cs) <- readP_to_S pCommandLine s, all isSpace cs] of
[x] -> Just x
_ -> Nothing
pCommandLine =
(skipSpaces >> char '-' >> char '-' >> pTheRest >> return []) -- comment
<++
(sepBy (skipSpaces >> pPipe) (skipSpaces >> char ';'))
pPipe = sepBy1 (skipSpaces >> pCommand) (skipSpaces >> char '|')
pCommand = (do
cmd <- pIdent <++ (char '%' >> fmap ('%':) pIdent)
skipSpaces
opts <- sepBy pOption skipSpaces
arg <- if getCommandOp cmd == "cc" then pArgTerm else pArgument
return (Command cmd opts arg)
)
<++ (do
char '?'
skipSpaces
c <- pSystemCommand
return (Command "sp" [OFlag "command" (VStr c)] ANoArg)
)
pOption = do
char '-'
flg <- pIdent
option (OOpt flg) (fmap (OFlag flg) (char '=' >> pValue))
pValue = do
fmap VInt (readS_to_P reads)
<++
fmap VStr (readS_to_P reads)
<++
fmap VId pFilename
pFilename = liftM2 (:) (satisfy isFileFirst) (munch (not . isSpace)) where
isFileFirst c = not (isSpace c) && not (isDigit c)
pArgument =
option ANoArg
(fmap AExpr pExpr
<++
(skipSpaces >> char '%' >> fmap AMacro pIdent))
pArgTerm = ATerm `fmap` readS_to_P sTerm
where
sTerm s = case runPartial pTerm s of
Right (s,t) -> [(t,s)]
_ -> []
pSystemCommand =
(char '"' >> (manyTill (pEsc <++ get) (char '"')))
<++
pTheRest
where
pEsc = char '\\' >> get
pTheRest = munch (const True)