{-# LANGUAGE ScopedTypeVariables #-} module Distribution.Simple.UUAGC.Parser(parserAG, parserAG', scanner, parseIOAction, parseClassAG, parseOptionAG) where import UU.Parsing import UU.Scanner import Distribution.Simple.UUAGC.AbsSyn import Options import System.Console.GetOpt import System.IO.Unsafe(unsafeInterleaveIO) import System.IO(hPutStr,stderr) import Control.Monad.Error data ParserError = DefParserError String deriving (Show, Eq, Read) instance Error ParserError where strMsg x = DefParserError x uFlags :: [String] uFlags = concat [ filter (not . null) x | Option _ x _ _ <- options] kwtxt = uFlags ++ ["file", "options", "class", "with"] kwotxt = ["=",":","..","."] sctxt = "..," octxt = "=:.," posTxt :: Pos posTxt = Pos 0 0 "" puFlag :: OptDescr (Options -> Options) -> Parser Token (Options -> Options) puFlag (Option _ [] _ _) = pFail puFlag (Option _ kws (NoArg f) _) = pAny (\kw -> const f <$> pKey kw) kws puFlag (Option _ kws (ReqArg f _) _) = pAny (\kw -> f <$ pKey kw <*> pString) kws puFlag (Option _ kws (OptArg f _) _) = pAny (\kw -> const (f Nothing) <$> pKey kw <|> f . Just <$ pKey kw <*> pString) kws pugFlags :: [Parser Token (Options -> Options)] pugFlags = map puFlag options pAnyFlag = pAny id pugFlags pSep :: Parser Token String pSep = pKey ":" <|> pKey "=" pFileClasses :: Parser Token [String] pFileClasses = pKey "with" *> (pCommas pString) <|> pSucceed [] pAGFileOption :: Parser Token AGFileOption pAGFileOption = (\f cl opt -> AGFileOption f cl (constructOptions opt)) <$> (pKey "file" *> pSep *> pString) <*> pFileClasses <*> (pKey "options" *> pSep *> pCommas pAnyFlag) pAGOptionsClass :: Parser Token AGOptionsClass pAGOptionsClass = (\c opt -> AGOptionsClass c (constructOptions opt)) <$> (pKey "class" *> pSep *> pString) <*> (pKey "options" *> pSep *> pCommas pAnyFlag) pAGFileOptions :: Parser Token AGFileOptions pAGFileOptions = pList pAGFileOption parserAG :: FilePath -> IO AGFileOptions parserAG fp = do s <- readFile fp parseIOAction action pAGFileOptions (scanner fp s) parserAG' :: FilePath -> IO (Either ParserError AGFileOptions) parserAG' fp = do s <- readFile fp let steps = parse pAGFileOptions (scanner fp s) let (Pair res _, mesg) = evalStepsMessages steps if null mesg then return $ Right res else do let err = foldr (++) [] $ map message2error mesg return (Left $ DefParserError err) message2error :: Message Token (Maybe Token) -> String message2error (Msg e p a) = "Expecting: " ++ (show e) ++ " at " ++ action where action = case a of Insert s -> " Inserting: " ++ (show s) Delete s -> " Deleting: " ++ (show s) Other s -> s liftParse p text = parseIOAction action p (scanner text text) parseOptionAG :: String -> IO AGFileOption parseOptionAG = liftParse pAGFileOption parseClassAG :: String -> IO AGOptionsClass parseClassAG = liftParse pAGOptionsClass scanner :: String -> String -> [Token] scanner fn s = scan kwtxt kwotxt sctxt octxt (Pos 0 0 fn) s action :: (Eq s, Show s, Show p) => Message s p -> IO () action m = hPutStr stderr (show m) test :: (Show a) => Parser Token a -> [Token] -> IO () test p inp = do r <- parseIOAction action p inp print r parseIOAction :: (Symbol s, InputState inp s p) => (Message s p -> IO ()) -> AnaParser inp Pair s p a -> inp -> IO a parseIOAction showMessage p inp = do (Pair v final) <- evalStepsIOAction showMessage (parse p inp) final `seq` return v -- in order to force the trailing error messages to be printed evalStepsIOAction :: (Message s p -> IO ()) -> Steps b s p -> IO b evalStepsIOAction showMessage = evalStepsIOAction' showMessage (-1) evalStepsIOAction' :: (Message s p -> IO ()) -> Int -> Steps b s p -> IO b evalStepsIOAction' showMessage n (steps :: Steps b s p) = eval n steps where eval :: Int -> Steps a s p -> IO a eval 0 steps = return (evalSteps steps) eval n steps = case steps of OkVal v rest -> do arg <- unsafeInterleaveIO (eval n rest) return (v arg) Ok rest -> eval n rest Cost _ rest -> eval n rest StRepair _ msg rest -> do showMessage msg eval (n-1) rest Best _ rest _ -> eval n rest NoMoreSteps v -> return v evalStepsMessages :: (Eq s, Show s, Show p) => Steps a s p -> (a,[Message s p]) evalStepsMessages steps = case steps of OkVal v rest -> let (arg, ms) = evalStepsMessages rest in (v arg, ms) Ok rest -> evalStepsMessages rest Cost _ rest -> evalStepsMessages rest StRepair _ msg rest -> let (v, ms) = evalStepsMessages rest in (v, msg:ms) Best _ rest _ -> evalStepsMessages rest NoMoreSteps v -> (v,[])