{-# LANGUAGE TemplateHaskell #-} -- | -- Module : Data.Binding.Hobbits.QQ -- Copyright : (c) 2011 Edwin Westbrook, Nicolas Frisby, and Paul Brauner -- -- License : BSD3 -- -- Maintainer : emw4@rice.edu -- Stability : experimental -- Portability : GHC -- -- Defines a quasi-quoter for writing patterns that match the bodies -- of 'Mb' multi-bindings. Uses the -- "Data.Binding.Hobbits.PatternParser" module, and thus only supports -- the pattern forms listed there. If @P@ is a (supported) Haskell -- pattern, then @[nuQQ| P ]@ defines a pattern that will match an -- multi-binding whose body matches @P@. Any variables matched by @P@ -- will remain inside the binding; thus, for example, in the pattern -- @[nuQQ| x |]@, @x@ matches the entire multi-binding. -- -- Examples: -- -- > case (nu Left) of [nuQQ| Left x |] -> x == nu id -- module Data.Binding.Hobbits.QQ (nuQQ) where import Data.Binding.Hobbits.Internal (Mb(..)) import Data.Binding.Hobbits.PatternParser (parsePattern) import Language.Haskell.TH.Syntax as TH import Language.Haskell.TH.Quote import Control.DeepSeq import qualified Control.Exception as CE import qualified Data.Generics as SYB ------------------------------------------------------------ -- matching under binders using a quasi-quoter ------------------------------------------------------------ hobbitNamesPattVar n = mkName $ "hobbit$$names" ++ (show n) -- internPattVars replaces all subterms (VarP "x") with (MkMb ln -> VarP "x") internPattVars :: TH.Name -> TH.Name -> Pat -> Pat internPattVars mb ln = SYB.everywhere (SYB.mkT wrapVars) where mkView p = ViewP (InfixE (Just $ VarE 'same_ctx `AppE` VarE mb) (VarE '(.)) (Just $ ConE 'MkMb `AppE` VarE ln)) p wrapVars p @ (VarP _) = mkView p wrapVars (AsP v p) = mkView (AsP v (ConP 'MkMb [WildP, p])) wrapVars p = p syb_rnf :: SYB.Data a => a -> () syb_rnf = (`seq` ()) . rnf . SYB.gmapQ syb_rnf same_ctx :: Mb ctx a -> Mb ctx b -> Mb ctx b same_ctx _ x = x nuQQPatt :: String -> Q Pat nuQQPatt str = do mb <- newName "mb" ln <- newName "bs" pat <- runIO $ CE.evaluate (let x = parsePattern str in syb_rnf x `seq` x) `catch` \err -> (error $ "error parsing string |" ++ str ++ "|: " ++ show err) return $ AsP mb $ ConP 'MkMb [VarP ln, internPattVars mb ln pat] nuQQ = QuasiQuoter (error "nuQQ Exp") nuQQPatt (error "nuQQ Type") (error "nuQQ Decs")