overloaded-0.3: src/Overloaded/Plugin/LocalDo.hs
{-# LANGUAGE CPP #-}
module Overloaded.Plugin.LocalDo where
import qualified Data.Generics as SYB
import qualified GHC.Compat.All as GHC
import GHC.Compat.Expr
#if MIN_VERSION_ghc(9,0,0)
import qualified GHC.Plugins as Plugins
#else
import qualified GhcPlugins as Plugins
#endif
import Overloaded.Plugin.Diagnostics
import Overloaded.Plugin.Names
import Overloaded.Plugin.Rewrite
#if MIN_VERSION_ghc(9,0,0)
#define _bufspan _
#else
#define _bufspan
#endif
transformDo
:: Names
-> LHsExpr GhcRn
-> Rewrite (LHsExpr GhcRn)
transformDo names (L l (OpApp _ (L (RealSrcSpan l1 _bufspan) (HsVar _ (L _ doName)))
(L (RealSrcSpan l2 _bufspan) (HsVar _ (L _ compName')))
(L (RealSrcSpan l3 _bufspan)
#if MIN_VERSION_ghc(9,0,0)
(HsDo _ (DoExpr Nothing) (L _ stmts))
#else
(HsDo _ DoExpr (L _ stmts))
#endif
)))
| spanNextTo l1 l2
, spanNextTo l2 l3
, compName' == composeName names
= case transformDo' names doName l stmts of
Right x -> Rewrite x
Left err -> Error err
transformDo _ _ = NoRewrite
transformDo' :: Names -> GHC.Name -> SrcSpan -> [ExprLStmt GhcRn] -> Either (GHC.DynFlags -> IO ()) (LHsExpr GhcRn)
transformDo' _names _doName l [] = Left $ \dflags ->
putError dflags l $ GHC.text "Empty do"
#if MIN_VERSION_ghc(9,0,0)
transformDo' names doName _ (L l (BindStmt _ pat body) : next) = do
#else
transformDo' names doName _ (L l (BindStmt _ pat body _ _) : next) = do
#endif
next' <- transformDo' names doName l next
return $ hsApps l bind [ body, kont next' ]
where
bind = hsTyApp l (hsVar l doName) (hsTyVar l (doBindName names))
kont next' = L l $ HsLam noExtField MG
{ mg_ext = noExtField
, mg_alts = L l $ pure $ L l Match
{ m_ext = noExtField
, m_ctxt = LambdaExpr
, m_pats = [pat]
, m_grhss = GRHSs
{ grhssExt = noExtField
, grhssGRHSs = [ L noSrcSpan $ GRHS noExtField [] $ next' ]
, grhssLocalBinds = L noSrcSpan $ EmptyLocalBinds noExtField
}
}
, mg_origin = Plugins.Generated
}
transformDo' names doName _ (L l (BodyStmt _ body _ _) : next) = do
next' <- transformDo' names doName l next
return $ hsApps l then_ [ body, next' ]
where
then_ = hsTyApp l (hsVar l doName) (hsTyVar l (doThenName names))
transformDo' _ _ _ [L _ (LastStmt _ body _ _)] = return body
transformDo' _ _ _ (L l stmt : _) = Left $ \dflags ->
putError dflags l $ GHC.text "Unsupported statement in do"
GHC.$$ GHC.ppr stmt
GHC.$$ GHC.text (SYB.gshow stmt)
spanNextTo :: RealSrcSpan -> RealSrcSpan -> Bool
spanNextTo x y
= srcSpanStartLine y == srcSpanEndLine x
&& srcSpanStartCol y == srcSpanEndCol x