module Language.Haskell.Tools.BackendGHC.Names where
import Control.Monad.Reader ((=<<), asks)
import Data.Char (isAlphaNum)
import Data.List.Split (splitOn)
import FastString as GHC (FastString, unpackFS)
import HsSyn as GHC
import Name as GHC (isSymOcc, occNameString)
import qualified Name as GHC (Name)
import OccName as GHC (HasOccName)
import RdrName as GHC (RdrName)
import SrcLoc as GHC
import Language.Haskell.Tools.AST (Ann(..), AnnListG, RangeStage, Dom)
import qualified Language.Haskell.Tools.AST as AST
import Language.Haskell.Tools.BackendGHC.GHCUtils
import Language.Haskell.Tools.BackendGHC.Monad
import Language.Haskell.Tools.BackendGHC.Utils
trfOperator :: TransformName n r => Located n -> Trf (Ann AST.UOperator (Dom r) RangeStage)
trfOperator = trfLocNoSema trfOperator'
trfOperator' :: TransformName n r => n -> Trf (AST.UOperator (Dom r) RangeStage)
trfOperator' n
| isSymOcc (occName n) = AST.UNormalOp <$> trfQualifiedNameFocus True n
| otherwise = AST.UBacktickOp <$> trfQualifiedNameFocus True n
trfName :: TransformName n r => Located n -> Trf (Ann AST.UName (Dom r) RangeStage)
trfName = trfLocNoSema trfName'
trfName' :: TransformName n r => n -> Trf (AST.UName (Dom r) RangeStage)
trfName' n
| isSymOcc (occName n) = (if isSpecKind then AST.UNormalName else AST.UParenName) <$> trfQualifiedNameFocus isSpecKind n
| otherwise = AST.UNormalName <$> trfQualifiedNameFocus False n
where
isSpecKind = occNameString (occName n) `elem` ["*", "#", "?", "??"]
trfAmbiguousFieldName :: TransformName n r => Located (AmbiguousFieldOcc n) -> Trf (Ann AST.UName (Dom r) RangeStage)
trfAmbiguousFieldName (L l af) = trfAmbiguousFieldName' l af
trfAmbiguousFieldName' :: forall n r . TransformName n r => SrcSpan -> AmbiguousFieldOcc n -> Trf (Ann AST.UName (Dom r) RangeStage)
trfAmbiguousFieldName' l (Unambiguous (L _ rdr) pr) = annLocNoSema (pure l) $ trfName' (unpackPostRn @n rdr pr)
trfAmbiguousFieldName' _ (Ambiguous (L l rdr) _)
= annLocNoSema (pure l)
$ (if (isSymOcc (occName rdr)) then AST.UParenName else AST.UNormalName)
<$> (annLoc (createAmbigousNameInfo rdr l) (pure l) $ AST.nameFromList <$> trfNameStr (isSymOcc (occName rdr)) (rdrNameStr rdr))
trfAmbiguousOperator' :: forall n r . TransformName n r => SrcSpan -> AmbiguousFieldOcc n -> Trf (Ann AST.UOperator (Dom r) RangeStage)
trfAmbiguousOperator' l (Unambiguous (L _ rdr) pr) = annLocNoSema (pure l) $ trfOperator' (unpackPostRn @n rdr pr)
trfAmbiguousFieldOperator' _ (Ambiguous (L l rdr) _)
= annLocNoSema (pure l)
$ (if (isSymOcc (occName rdr)) then AST.UNormalOp else AST.UBacktickOp)
<$> (annLoc (createAmbigousNameInfo rdr l) (pure l) $ AST.nameFromList <$> trfOperatorStr (not $ isSymOcc (occName rdr)) (rdrNameStr rdr))
class (DataId n, Eq n, GHCName n, FromGHCName n, NameOrRdrName n ~ n, HasOccName n) => TransformableName n where
correctNameString :: n -> Trf String
transformSplice :: HsSplice RdrName -> Trf (HsSplice n)
instance TransformableName RdrName where
correctNameString = pure . rdrNameStr
transformSplice = pure
instance TransformableName GHC.Name where
correctNameString n = getOriginalName (rdrName n)
transformSplice = rdrSplice
class (TransformableName name, HsHasName name, TransformableName res, HsHasName res, GHCName res)
=> TransformName name res where
transformName :: name -> res
instance (n ~ r, TransformableName n, HsHasName n) => TransformName n r where
transformName = id
instance (TransformableName res, GHCName res, HsHasName res) => TransformName GHC.Name res where
transformName = fromGHCName
trfNameText :: String -> Trf (Ann AST.UName (Dom r) RangeStage)
trfNameText str
= annContNoSema (AST.UNormalName <$> annLoc (createImplicitNameInfo str) (asks contRange) (AST.nameFromList <$> trfNameStr (isOperatorStr str) str))
trfImplicitName :: HsIPName -> Trf (Ann AST.UName (Dom r) RangeStage)
trfImplicitName (HsIPName fs)
= let nstr = unpackFS fs
in do rng <- asks contRange
let rng' = mkSrcSpan (updateCol (+1) (srcSpanStart rng)) (srcSpanEnd rng)
annContNoSema (AST.UImplicitName <$> annLoc (createImplicitNameInfo nstr) (pure rng')
(AST.nameFromList <$> trfNameStr (isOperatorStr nstr) nstr))
isOperatorStr :: String -> Bool
isOperatorStr = any (not . isAlphaNum)
trfQualifiedName :: TransformName n r => Bool -> Located n -> Trf (Ann AST.UQualifiedName (Dom r) RangeStage)
trfQualifiedName isOperator (L l n) = focusOn l $ trfQualifiedNameFocus isOperator n
trfQualifiedNameFocus :: TransformName n r => Bool -> n -> Trf (Ann AST.UQualifiedName (Dom r) RangeStage)
trfQualifiedNameFocus isOperator n
= do rng <- asks contRange
let rng' = if isOperator == isSymOcc (occName n) then rng
else mkSrcSpan (updateCol (+1) (srcSpanStart rng)) (updateCol (subtract 1) (srcSpanEnd rng))
annLoc (createNameInfo (transformName n)) (pure rng') (trfQualifiedName' n)
trfQualifiedName' :: TransformName n r => n -> Trf (AST.UQualifiedName (Dom r) RangeStage)
trfQualifiedName' n = AST.nameFromList <$> ((if isSymOcc (occName n) then trfOperatorStr else trfNameStr) False =<< correctNameString n)
trfOperatorStr :: Bool -> String -> Trf (AnnListG AST.UNamePart (Dom r) RangeStage)
trfOperatorStr isInParen str = do rng <- correctSpan <$> asks contRange
makeList "." (pure $ srcSpanStart rng)
(pure [Ann (noSemaInfo $ AST.NodeSpan rng) (AST.UNamePart str)])
where correctSpan sp = if isInParen then mkSrcSpan (updateCol (+1) (srcSpanStart sp))
(updateCol (subtract 1) (srcSpanEnd sp))
else sp
trfNameStr :: Bool -> String -> Trf (AnnListG AST.UNamePart (Dom r) RangeStage)
trfNameStr isInBackticks str = makeList "." atTheStart (trfNameStr' str . correct <$> atTheStart)
where correct = if isInBackticks then updateCol (+1) else id
trfNameStr' :: String -> SrcLoc -> [Ann AST.UNamePart (Dom r) RangeStage]
trfNameStr' str startLoc = fst $
foldl (\(r,loc) np -> let nextLoc = advanceAllSrcLoc loc np
in ( r ++ [Ann (noSemaInfo $ AST.NodeSpan (mkSrcSpan loc nextLoc)) (AST.UNamePart np)], advanceAllSrcLoc nextLoc "." ) )
([], startLoc) (splitOn "." str)
where
advanceAllSrcLoc :: SrcLoc -> String -> SrcLoc
advanceAllSrcLoc (RealSrcLoc rl) str = RealSrcLoc $ foldl advanceSrcLoc rl str
advanceAllSrcLoc oth _ = oth
trfFastString :: Located FastString -> Trf (Ann AST.UStringNode (Dom r) RangeStage)
trfFastString = trfLocNoSema $ pure . AST.UStringNode . unpackFS