{-# LANGUAGE CPP #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
module Refact.Fixity (applyFixities) where
import SrcLoc
import Refact.Utils
import BasicTypes (Fixity(..), defaultFixity, compareFixity, negateFixity, FixityDirection(..), SourceText(..))
#if __GLASGOW_HASKELL__ >= 810
import GHC.Hs
#else
import HsExpr
import HsExtension hiding (noExt)
#endif
import ApiAnnotation
import RdrName
import OccName
import Data.Generics hiding (Fixity)
import Data.List
import Data.Maybe
import Language.Haskell.GHC.ExactPrint.Types hiding (GhcPs, GhcTc, GhcRn)
import Control.Monad.Trans.State
import qualified Data.Map as Map
import Data.Tuple
applyFixities :: Anns -> Module -> (Anns, Module)
applyFixities as m = let (as', m') = swap $ runState (everywhereM (mkM expFix) m) as
in (as', m')
expFix :: LHsExpr GhcPs -> M (LHsExpr GhcPs)
expFix (L loc (OpApp _ l op r)) =
mkOpAppRn baseFixities loc l op (findFixity baseFixities op) r
expFix e = return e
getIdent :: Expr -> String
getIdent (unLoc -> HsVar _ (L _ n)) = occNameString . rdrNameOcc $ n
getIdent _ = error "Must be HsVar"
moveDelta :: Annotation -> AnnKey -> AnnKey -> M ()
moveDelta oldAnn oldKey newKey = do
let newAnnsDP | Just dp <- find ((== G AnnMinus) . fst) (annsDP oldAnn) = [dp]
| otherwise = []
modify . Map.insert newKey $ annNone
{ annEntryDelta = annEntryDelta oldAnn
, annPriorComments = annPriorComments oldAnn
, annsDP = newAnnsDP
}
modify $ Map.adjust (\a -> a { annEntryDelta = DP (0,0), annPriorComments = []}) oldKey
mkOpAppRn ::
[(String, Fixity)]
-> SrcSpan
-> LHsExpr GhcPs
-> LHsExpr GhcPs -> Fixity
-> LHsExpr GhcPs
-> M (LHsExpr GhcPs)
mkOpAppRn fs loc e1@(L _ (OpApp x1 e11 op1 e12)) op2 fix2 e2
| nofix_error
= return $ L loc (OpApp noExt e1 op2 e2)
| associate_right = do
let oldKey = mkAnnKey e12
oldAnn <- gets $ Map.findWithDefault annNone oldKey
new_e <- mkOpAppRn fs loc' e12 op2 fix2 e2
let newKey = mkAnnKey new_e
moveDelta oldAnn oldKey newKey
return $ L loc (OpApp x1 e11 op1 new_e)
where
loc'= combineLocs e12 e2
fix1 = findFixity fs op1
(nofix_error, associate_right) = compareFixity fix1 fix2
mkOpAppRn fs loc e1@(L _ (NegApp _ neg_arg neg_name)) op2 fix2 e2
| nofix_error
= return (L loc (OpApp noExt e1 op2 e2))
| associate_right
= do
let oldKey = mkAnnKey neg_arg
oldAnn <- gets $ Map.findWithDefault annNone oldKey
new_e <- mkOpAppRn fs loc' neg_arg op2 fix2 e2
let newKey = mkAnnKey new_e
moveDelta oldAnn oldKey newKey
let res = L loc (NegApp noExt new_e neg_name)
key = mkAnnKey res
ak = AnnKey loc (CN "OpApp")
opAnn <- gets (fromMaybe annNone . Map.lookup ak)
negAnns <- gets (fromMaybe annNone . Map.lookup (mkAnnKey e1))
modify (Map.insert key (annNone { annEntryDelta = annEntryDelta opAnn, annsDP = annsDP negAnns }))
modify (Map.delete (mkAnnKey e1))
return res
where
loc' = combineLocs neg_arg e2
(nofix_error, associate_right) = compareFixity negateFixity fix2
mkOpAppRn _ loc e1 op1 fix1 e2@(L _ NegApp{})
| not associate_right
= return $ L loc (OpApp noExt e1 op1 e2)
where
(_, associate_right) = compareFixity fix1 negateFixity
mkOpAppRn _ loc e1 op _fix e2
= return $ L loc (OpApp noExt e1 op e2)
findFixity :: [(String, Fixity)] -> Expr -> Fixity
findFixity fs r = askFix fs (getIdent r)
askFix :: [(String, Fixity)] -> String -> Fixity
askFix xs = \k -> lookupWithDefault defaultFixity k xs
where
lookupWithDefault def_v k mp1 = fromMaybe def_v $ lookup k mp1
preludeFixities :: [(String, Fixity)]
preludeFixities = concat
[infixr_ 9 ["."]
,infixl_ 9 ["!!"]
,infixr_ 8 ["^","^^","**"]
,infixl_ 7 ["*","/","quot","rem","div","mod",":%","%"]
,infixl_ 6 ["+","-"]
,infixr_ 5 [":","++"]
,infix_ 4 ["==","/=","<","<=",">=",">","elem","notElem"]
,infixr_ 3 ["&&"]
,infixr_ 2 ["||"]
,infixl_ 1 [">>",">>="]
,infixr_ 1 ["=<<"]
,infixr_ 0 ["$","$!","seq"]
]
baseFixities :: [(String, Fixity)]
baseFixities = preludeFixities ++ concat
[infixl_ 9 ["!","//","!:"]
,infixl_ 8 ["shift","rotate","shiftL","shiftR","rotateL","rotateR"]
,infixl_ 7 [".&."]
,infixl_ 6 ["xor"]
,infix_ 6 [":+"]
,infixl_ 5 [".|."]
,infixr_ 5 ["+:+","<++","<+>"]
,infix_ 5 ["\\\\"]
,infixl_ 4 ["<$>","<$","<*>","<*","*>","<**>"]
,infix_ 4 ["elemP","notElemP"]
,infixl_ 3 ["<|>"]
,infixr_ 3 ["&&&","***"]
,infixr_ 2 ["+++","|||"]
,infixr_ 1 ["<=<",">=>",">>>","<<<","^<<","<<^","^>>",">>^"]
,infixl_ 0 ["on"]
,infixr_ 0 ["par","pseq"]
]
infixr_, infixl_, infix_ :: Int -> [String] -> [(String,Fixity)]
infixr_ = fixity InfixR
infixl_ = fixity InfixL
infix_ = fixity InfixN
fixity :: FixityDirection -> Int -> [String] -> [(String, Fixity)]
fixity a p = map (,Fixity (SourceText "") p a)