content: 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)
  