{-# LANGUAGE RankNTypes #-}
module Retrie.Fixity
( FixityEnv
, mkFixityEnv
, lookupOp
, lookupOpRdrName
, Fixity(..)
, FixityDirection(..)
, defaultFixityEnv
, extendFixityEnv
, ppFixityEnv
) where
import qualified Language.Haskell.Exts as HSE
import Data.Default
import Retrie.GHC
newtype FixityEnv = FixityEnv
{ unFixityEnv :: FastStringEnv (FastString, Fixity) }
instance Default FixityEnv where
def = defaultFixityEnv
defaultFixityEnv :: FixityEnv
defaultFixityEnv = mkFixityEnv HSE.baseFixities
instance Semigroup FixityEnv where
(<>) = mappend
instance Monoid FixityEnv where
mempty = mkFixityEnv []
mappend (FixityEnv e1) (FixityEnv e2) = FixityEnv (plusFsEnv e1 e2)
lookupOp :: LHsExpr GhcPs -> FixityEnv -> Fixity
lookupOp (L _ e) | Just n <- varRdrName e = lookupOpRdrName n
lookupOp _ = error "lookupOp: called with non-variable!"
lookupOpRdrName :: Located RdrName -> FixityEnv -> Fixity
lookupOpRdrName (L _ n) (FixityEnv env) =
maybe defaultFixity snd $ lookupFsEnv env (occNameFS $ occName n)
mkFixityEnv :: [HSE.Fixity] -> FixityEnv
mkFixityEnv = FixityEnv . mkFsEnv . map hseToGHC
extendFixityEnv :: [(FastString, Fixity)] -> FixityEnv -> FixityEnv
extendFixityEnv l (FixityEnv env) =
FixityEnv $ extendFsEnvList env [ (fs, p) | p@(fs,_) <- l ]
ppFixityEnv :: FixityEnv -> String
ppFixityEnv = unlines . map ppFixity . eltsUFM . unFixityEnv
where
ppFixity (fs, Fixity _ p d) = unwords
[ case d of
InfixN -> "infix"
InfixL -> "infixl"
InfixR -> "infixr"
, show p
, unpackFS fs
]
hseToGHC :: HSE.Fixity -> (FastString, (FastString, Fixity))
hseToGHC (HSE.Fixity assoc p nm) = (fs, (fs, Fixity (SourceText nm') p (dir assoc)))
where
dir (HSE.AssocNone _) = InfixN
dir (HSE.AssocLeft _) = InfixL
dir (HSE.AssocRight _) = InfixR
nm' = case nm of
HSE.Qual _ _ n -> nameStr n
HSE.UnQual _ n -> nameStr n
_ -> "SpecialCon"
fs = mkFastString nm'
nameStr (HSE.Ident _ s) = s
nameStr (HSE.Symbol _ s) = s