packages feed

hindent-6.3.0: src/HIndent/Ast/Expression/Splice.hs

{-# LANGUAGE CPP #-}

module HIndent.Ast.Expression.Splice
  ( Splice
  , mkSplice
  , mkTypedSplice
  ) where

import qualified GHC.Data.FastString as GHC
import {-# SOURCE #-} HIndent.Ast.Expression (Expression, mkExpression)
import HIndent.Ast.Name.Prefix
import HIndent.Ast.NodeComments
import HIndent.Ast.WithComments (WithComments, fromGenLocated)
import qualified HIndent.GhcLibParserWrapper.GHC.Hs as GHC
import {-# SOURCE #-} HIndent.Pretty
import HIndent.Pretty.Combinators
import HIndent.Pretty.NodeComments
#if MIN_VERSION_ghc_lib_parser(9, 6, 1)
import qualified GHC.Types.SrcLoc as GHC
#endif
data Splice
  = Typed (WithComments Expression)
  | UntypedDollar (WithComments Expression)
  | UntypedBare (WithComments Expression)
  | QuasiQuote PrefixName GHC.FastString

instance CommentExtraction Splice where
  nodeComments (Typed expr) = nodeComments expr
  nodeComments (UntypedDollar expr) = nodeComments expr
  nodeComments (UntypedBare expr) = nodeComments expr
  nodeComments QuasiQuote {} = NodeComments [] [] []

instance Pretty Splice where
  pretty' (Typed x) = string "$$" >> pretty x
  pretty' (UntypedDollar x) = string "$" >> pretty x
  pretty' (UntypedBare x) = pretty x
  pretty' (QuasiQuote l r) =
    brackets $ do
      pretty l
      wrapWithBars
        $ indentedWithFixedLevel 0
        $ sequence_
        $ printers [] ""
        $ GHC.unpackFS r
    where
      printers ps s [] = reverse (string (reverse s) : ps)
      printers ps s ('\n':xs) =
        printers (newline : string (reverse s) : ps) "" xs
      printers ps s (x:xs) = printers ps (x : s) xs
#if MIN_VERSION_ghc_lib_parser(9, 6, 1)
mkSplice :: GHC.HsUntypedSplice GHC.GhcPs -> Splice
mkSplice (GHC.HsUntypedSpliceExpr anns x)
  | hasDollarToken anns = UntypedDollar $ mkExpression <$> fromGenLocated x
  | otherwise = UntypedBare $ mkExpression <$> fromGenLocated x
mkSplice (GHC.HsQuasiQuote _ l (GHC.L _ r)) = QuasiQuote (mkPrefixName l) r
#else
mkSplice :: GHC.HsSplice GHC.GhcPs -> Splice
mkSplice (GHC.HsTypedSplice _ _ _ body) =
  Typed $ mkExpression <$> fromGenLocated body
mkSplice (GHC.HsUntypedSplice _ GHC.DollarSplice _ body) =
  UntypedDollar $ mkExpression <$> fromGenLocated body
mkSplice (GHC.HsUntypedSplice _ GHC.BareSplice _ body) =
  UntypedBare $ mkExpression <$> fromGenLocated body
mkSplice (GHC.HsQuasiQuote _ _ l _ r) = QuasiQuote (mkPrefixName l) r
mkSplice GHC.HsSpliced {} = error "This AST node should never appear."
#endif

#if MIN_VERSION_ghc_lib_parser(9, 12, 1)
hasDollarToken :: GHC.XUntypedSpliceExpr GHC.GhcPs -> Bool
hasDollarToken (GHC.EpTok _) = True
hasDollarToken GHC.NoEpTok = False
#elif MIN_VERSION_ghc_lib_parser(9, 10, 1)
hasDollarToken :: GHC.XUntypedSpliceExpr GHC.GhcPs -> Bool
hasDollarToken anns = any isDollarAnn anns
  where
    isDollarAnn (GHC.AddEpAnn GHC.AnnDollar _) = True
    isDollarAnn _ = False
#else
hasDollarToken :: GHC.XUntypedSpliceExpr GHC.GhcPs -> Bool
hasDollarToken (GHC.EpAnn _ anns _) = any isDollarAnn anns
  where
    isDollarAnn (GHC.AddEpAnn GHC.AnnDollar _) = True
    isDollarAnn _ = False
hasDollarToken GHC.EpAnnNotUsed = False
#endif
mkTypedSplice :: GHC.LHsExpr GHC.GhcPs -> Splice
mkTypedSplice = Typed . fmap mkExpression . fromGenLocated