{-# LANGUAGE RecordWildCards #-}
module Overloaded.Plugin.IdiomBrackets where
import Data.List (foldl')
import Data.List.NonEmpty (NonEmpty (..))
import GHC.Compat.Expr
import Overloaded.Plugin.Rewrite
import Overloaded.Plugin.Names
transformIdiomBrackets
:: Names
-> LHsExpr GhcRn
-> Rewrite (LHsExpr GhcRn)
transformIdiomBrackets names (L _l (HsRnBracketOut _ (ExpBr _ e) _))
= Rewrite (transformIdiomBrackets' names e)
transformIdiomBrackets _ _ = NoRewrite
transformIdiomBrackets'
:: Names
-> LHsExpr GhcRn
-> LHsExpr GhcRn
transformIdiomBrackets' names expr@(L _e OpApp {}) = do
let bt = matchOp expr
let result = idiomBT names bt
result
transformIdiomBrackets' names expr = do
let (f :| args) = matchApp expr
let f' = pureExpr names f
let result = foldl' (applyExpr names) f' args
result
matchApp :: LHsExpr p -> NonEmpty (LHsExpr p)
matchApp (L _ (HsApp _ f x)) = neSnoc (matchApp f) x
matchApp e = pure e
neSnoc :: NonEmpty a -> a -> NonEmpty a
neSnoc (x :| xs) y = x :| xs ++ [y]
matchOp :: LHsExpr p -> BT (LHsExpr p)
matchOp (L _ (OpApp _ lhs op rhs)) = Branch (matchOp lhs) op (matchOp rhs)
matchOp x = Leaf x
data BT a = Leaf a | Branch (BT a) a (BT a)
idiomBT :: Names -> BT (LHsExpr GhcRn) -> LHsExpr GhcRn
idiomBT _ (Leaf x) = x
idiomBT names (Branch lhs op rhs) = fmapExpr names op (idiomBT names lhs) `ap` idiomBT names rhs
where
ap = apExpr names
applyExpr :: Names -> LHsExpr GhcRn -> LHsExpr GhcRn -> LHsExpr GhcRn
applyExpr names f (L _ (HsPar _ (L _ (HsApp _ (L _ (HsVar _ (L _ voidName'))) x))))
| voidName' == voidName names = birdExpr names f x
applyExpr names f x = apExpr names f x
apExpr :: Names -> LHsExpr GhcRn -> LHsExpr GhcRn -> LHsExpr GhcRn
apExpr Names {..} f x = hsApps l' (hsVar l' apName) [f, x] where
l' = noSrcSpan
birdExpr :: Names -> LHsExpr GhcRn -> LHsExpr GhcRn -> LHsExpr GhcRn
birdExpr Names {..} f x = hsApps l' (hsVar l' birdName) [f, x] where
l' = noSrcSpan
fmapExpr :: Names -> LHsExpr GhcRn -> LHsExpr GhcRn -> LHsExpr GhcRn
fmapExpr Names {..} f x = hsApps l' (hsVar l' fmapName) [f, x] where
l' = noSrcSpan
pureExpr :: Names -> LHsExpr GhcRn -> LHsExpr GhcRn
pureExpr Names {..} x = hsApps l' (hsVar l' pureName) [x] where
l' = noSrcSpan