module Text.Happy.Quote ( parseHappy , parseHappyInfo , compileHappy , happy , HappyStk(..) , HappyInfo , happyWarn ) where import Text.Happy(runHappy, HappyInfo(..)) import Text.Happy.HappyTemplate import Language.Haskell.TH.Quote import Language.Haskell.TH import Language.Haskell.Meta import Control.Monad(when) import System.IO(hPutStrLn,stderr) -- Runtime (The infixr declaration can not be spliced by TH) data HappyStk a = HappyStk a (HappyStk a) infixr 9 `HappyStk` type Happy = String compileHappy :: Happy -> Q [Dec] compileHappy = return . either error id . parseDecs happy :: QuasiQuoter happy = QuasiQuoter (happyToExp . parseHappyInfo) (error "happy: pattern quoting is not supported") parseHappy :: String -> Happy parseHappy = fst . parseHappyInfo parseHappyInfo :: String -> (Happy,HappyInfo) parseHappyInfo s = (subst old "" $ code ++ "\n" ++ happyTemplate, info) where (code,info) = either error id $ runHappy [] s old = unlines ["infixr 9 `HappyStk`", "data HappyStk a = HappyStk a (HappyStk a)"] happyWarn :: HappyInfo -> Q () happyWarn i = do loc <- location let warnMsg msg = do let (row,col) = loc_start loc (file) = loc_filename loc runIO $ hPutStrLn stderr $ file ++ ":"++show row++":"++show col++":" runIO $ hPutStrLn stderr $ " " ++ msg when (sr i > 0) $ warnMsg $ show (sr i) ++ "Warning: shift/reduce conflicts" when (rr i > 0) $ warnMsg $ show (rr i) ++ "Warning: reduce/reduce conflicts" happyToExp (code,info) = happyWarn info >> litE (StringL code) -- optIO (not (null unused_rules)) -- (hPutStrLn stderr ("unused rules: " ++ show (length unused_rules))) >> -- optIO (not (null unused_terminals)) -- (hPutStrLn stderr ("unused terminals: " ++ show (length unused_terminals))) >> -- This is some really bad code but it works for this purpose. subst _ _ [ ] = [] subst from to xs@(a:as) = if isPrefixOf from xs then to ++ drop (length from) xs else a : subst from to as where isPrefixOf as bs = and $ zipWith (==) as bs