module Language.Haskell.Tools.AST.FromGHC.Binds where
import Control.Monad.Reader
import SrcLoc as GHC
import RdrName as GHC
import HsBinds as GHC
import HsExpr as GHC
import BasicTypes as GHC
import ApiAnnotation as GHC
import Bag as GHC
import Outputable as GHC
import HsPat as GHC
import HsDecls as GHC
import HsTypes as GHC
import OccName as GHC
import Name as GHC
import BooleanFormula as GHC
import Data.List
import Language.Haskell.Tools.AST.FromGHC.Base
import Language.Haskell.Tools.AST.FromGHC.Exprs
import Language.Haskell.Tools.AST.FromGHC.Patterns
import Language.Haskell.Tools.AST.FromGHC.Types
import Language.Haskell.Tools.AST.FromGHC.Kinds
import Language.Haskell.Tools.AST.FromGHC.Monad
import Language.Haskell.Tools.AST.FromGHC.Utils
import Language.Haskell.Tools.AST.FromGHC.GHCUtils
import Language.Haskell.Tools.AST (Ann(..), AnnMaybe(..), AnnList(..), Dom, RangeStage)
import qualified Language.Haskell.Tools.AST as AST
trfBind :: TransformName n r => Located (HsBind n) -> Trf (Ann AST.ValueBind (Dom r) RangeStage)
trfBind = trfLocNoSema trfBind'
trfBind' :: TransformName n r => HsBind n -> Trf (AST.ValueBind (Dom r) RangeStage)
trfBind' (FunBind { fun_id = id, fun_matches = MG { mg_alts = unLoc -> [L matchLoc (Match { m_pats = [], m_grhss = GRHSs [L rhsLoc (GRHS [] expr)] (unLoc -> locals) })]} })
= AST.SimpleBind <$> copyAnnot AST.VarPat (define $ trfName id)
<*> addToScope locals (annLocNoSema (combineSrcSpans (getLoc expr) <$> tokenLoc AnnEqual) (AST.UnguardedRhs <$> trfExpr expr))
<*> addToScope locals (trfWhereLocalBinds locals)
trfBind' (FunBind id (MG (unLoc -> matches) _ _ _) _ _ _) = AST.FunBind <$> makeNonemptyIndentedList (mapM (trfMatch (unLoc id)) matches)
trfBind' (PatBind pat (GRHSs rhs (unLoc -> locals)) _ _ _) = AST.SimpleBind <$> trfPattern pat <*> trfRhss rhs <*> trfWhereLocalBinds locals
trfBind' (AbsBinds _ _ _ _ _) = error "AbsBinds are not allowed as an input to the conversion (they are generated by the type checker)"
trfBind' (PatSynBind _) = error "Pattern synonym bindings should be recognized on the declaration level"
trfMatch :: TransformName n r => n -> Located (Match n (LHsExpr n)) -> Trf (Ann AST.Match (Dom r) RangeStage)
trfMatch id = trfLocNoSema (trfMatch' id)
trfMatch' :: TransformName n r => n -> Match n (LHsExpr n) -> Trf (AST.Match (Dom r) RangeStage)
trfMatch' name (Match funid pats typ (GRHSs rhss (unLoc -> locBinds)))
= AST.Match <$> trfMatchLhs name funid pats
<*> addToScope pats (trfRhss rhss)
<*> addToScope pats (trfWhereLocalBinds locBinds)
trfMatchLhs :: TransformName n r => n -> MatchFixity n -> [LPat n] -> Trf (Ann AST.MatchLhs (Dom r) RangeStage)
trfMatchLhs name fb pats
= do implicitIdLoc <- mkSrcSpan <$> atTheStart <*> atTheStart
closeLoc <- srcSpanStart <$> (combineSrcSpans <$> tokenLoc AnnEqual <*> tokenLoc AnnVbar)
let (n, isInfix) = case fb of NonFunBindMatch -> (L implicitIdLoc name, False)
FunBindMatch n inf -> (n, inf)
args <- mapM trfPattern pats
annLocNoSema (mkSrcSpan <$> atTheStart <*> (pure closeLoc)) $
case (args, isInfix) of
(left:right:rest, True) -> AST.InfixLhs left <$> define (trfOperator n) <*> pure right <*> makeList " " (pure closeLoc) (pure rest)
_ -> AST.NormalLhs <$> define (trfName n) <*> makeList " " (pure closeLoc) (pure args)
trfRhss :: TransformName n r => [Located (GRHS n (LHsExpr n))] -> Trf (Ann AST.Rhs (Dom r) RangeStage)
trfRhss [unLoc -> GRHS [] body] = annLocNoSema (combineSrcSpans (getLoc body) <$> tokenBefore (srcSpanStart $ getLoc body) AnnEqual)
(AST.UnguardedRhs <$> trfExpr body)
trfRhss rhss = annLocNoSema (pure $ collectLocs rhss)
(AST.GuardedRhss . nonemptyAnnList <$> mapM trfGuardedRhs rhss)
trfGuardedRhs :: TransformName n r => Located (GRHS n (LHsExpr n)) -> Trf (Ann AST.GuardedRhs (Dom r) RangeStage)
trfGuardedRhs = trfLocNoSema $ \(GRHS guards body)
-> AST.GuardedRhs . nonemptyAnnList <$> trfScopedSequence trfRhsGuard guards <*> addToScope guards (trfExpr body)
trfRhsGuard :: TransformName n r => Located (Stmt n (LHsExpr n)) -> Trf (Ann AST.RhsGuard (Dom r) RangeStage)
trfRhsGuard = trfLocNoSema trfRhsGuard'
trfRhsGuard' :: TransformName n r => Stmt n (LHsExpr n) -> Trf (AST.RhsGuard (Dom r) RangeStage)
trfRhsGuard' (BindStmt pat body _ _ _) = AST.GuardBind <$> trfPattern pat <*> trfExpr body
trfRhsGuard' (BodyStmt body _ _ _) = AST.GuardCheck <$> trfExpr body
trfRhsGuard' (LetStmt (unLoc -> binds)) = AST.GuardLet <$> trfLocalBinds binds
trfWhereLocalBinds :: TransformName n r => HsLocalBinds n -> Trf (AnnMaybe AST.LocalBinds (Dom r) RangeStage)
trfWhereLocalBinds EmptyLocalBinds = nothing "" "" atTheEnd
trfWhereLocalBinds binds
= makeJust <$> annLocNoSema (combineSrcSpans (getBindLocs binds) <$> tokenLoc AnnWhere) (AST.LocalBinds <$> addToScope binds (trfLocalBinds binds))
getBindLocs :: HsLocalBinds n -> SrcSpan
getBindLocs (HsValBinds (ValBindsIn binds sigs)) = foldLocs $ map getLoc (bagToList binds) ++ map getLoc sigs
getBindLocs (HsValBinds (ValBindsOut binds sigs)) = foldLocs $ map getLoc (concatMap (bagToList . snd) binds) ++ map getLoc sigs
getBindLocs (HsIPBinds (IPBinds binds _)) = foldLocs $ map getLoc binds
trfLocalBinds :: TransformName n r => HsLocalBinds n -> Trf (AnnList AST.LocalBind (Dom r) RangeStage)
trfLocalBinds (HsValBinds (ValBindsIn binds sigs))
= makeIndentedList (after AnnWhere)
(orderDefs <$> ((++) <$> mapM (copyAnnot AST.LocalValBind . trfBind) (bagToList binds)
<*> mapM trfLocalSig sigs))
trfLocalBinds (HsValBinds (ValBindsOut binds sigs))
= makeIndentedList (after AnnWhere)
(orderDefs <$> ((++) <$> (concat <$> mapM (mapM (copyAnnot AST.LocalValBind . trfBind) . bagToList . snd) binds)
<*> mapM trfLocalSig sigs))
trfLocalBinds (HsIPBinds (IPBinds binds _))
= makeIndentedList (after AnnWhere) (mapM trfIpBind binds)
trfIpBind :: TransformName n r => Located (IPBind n) -> Trf (Ann AST.LocalBind (Dom r) RangeStage)
trfIpBind = trfLocNoSema $ \case
IPBind (Left (L l ipname)) expr -> AST.LocalValBind <$> (annContNoSema $ AST.SimpleBind <$> focusOn l (annContNoSema (AST.VarPat <$> define (trfImplicitName ipname)))
<*> annFromNoSema AnnEqual (AST.UnguardedRhs <$> trfExpr expr)
<*> nothing " " "" atTheEnd)
trfLocalSig :: TransformName n r => Located (Sig n) -> Trf (Ann AST.LocalBind (Dom r) RangeStage)
trfLocalSig = trfLocNoSema $ \case
ts@(TypeSig {}) -> AST.LocalSignature <$> annContNoSema (trfTypeSig' ts)
(FixSig fs) -> AST.LocalFixity <$> annContNoSema (trfFixitySig fs)
trfTypeSig :: TransformName n r => Located (Sig n) -> Trf (Ann AST.TypeSignature (Dom r) RangeStage)
trfTypeSig = trfLocNoSema trfTypeSig'
trfTypeSig' :: TransformName n r => Sig n -> Trf (AST.TypeSignature (Dom r) RangeStage)
trfTypeSig' (TypeSig names typ)
= defineTypeVars $ AST.TypeSignature <$> makeNonemptyList ", " (mapM trfName names) <*> trfType (hswc_body $ hsib_body typ)
trfFixitySig :: TransformName n r => FixitySig n -> Trf (AST.FixitySignature (Dom r) RangeStage)
trfFixitySig (FixitySig names (Fixity _ prec dir))
= AST.FixitySignature <$> transformDir dir
<*> annLocNoSema (tokenLoc AnnVal) (pure $ AST.Precedence prec)
<*> (nonemptyAnnList . nub <$> mapM trfOperator names)
where transformDir InfixL = directionChar (pure AST.AssocLeft)
transformDir InfixR = directionChar (pure AST.AssocRight)
transformDir InfixN = annLocNoSema (srcLocSpan . srcSpanEnd <$> tokenLoc AnnInfix) (pure AST.AssocNone)
directionChar = annLocNoSema ((\l -> mkSrcSpan (updateCol (subtract 1) l) l) . srcSpanEnd <$> tokenLoc AnnInfix)
trfRewriteRule :: TransformName n r => Located (RuleDecl n) -> Trf (Ann AST.Rule (Dom r) RangeStage)
trfRewriteRule = trfLocNoSema $ \(HsRule (L nameLoc (_, ruleName)) act bndrs left _ right _) ->
AST.Rule <$> trfFastString (L nameLoc ruleName)
<*> trfPhase (before AnnForall) act
<*> makeNonemptyList " " (mapM trfRuleBndr bndrs)
<*> trfExpr left
<*> trfExpr right
trfRuleBndr :: TransformName n r => Located (RuleBndr n) -> Trf (Ann AST.TyVar (Dom r) RangeStage)
trfRuleBndr = trfLocNoSema $ \case (RuleBndr n) -> AST.TyVarDecl <$> trfName n <*> nothing " " "" atTheEnd
(RuleBndrSig n k) -> AST.TyVarDecl <$> trfName n <*> (makeJust <$> (trfKindSig' (hswc_body $ hsib_body k)))
trfMinimalFormula :: TransformName n r => Located (BooleanFormula (Located n)) -> Trf (Ann AST.MinimalFormula (Dom r) RangeStage)
trfMinimalFormula = trfLocNoSema trfMinimalFormula'
trfMinimalFormula' :: TransformName n r => BooleanFormula (Located n) -> Trf (AST.MinimalFormula (Dom r) RangeStage)
trfMinimalFormula' (Var name) = AST.MinimalName <$> trfName name
trfMinimalFormula' (And formulas) = AST.MinimalAnd <$> trfAnnList " & " trfMinimalFormula' formulas
trfMinimalFormula' (Or formulas) = AST.MinimalOr <$> trfAnnList " | " trfMinimalFormula' formulas
trfMinimalFormula' (Parens formula) = AST.MinimalParen <$> trfMinimalFormula formula