packages feed

ghc-exactprint 1.4.1 → 1.5.0

raw patch · 15 files changed

+482/−209 lines, 15 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Language.Haskell.GHC.ExactPrint.Utils: showAst :: Data a => a -> String
+ Language.Haskell.GHC.ExactPrint: BlankEpAnnotations :: BlankEpAnnotations
+ Language.Haskell.GHC.ExactPrint: BlankSrcSpan :: BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint: BlankSrcSpanFile :: BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint: NoBlankEpAnnotations :: BlankEpAnnotations
+ Language.Haskell.GHC.ExactPrint: NoBlankSrcSpan :: BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint: data BlankEpAnnotations
+ Language.Haskell.GHC.ExactPrint: data BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint: showAst :: Data a => a -> String
+ Language.Haskell.GHC.ExactPrint: showAstData :: Data a => BlankSrcSpan -> BlankEpAnnotations -> a -> SDoc
+ Language.Haskell.GHC.ExactPrint.Dump: BlankEpAnnotations :: BlankEpAnnotations
+ Language.Haskell.GHC.ExactPrint.Dump: BlankSrcSpan :: BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint.Dump: BlankSrcSpanFile :: BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint.Dump: NoBlankEpAnnotations :: BlankEpAnnotations
+ Language.Haskell.GHC.ExactPrint.Dump: NoBlankSrcSpan :: BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint.Dump: data BlankEpAnnotations
+ Language.Haskell.GHC.ExactPrint.Dump: data BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint.Dump: instance GHC.Classes.Eq Language.Haskell.GHC.ExactPrint.Dump.BlankEpAnnotations
+ Language.Haskell.GHC.ExactPrint.Dump: instance GHC.Classes.Eq Language.Haskell.GHC.ExactPrint.Dump.BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint.Dump: instance GHC.Show.Show Language.Haskell.GHC.ExactPrint.Dump.BlankEpAnnotations
+ Language.Haskell.GHC.ExactPrint.Dump: instance GHC.Show.Show Language.Haskell.GHC.ExactPrint.Dump.BlankSrcSpan
+ Language.Haskell.GHC.ExactPrint.Dump: showAstData :: Data a => BlankSrcSpan -> BlankEpAnnotations -> a -> SDoc
+ Language.Haskell.GHC.ExactPrint.ExactPrint: showAst :: Data a => a -> String

Files

ChangeLog view
@@ -1,3 +1,9 @@+2022-02-01 v1.5.0+	* Add private version of showAstData, to be able to render+	AnchorOperation's hacked into SrcSpan's.+	* Change the starting top level margin from 0 to 1. This means we+	can use (DifferentLine n 0) everywhere with the same meaning, not+	needing (DifferentLine n 1) at the top level. Hence 1.5 bump. 2022-01-03 v1.4.1 	* Fix delta-in of open/close parentheses in AnnContext (@pepeiborra) 2022-01-03 v1.4.0.1
ghc-exactprint.cabal view
@@ -1,5 +1,5 @@ name:                ghc-exactprint-version:             1.4.1+version:             1.5.0 synopsis:            ExactPrint for GHC description:         Using the API Annotations available from GHC 9.2.1, this                      library provides a means to round trip any code that can@@ -55,6 +55,7 @@  library   exposed-modules:     Language.Haskell.GHC.ExactPrint+                     , Language.Haskell.GHC.ExactPrint.Dump                      , Language.Haskell.GHC.ExactPrint.ExactPrint                      , Language.Haskell.GHC.ExactPrint.Lookup                      , Language.Haskell.GHC.ExactPrint.Orphans
src/Language/Haskell/GHC/ExactPrint.hs view
@@ -16,8 +16,17 @@          -- * Relativising         , makeDeltaAst+++        -- * Dumping ASTs+        , showAst+        -- ** Temporary copy from GHC, shows AnchorOps embedded in SrcSpan+        , showAstData+        , BlankSrcSpan(..)+        , BlankEpAnnotations(..)         ) where +import Language.Haskell.GHC.ExactPrint.Dump import Language.Haskell.GHC.ExactPrint.ExactPrint import Language.Haskell.GHC.ExactPrint.Transform import Language.Haskell.GHC.ExactPrint.Types
+ src/Language/Haskell/GHC/ExactPrint/Dump.hs view
@@ -0,0 +1,307 @@++{-+Temporary copy of the GHC.Hs.Dump module, modified to show DeltaPos+hacked into a SrcSpan.+-}++{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Language.Haskell.GHC.ExactPrint.Dump (+        -- * Dumping ASTs+        showAstData,+        BlankSrcSpan(..),+        BlankEpAnnotations(..),+    ) where++import Prelude ()+import GHC.Prelude++import GHC.Hs hiding ( ann, anns, deltaPos, realSrcSpan )++import GHC.Core.DataCon++import GHC.Data.Bag+import GHC.Data.FastString+import GHC.Types.Name.Set+import GHC.Types.Name hiding ( occName )+import GHC.Types.SrcLoc+import GHC.Types.Var+import GHC.Types.SourceText+import GHC.Unit.Module hiding ( moduleName )+import GHC.Utils.Outputable++import Data.Data hiding (Fixity)+import qualified Data.ByteString as B++import Data.Generics (extQ, ext1Q, ext2Q)+import Language.Haskell.GHC.ExactPrint.Utils++data BlankSrcSpan = BlankSrcSpan | BlankSrcSpanFile | NoBlankSrcSpan+                  deriving (Eq,Show)++data BlankEpAnnotations = BlankEpAnnotations | NoBlankEpAnnotations+                  deriving (Eq,Show)++-- | Show a GHC syntax tree. This parameterised because it is also used for+-- comparing ASTs in ppr roundtripping tests, where the SrcSpan's are blanked+-- out, to avoid comparing locations, only structure+showAstData :: Data a => BlankSrcSpan -> BlankEpAnnotations -> a -> SDoc+showAstData bs ba a0 = blankLine $$ showAstData' a0+  where+    showAstData' :: Data a => a -> SDoc+    showAstData' =+      generic+              `ext1Q` list+              `extQ` string `extQ` fastString `extQ` srcSpan `extQ` realSrcSpan+              `extQ` annotation+              `extQ` annotationModule+              `extQ` annotationAddEpAnn+              `extQ` annotationGrhsAnn+              `extQ` annotationEpAnnHsCase+              `extQ` annotationEpAnnHsLet+              `extQ` annotationAnnList+              `extQ` annotationEpAnnImportDecl+              `extQ` annotationAnnParen+              `extQ` annotationTrailingAnn+              `extQ` annotationEpaLocation+              `extQ` addEpAnn+              `extQ` lit `extQ` litr `extQ` litt+              `extQ` sourceText+              `extQ` deltaPos+              `extQ` epaAnchor+              `extQ` bytestring+              `extQ` name `extQ` occName `extQ` moduleName `extQ` var+              `extQ` dataCon+              `extQ` bagName `extQ` bagRdrName `extQ` bagVar `extQ` nameSet+              `extQ` fixity+              `ext2Q` located+              `extQ` srcSpanAnnA+              `extQ` srcSpanAnnL+              `extQ` srcSpanAnnP+              `extQ` srcSpanAnnC+              `extQ` srcSpanAnnN++      where generic :: Data a => a -> SDoc+            generic t = parens $ text (showConstr (toConstr t))+                                  $$ vcat (gmapQ showAstData' t)++            string :: String -> SDoc+            string     = text . normalize_newlines . show++            fastString :: FastString -> SDoc+            fastString s = braces $+                            text "FastString:"+                        <+> text (normalize_newlines . show $ s)++            bytestring :: B.ByteString -> SDoc+            bytestring = text . normalize_newlines . show++            list []    = brackets empty+            list [x]   = brackets (showAstData' x)+            list (x1 : x2 : xs) =  (text "[" <> showAstData' x1)+                                $$ go x2 xs+              where+                go y [] = text "," <> showAstData' y <> text "]"+                go y1 (y2 : ys) = (text "," <> showAstData' y1) $$ go y2 ys++            -- Eliminate word-size dependence+            lit :: HsLit GhcPs -> SDoc+            lit (HsWordPrim   s x) = numericLit "HsWord{64}Prim" x s+            lit (HsWord64Prim s x) = numericLit "HsWord{64}Prim" x s+            lit (HsIntPrim    s x) = numericLit "HsInt{64}Prim"  x s+            lit (HsInt64Prim  s x) = numericLit "HsInt{64}Prim"  x s+            lit l                  = generic l++            litr :: HsLit GhcRn -> SDoc+            litr (HsWordPrim   s x) = numericLit "HsWord{64}Prim" x s+            litr (HsWord64Prim s x) = numericLit "HsWord{64}Prim" x s+            litr (HsIntPrim    s x) = numericLit "HsInt{64}Prim"  x s+            litr (HsInt64Prim  s x) = numericLit "HsInt{64}Prim"  x s+            litr l                  = generic l++            litt :: HsLit GhcTc -> SDoc+            litt (HsWordPrim   s x) = numericLit "HsWord{64}Prim" x s+            litt (HsWord64Prim s x) = numericLit "HsWord{64}Prim" x s+            litt (HsIntPrim    s x) = numericLit "HsInt{64}Prim"  x s+            litt (HsInt64Prim  s x) = numericLit "HsInt{64}Prim"  x s+            litt l                  = generic l++            numericLit :: String -> Integer -> SourceText -> SDoc+            numericLit tag x s = braces $ hsep [ text tag+                                               , generic x+                                               , generic s ]++            sourceText :: SourceText -> SDoc+            sourceText NoSourceText = parens $ text "NoSourceText"+            sourceText (SourceText src) = case bs of+              NoBlankSrcSpan   -> parens $ text "SourceText" <+> text src+              BlankSrcSpanFile -> parens $ text "SourceText" <+> text src+              _                -> parens $ text "SourceText" <+> text "blanked"++            epaAnchor :: EpaLocation -> SDoc+            epaAnchor (EpaSpan r)  = parens $ text "EpaSpan" <+> realSrcSpan r+            epaAnchor (EpaDelta d cs) = case ba of+              NoBlankEpAnnotations -> parens $ text "EpaDelta" <+> deltaPos d <+> showAstData' cs+              BlankEpAnnotations -> parens $ text "EpaDelta" <+> deltaPos d <+> text "blanked"++            deltaPos :: DeltaPos -> SDoc+            deltaPos (SameLine c) = parens $ text "SameLine" <+> ppr c+            deltaPos (DifferentLine l c) = parens $ text "DifferentLine" <+> ppr l <+> ppr c++            name :: Name -> SDoc+            name nm    = braces $ text "Name:" <+> ppr nm++            occName n  =  braces $+                          text "OccName:"+                      <+> text (occNameString n)++            moduleName :: ModuleName -> SDoc+            moduleName m = braces $ text "ModuleName:" <+> ppr m++            srcSpan :: SrcSpan -> SDoc+            srcSpan ss = case bs of+             BlankSrcSpan -> text "{ ss }"+             NoBlankSrcSpan -> braces $ char ' ' <>+                             (hang (pprSrcSpanWithAnchor ss) 1+                                   (text ""))+             BlankSrcSpanFile -> braces $ char ' ' <>+                             (hang (pprUserSpan False ss) 1+                                   (text ""))++            realSrcSpan :: RealSrcSpan -> SDoc+            realSrcSpan ss = case bs of+             BlankSrcSpan -> text "{ ss }"+             NoBlankSrcSpan -> braces $ char ' ' <>+                             (hang (ppr ss) 1+                                   (text ""))+             BlankSrcSpanFile -> braces $ char ' ' <>+                             (hang (pprUserRealSpan False ss) 1+                                   (text ""))+++            addEpAnn :: AddEpAnn -> SDoc+            addEpAnn (AddEpAnn a s) = case ba of+             BlankEpAnnotations -> parens+                                      $ text "blanked:" <+> text "AddEpAnn"+             NoBlankEpAnnotations ->+              parens $ text "AddEpAnn" <+> ppr a <+> epaAnchor s++            var  :: Var -> SDoc+            var v      = braces $ text "Var:" <+> ppr v++            dataCon :: DataCon -> SDoc+            dataCon c  = braces $ text "DataCon:" <+> ppr c++            bagRdrName:: Bag (LocatedA (HsBind GhcPs)) -> SDoc+            bagRdrName bg =  braces $+                             text "Bag(LocatedA (HsBind GhcPs)):"+                          $$ (list . bagToList $ bg)++            bagName   :: Bag (LocatedA (HsBind GhcRn)) -> SDoc+            bagName bg  =  braces $+                           text "Bag(LocatedA (HsBind Name)):"+                        $$ (list . bagToList $ bg)++            bagVar    :: Bag (LocatedA (HsBind GhcTc)) -> SDoc+            bagVar bg  =  braces $+                          text "Bag(LocatedA (HsBind Var)):"+                       $$ (list . bagToList $ bg)++            nameSet ns =  braces $+                          text "NameSet:"+                       $$ (list . nameSetElemsStable $ ns)++            fixity :: Fixity -> SDoc+            fixity fx =  braces $+                         text "Fixity:"+                     <+> ppr fx++            located :: (Data a, Data b) => GenLocated a b -> SDoc+            located (L ss a)+              = parens (text "L"+                        $$ vcat [showAstData' ss, showAstData' a])+++            -- -------------------------++            annotation :: EpAnn [AddEpAnn] -> SDoc+            annotation = annotation' (text "EpAnn [AddEpAnn]")++            annotationModule :: EpAnn AnnsModule -> SDoc+            annotationModule = annotation' (text "EpAnn AnnsModule")++            annotationAddEpAnn :: EpAnn AddEpAnn -> SDoc+            annotationAddEpAnn = annotation' (text "EpAnn AddEpAnn")++            annotationGrhsAnn :: EpAnn GrhsAnn -> SDoc+            annotationGrhsAnn = annotation' (text "EpAnn GrhsAnn")++            annotationEpAnnHsCase :: EpAnn EpAnnHsCase -> SDoc+            annotationEpAnnHsCase = annotation' (text "EpAnn EpAnnHsCase")++            annotationEpAnnHsLet :: EpAnn AnnsLet -> SDoc+            annotationEpAnnHsLet = annotation' (text "EpAnn AnnsLet")++            annotationAnnList :: EpAnn AnnList -> SDoc+            annotationAnnList = annotation' (text "EpAnn AnnList")++            annotationEpAnnImportDecl :: EpAnn EpAnnImportDecl -> SDoc+            annotationEpAnnImportDecl = annotation' (text "EpAnn EpAnnImportDecl")++            annotationAnnParen :: EpAnn AnnParen -> SDoc+            annotationAnnParen = annotation' (text "EpAnn AnnParen")++            annotationTrailingAnn :: EpAnn TrailingAnn -> SDoc+            annotationTrailingAnn = annotation' (text "EpAnn TrailingAnn")++            annotationEpaLocation :: EpAnn EpaLocation -> SDoc+            annotationEpaLocation = annotation' (text "EpAnn EpaLocation")++            annotation' :: forall a .(Data a)+                       => SDoc -> EpAnn a -> SDoc+            annotation' tag anns = case ba of+             BlankEpAnnotations -> parens (text "blanked:" <+> tag)+             NoBlankEpAnnotations -> parens $ text (showConstr (toConstr anns))+                                               $$ vcat (gmapQ showAstData' anns)++            -- -------------------------++            srcSpanAnnA :: SrcSpanAnn' (EpAnn AnnListItem) -> SDoc+            srcSpanAnnA = locatedAnn'' (text "SrcSpanAnnA")++            srcSpanAnnL :: SrcSpanAnn' (EpAnn AnnList) -> SDoc+            srcSpanAnnL = locatedAnn'' (text "SrcSpanAnnL")++            srcSpanAnnP :: SrcSpanAnn' (EpAnn AnnPragma) -> SDoc+            srcSpanAnnP = locatedAnn'' (text "SrcSpanAnnP")++            srcSpanAnnC :: SrcSpanAnn' (EpAnn AnnContext) -> SDoc+            srcSpanAnnC = locatedAnn'' (text "SrcSpanAnnC")++            srcSpanAnnN :: SrcSpanAnn' (EpAnn NameAnn) -> SDoc+            srcSpanAnnN = locatedAnn'' (text "SrcSpanAnnN")++            locatedAnn'' :: forall a. (Data a)+              => SDoc -> SrcSpanAnn' a -> SDoc+            locatedAnn'' tag ss = parens $+              case cast ss of+                Just ((SrcSpanAnn ann s) :: SrcSpanAnn' a) ->+                  case ba of+                    BlankEpAnnotations+                      -> parens (text "blanked:" <+> tag)+                    NoBlankEpAnnotations+                      -> text "SrcSpanAnn" <+> showAstData' ann+                              <+> srcSpan s+                Nothing -> text "locatedAnn:unmatched" <+> tag+                           <+> (parens $ text (showConstr (toConstr ss)))+++normalize_newlines :: String -> String+normalize_newlines ('\\':'r':'\\':'n':xs) = '\\':'n':normalize_newlines xs+normalize_newlines (x:xs)                 = x:normalize_newlines xs+normalize_newlines []                     = []++pprSrcSpanWithAnchor :: SrcSpan -> SDoc+pprSrcSpanWithAnchor ss@(UnhelpfulSpan _) = ppr ss+pprSrcSpanWithAnchor ss = ppr ss <+> parens (ppr (hackSrcSpanToAnchor ss))
src/Language/Haskell/GHC/ExactPrint/ExactPrint.hs view
@@ -24,10 +24,13 @@   , stringOptions   , epOptions   , deltaOptions++  -- Temporary to avoid import loop problems+  , showAst   ) where  import GHC-import GHC.Base (NonEmpty(..))+import GHC.Base (NonEmpty(..) ) import GHC.Core.Coercion.Axiom (Role(..)) import GHC.Data.Bag import qualified GHC.Data.BooleanFormula as BF@@ -57,6 +60,7 @@  import Data.Void +import Language.Haskell.GHC.ExactPrint.Dump import Language.Haskell.GHC.ExactPrint.Lookup import Language.Haskell.GHC.ExactPrint.Utils import Language.Haskell.GHC.ExactPrint.Types@@ -65,6 +69,15 @@  -- --------------------------------------------------------------------- +-- Note: moved from Language.Haskell.GHC.ExactPrint.Utils as a hack to+-- avoid import loop problems while we have to use the local version+-- of Dump+showAst :: (Data a) => a -> String+showAst ast+  = showSDocUnsafe+    $ showAstData NoBlankSrcSpan NoBlankEpAnnotations ast+-- ---------------------------------------------------------------------+ exactPrint :: ExactPrint ast => ast -> String exactPrint ast = snd $ runIdentity (runEP stringOptions (markAnnotated ast)) @@ -99,9 +112,9 @@ defaultEPState :: EPState defaultEPState = EPState              { epPos      = (1,1)-             , dLHS       = 0+             , dLHS       = 1              , pMarkLayout = False-             , pLHS = 0+             , pLHS = 1              , dMarkLayout = False              , dPriorEndPosition = (1,1)              , uAnchorSpan = badRealSrcSpan@@ -192,11 +205,6 @@  -- --------------------------------------------------------------------- --- type Annotated = FreeT AnnotationF Identity--- type Annotated a = EP w m a---- ---------------------------------------------------------------------- -- | Key entry point.  Switches to an independent AST element with its -- own annotation, calculating new offsets, etc markAnnotated :: (Monad m, Monoid w, ExactPrint a) => a -> EP w m a@@ -237,7 +245,11 @@ fromAnn' :: (HasEntry a) => a -> Entry fromAnn' an = case fromAnn an of   NoEntryVal -> NoEntryVal-  Entry a c _ u -> Entry a c FlushComments u+  Entry a c _ u -> Entry a c' FlushComments u+    where+      c' = case c of+        EpaComments cs -> EpaCommentsBalanced (filterEofComment False cs) (filterEofComment True cs)+        EpaCommentsBalanced cp ct -> EpaCommentsBalanced cp ct  -- --------------------------------------------------------------------- @@ -340,22 +352,18 @@    debugM $ "enterAnn: (anchor_op, curAnchor):" ++ show (anchor_op anchor', rs2range curAnchor)   debugM $ "enterAnn: (dLHS,spanStart,pec,edp)=" ++ show (off,spanStart,priorEndAfterComments,edp)-  p <- getPosP+  p0 <- getPosP   d <- getPriorEndD-  debugM $ "enterAnn: (posp, posd)=" ++ show (p,d)+  debugM $ "enterAnn: (posp, posd)=" ++ show (p0,d)    -- end of delta phase processing   -- -------------------------------------------------------------------   -- start of print phase processing    let mflush = when (flush == FlushComments) $ do-        debugM $ "flushing comments in enterAnn"-        flushComments (getFollowingComments cs)+        debugM $ "flushing comments in enterAnn:" ++ showAst cs+        flushComments (getFollowingComments cs ++ filterEofComment True (priorComments cs)) -  -- let-  --   st = annNone-  -- withOffset st (advance edp >> exact a >> mflush)--- local :: (r -> r) -> RWST r w s m a -> RWST r w s m a   advance edp   a' <- exact a   mflush@@ -373,22 +381,13 @@             CanUpdateAnchor -> setAnnotationAnchor a' newAchor (mkEpaComments (priorCs++ postCs) [])             CanUpdateAnchorOnly -> setAnnotationAnchor a' newAchor emptyComments             NoCanUpdateAnchor -> a'-  -- let r = (setAnnotationAnchor a' newAchor (mkEpaComments [] postCs))-  pure () -- monadic action to flush debugM   -- debugM $ "calling setAnnotationAnchor:(curAnchor, newAchor,priorCs,postCs)=" ++ showAst (show (rs2range curAnchor), newAchor, priorCs, postCs)   -- debugM $ "calling setAnnotationAnchor:(newAchor,postCs)=" ++ showAst (newAchor, postCs)-  debugM $ "enterAnn:done:(p,a) =" ++ show (p, astId a')+  debugM $ "enterAnn:done:(p,a) =" ++ show (p0, astId a')   return r  -- --------------------------------------------------------------------- --- withComments :: (Monad m, Monoid w) => Annotation -> (EP w m a -> EP w m a)--- withComments a =---   local (\s -> s { epAnn = a, epContext = pushAcs (epContext s) })----- ---------------------------------------------------------------------- addCommentsA :: (Monad m, Monoid w) => [LEpaComment] -> EP w m () addCommentsA csNew = addComments (map tokComment csNew) @@ -425,12 +424,23 @@ -- ones in the state. flushComments :: (Monad m, Monoid w) => [LEpaComment] -> EP w m () flushComments trailing = do-  addCommentsA trailing+  addCommentsA (filterEofComment False trailing)   cs <- getUnallocatedComments   debugM $ "flushing comments starting"   mapM_ printOneComment (sortComments cs)+  debugM $ "flushing comments:EOF:trailing:" ++ showAst (trailing)+  debugM $ "flushing comments:EOF:" ++ showAst (filterEofComment True trailing)+  mapM_ printOneComment (map tokComment (filterEofComment True trailing))   debugM $ "flushing comments done" +filterEofComment :: Bool -> [LEpaComment] -> [LEpaComment]+filterEofComment keep cs = fixCs cs+  where+      notEof com = case com of+       L _ (GHC.EpaComment (EpaEofComment) _) -> keep+       _ -> not keep+      fixCs c = filter notEof c+ -- ---------------------------------------------------------------------  -- |In order to interleave annotations into the stream, we turn them into@@ -451,29 +461,6 @@       | Set.member k keywords = go ((mkKWComment k ss):cs', ans) ls       | otherwise             = go (cs', (AddEpAnn k ss):ans)    ls ---- -- |In order to interleave annotations into the stream, we turn them into--- -- comments.--- annotationsToComments' :: (Monad m, Monoid w) => [AddEpAnn] -> [AnnKeywordId] -> EP w m ()--- annotationsToComments' ans kws = do---   let---     getSpans _ [] = []---     getSpans k1 (AddEpAnn k2 ss:as)---       | k1 == k2 = ss : getSpans k1 as---       | otherwise = getSpans k1 as---     doOne :: (Monad m, Monoid w) => AnnKeywordId -> EP w m [Comment]---     doOne kw = do---       let sps =getSpans kw ans---       return $ map (mkKWComment kw ) sps---     -- TODO:AZ make sure these are sorted/merged properly when the invariant for---     -- allocateComments is re-established.---   newComments <- mapM doOne kws---   addComments (concat newComments)---- annotationsToCommentsA :: (Monad m, Monoid w) => EpAnn [AddEpAnn] -> [AnnKeywordId] -> EP w m ()--- annotationsToCommentsA EpAnnNotUsed _ = return ()--- annotationsToCommentsA an kws = annotationsToComments' (anns an) kws- -- ---------------------------------------------------------------------  -- Temporary function to simply reproduce the "normal" pretty printer output@@ -526,7 +513,6 @@     CaptureComments -> takeAppliedComments     NoCaptureComments -> return []   debugM $ "printStringAtRs:cs'=" ++ show cs'-  -- return (EpaDelta p' (map comment2LEpaComment (noKWComments cs')))   return (EpaDelta p' (map comment2LEpaComment cs'))  printStringAtRs' :: (Monad m, Monoid w) => RealSrcSpan -> String -> EP w m ()@@ -534,11 +520,6 @@  -- --------------------------------------------------------------------- --- AZ:TODO get rid of this-printStringAtMLoc :: (Monad m, Monoid w) => Maybe EpaLocation -> String -> EP w m ()-printStringAtMLoc (Just aa) s = printStringAtAA aa s >> return ()-printStringAtMLoc Nothing s = printStringAtLsDelta (SameLine 1) s >> return ()- printStringAtMLoc' :: (Monad m, Monoid w)   => Maybe EpaLocation -> String -> EP w m (Maybe EpaLocation) printStringAtMLoc' (Just aa) s = Just <$> printStringAtAA aa s@@ -579,16 +560,13 @@   p2 <- getPosP   pe2 <- getPriorEndD   debugM $ "printStringAtAA:(pe1,pe2,p1,p2)=" ++ show (pe1,pe2,p1,p2)-  -- setPriorEndASTPD True (p1,p2)   setPriorEndASTPD True (pe1,pe2)   cs' <- case capture of     CaptureComments -> takeAppliedComments     NoCaptureComments -> return []   debugM $ "printStringAtAA:(pe1,pe2,p1,p2,cs')=" ++ show (pe1,pe2,p1,p2,cs')-  -- return (EpaDelta d (map comment2LEpaComment (noKWComments cs')))   return (EpaDelta d (map comment2LEpaComment cs')) - -- ---------------------------------------------------------------------  markExternalSourceText :: (Monad m, Monoid w) => SrcSpan -> SourceText -> String -> EP w m ()@@ -597,14 +575,6 @@  -- --------------------------------------------------------------------- --- -- TODO: remove in favour of markLensMAA--- markLocatedMAA :: (Monad m, Monoid w) => EpAnn a -> (a -> Maybe AddEpAnn) -> EP w m ()--- markLocatedMAA EpAnnNotUsed  _  = return ()--- markLocatedMAA (EpAnn _ a _) f =---   case f a of---     Nothing -> return ()---     Just aa -> markAddEpAnn aa >> return ()- markLensMAA :: (Monad m, Monoid w) => EpAnn a -> Lens a (Maybe AddEpAnn) -> EP w m (EpAnn a) markLensMAA EpAnnNotUsed  _  = return EpAnnNotUsed markLensMAA (EpAnn anc a cs) l =@@ -621,17 +591,6 @@   return (EpAnn anc (set l a' a) cs)  --- TODO: removein favour of markEpAnnL-markLocatedAAL :: (Monad m, Monoid w) => EpAnn a -> (a -> [AddEpAnn]) -> AnnKeywordId -> EP w m Int-markLocatedAAL EpAnnNotUsed  _ _ = return 1-markLocatedAAL (EpAnn _ a _) f kw = go (f a)-  where-    go [] = return 1-    go (aa@(AddEpAnn kw' _):as)-      | kw' == kw = mark [aa] kw-      | otherwise = go as-- markEpAnnLMS :: (Monad m, Monoid w)   => EpAnn a -> Lens a [AddEpAnn] -> AnnKeywordId -> Maybe String -> EP w m (EpAnn a) markEpAnnLMS an l kw Nothing = markEpAnnL an l kw@@ -732,15 +691,6 @@     kw AnnParens       = (AnnOpenP,  AnnCloseP)     kw AnnParensHash   = (AnnOpenPH, AnnClosePH)     kw AnnParensSquare = (AnnOpenS, AnnCloseS)--- markParen' :: (Monad m, Monoid w) => EpAnn AnnParen -> (forall a. (a,a) -> a) -> EP w m (EpAnn AnnParen)--- markParen' EpAnnNotUsed _ = return (EpAnnNotUsed)--- markParen' (EpAnn anc (AnnParen pt o c) cs) f = do---   markKwA (f $ kw pt) (f (o, c))---   return (EpAnn anc (AnnParen pt o c) cs)---   where---     kw AnnParens       = (AnnOpenP,  AnnCloseP)---     kw AnnParensHash   = (AnnOpenPH, AnnClosePH)---     kw AnnParensSquare = (AnnOpenS, AnnCloseS)  -- --------------------------------------------------------------------- -- Bare bones Optics@@ -1133,9 +1083,7 @@ markAnnKwAllL :: (Monad m, Monoid w)   => EpAnn a -> Lens a [EpaLocation] -> AnnKeywordId -> EP w m (EpAnn a) markAnnKwAllL EpAnnNotUsed  _ _  = return EpAnnNotUsed--- markAnnKwAllL (EpAnn _ a _) f kw = mapM_ (markKwA kw) (sort (f a)) markAnnKwAllL (EpAnn anc a cs) l kw = do-  -- anns <- mapM (markKwA kw) (sort (view l a))   anns <- mapM (markKwA kw) (view l a)   return (EpAnn anc (set l anns a) cs) @@ -1157,17 +1105,12 @@   t <- markTrailing (lann_trailing a)   return (EpAnn anc (a { lann_trailing = t }) cs) --- Deprecate in favour of markEpAnnL+-- TODO: Deprecate in favour of markEpAnnL markEpAnn :: (Monad m, Monoid w)   => EpAnn [AddEpAnn] -> AnnKeywordId -> EP w m Int -- Return something to trigger not used warning markEpAnn EpAnnNotUsed _ = return 1 markEpAnn (EpAnn _ a _) kw = mark a kw >> return 1 --- -- Deprecate in favour of markEpAnnL--- markEpAnn' :: (Monad m, Monoid w)---   => EpAnn ann -> (ann -> [AddEpAnn]) -> AnnKeywordId -> EP w m ()--- markEpAnn' EpAnnNotUsed _ _ = return ()--- markEpAnn' (EpAnn _anc a _cs) f kw = mark' (f a) kw >> return ()  markEpAnnL :: (Monad m, Monoid w)   => EpAnn ann -> Lens ann [AddEpAnn] -> AnnKeywordId -> EP w m (EpAnn ann)@@ -1324,7 +1267,9 @@   dp' <- case mep of     Just (Anchor _ (MovedAnchor edp)) -> do       debugM $ "printOneComment:edp=" ++ show edp-      adjustDeltaForOffsetM edp+      ddd <- fmap unTweakDelta $ adjustDeltaForOffsetM edp+      debugM $ "printOneComment:ddd=" ++ show ddd+      fmap unTweakDelta $ adjustDeltaForOffsetM edp     _ -> return dp   -- Start of debug printing   -- LayoutStartCol dOff <- getLayoutOffsetD@@ -1334,18 +1279,25 @@   updateAndApplyComment c dp'   printQueuedComment (anchor loc) c dp' +-- | For comment-related deltas starting on a new line we have an+-- off-by-one problem. Adjust+unTweakDelta :: DeltaPos  -> DeltaPos+unTweakDelta (SameLine d) = SameLine d+unTweakDelta (DifferentLine l d) = DifferentLine l (d+1)++ updateAndApplyComment :: (Monad m, Monoid w) => Comment -> DeltaPos -> EP w m ()-updateAndApplyComment co@(Comment str anc pp mo) dp = do+updateAndApplyComment (Comment str anc pp mo) dp = do   -- debugM $ "updateAndApplyComment: (dp,anc',co)=" ++ showAst (dp,anc',co)   applyComment (Comment str anc' pp mo)   where-    -- anc' = anc { anchor_op = MovedAnchor dp }     anc' = anc { anchor_op = op}      (r,c) = ss2posEnd pp     la = anchor anc     dp'' = if r == 0-           then (ss2delta (r,c+1) la)+           -- then (ss2delta (r,c+1) la)+           then (ss2delta (r,c+0) la)            else (ss2delta (r,c)   la)     dp' = if pp == anchor anc              then dp@@ -1394,14 +1346,12 @@ -- | Bare Located elements are simply stripped off without further -- processing. instance (ExactPrint a) => ExactPrint (Located a) where-  -- getAnnotationEntry (L l _) = Entry (spanAsAnchor l) emptyComments NoFlushComments NoCanUpdateAnchor   getAnnotationEntry (L l _) = case l of     UnhelpfulSpan _ -> NoEntryVal     _ -> Entry (hackSrcSpanToAnchor l) emptyComments NoFlushComments CanUpdateAnchorOnly-  -- getAnnotationEntry (L l _) = NoEntryVal -  -- setAnnotationAnchor _la _anc _cs = error "should not be called:setAnnotationAnchor (Located a)"-  setAnnotationAnchor (L _ a) anc _cs = L (hackAnchorToSrcSpan anc) a+  setAnnotationAnchor (L _ a) anc _cs = (L (hackAnchorToSrcSpan anc) a)+                 `debug` ("setAnnotationAnchor(Located):" ++ showAst anc)    exact (L l a) = L l <$> markAnnotated a @@ -1457,7 +1407,6 @@            return (an1, Just m', mdeprec', mexports') -    -- debugM $ "After HsModule.AnnWhere done, an0=" ++ showAst (anns an0)     let ann_decls = EpAnn (entry an) (am_decls $ anns an0) emptyComments     (ann_decls', (decls', imports')) <- markAnnList' False ann_decls $ do       imports' <- markTopLevelList imports@@ -1528,7 +1477,7 @@               return $ Just (mo', mc')             Nothing ->  do               _ <- markAnnOpen' Nothing msrc "{-# SOURCE"-              printStringAtMLoc Nothing "#-}"+              printStringAtLsDelta (SameLine 1) "#-}"               return Nothing         NoSourceText -> return (importDeclAnnPragma an)     ann1 <- if safeflag@@ -1880,17 +1829,13 @@       case mtybndrs of         Nothing -> return (an0, Nothing)         Just bndrs -> do-          -- an1 <-  markLensMAA an0 (\a -> fmap fst (ra_tyanns a))  -- AnnForall           an1 <-  markLensMAA an0 lra_tyanns_fst  -- AnnForall           bndrs' <- mapM markAnnotated bndrs-          -- an2 <- markLensMAA an1 (\a -> fmap snd (ra_tyanns a))  -- AnnDot           an2 <- markLensMAA an1 lra_tyanns_snd  -- AnnDot           return (an2, Just bndrs') -    -- an2 <- markLensMAA an1 (\a -> fmap fst (ra_tmanns a))  -- AnnForall     an2 <- markLensMAA an1 lra_tmanns_fst  -- AnnForall     termbndrs' <- mapM markAnnotated termbndrs-    -- an3 <- markLensMAA an2 (\a -> fmap snd (ra_tmanns a))  -- AnnDot     an3 <- markLensMAA an2 lra_tmanns_snd  -- AnnDot      lhs' <- markAnnotated lhs@@ -2058,7 +2003,6 @@  -- --------------------------------------------------------------------- --- instance ExactPrint (LHsTypeArg GhcPs) where instance (ExactPrint tm, ExactPrint ty, Outputable tm, Outputable ty)      =>  ExactPrint (HsArg tm ty) where   getAnnotationEntry = const NoEntryVal@@ -2082,7 +2026,6 @@                      , cid_datafam_insts = adts })       = do           (an0, mbOverlap', inst_ty') <- top_matter-          -- an0 <- markEpAnnL an' lidl AnnWhere           an1 <- markEpAnnL an0 lidl AnnOpenC           an2 <- markEpAnnAllL an1 lid AnnSemi           ds <- withSortKey sortKey@@ -2394,7 +2337,7 @@     return (HsValBinds an1 valbinds')    exact (HsIPBinds an bs) = do-    (as, ipb) <- markAnnList True an (markLocatedAAL an al_rest AnnWhere+    (as, ipb) <- markAnnList True an (markEpAnnL an lal_rest AnnWhere                            >> markAnnotated bs                            >>= \bs' -> return (HsIPBinds an bs'::HsLocalBinds GhcPs))     case ipb of@@ -2460,7 +2403,6 @@ prepareListAnnotationF an ls = map (\b -> (realSrcSpan $ getLocA b, go b)) ls   where     go (L l a) = do-      -- d' <- markAnnotated (DataFamInstDeclWithContext an TopLevel a)       d' <- markAnnotated (DataFamInstDeclWithContext an NotTopLevel a)       return (toDyn (L l (dc_d d'))) @@ -2698,7 +2640,9 @@    exact (GRHS an guards expr) = do     debugM $ "GRHS comments:" ++ showGhc (comments an)-    an0 <- markLensKwM an lga_vbar AnnVbar+    an0 <- if null guards+             then return an+             else markLensKwM an lga_vbar AnnVbar     guards' <- markAnnotated guards     debugM $ "GRHS before matchSeparator"     an1 <- markLensAA an0 lga_sep -- Mark the matchSeparator for these GRHSs@@ -2825,7 +2769,6 @@                 HsIntegral   (IL src _ _) -> src                 HsFractional (FL { fl_text = src }) -> src                 HsIsString src _          -> src-    -- markExternalSourceText l str ""     case str of       SourceText s -> printStringAdvance s >> return ()       NoSourceText -> withPpr x >> return ()@@ -3177,7 +3120,6 @@   setAnnotationAnchor a _ _ = a   exact (MG x matches o) = do     -- TODO:AZ use SortKey, in MG ann.-    -- matches' <- markAnnotated matches     matches' <- if isGoodSrcSpan (getLocA matches)       then markAnnotated matches       else return matches@@ -3510,7 +3452,6 @@    exact (RecStmt an stmts a b c d e) = do     debugM $ "RecStmt"-    -- markLocatedAAL an al_rest AnnRec     an0 <- markEpAnnL an lal_rest AnnRec     (an1, stmts') <- markAnnList True an0 (markAnnotated stmts)     return (RecStmt an1 stmts' a b c d e)@@ -4098,15 +4039,6 @@                              , deriv_clause_strategy = dcs                              , deriv_clause_tys      = dct' })       where-        -- -- This complexity is to distinguish between-        -- --    deriving Show-        -- --    deriving (Show)-        -- pp_dct [HsIB { hsib_body = ty }]-        --          = ppr (parenthesizeHsType appPrec ty)-        -- pp_dct _ = parens (interpp'SP dct)--        -- @via@ is unique in that in comes /after/ the class being derived,-        -- so we must special-case it.         (exact_strat_before, exact_strat_after) =           case dcs of             Just v@(L _ ViaStrategy{}) -> (pure (), markAnnotated v >> pure ())@@ -4141,10 +4073,8 @@     a' <- markAnnotated a     return (L (SrcSpanAnn EpAnnNotUsed l) a')   exact (L (SrcSpanAnn (EpAnn anc (AnnContext ma opens closes) cs) l) a) = do-    -- mapM_ (markKwA AnnOpenP) (sort opens)     opens' <- mapM (markKwA AnnOpenP) opens     a' <- markAnnotated a-    -- mapM_ (markKwA AnnCloseP) (sort closes)     closes' <- mapM (markKwA AnnCloseP) closes     ma' <- case ma of       Just (UnicodeSyntax, r) -> Just . (UnicodeSyntax,) <$> markKwA AnnDarrowU r@@ -4190,12 +4120,6 @@       case ann of         NameAnn a o l c t -> do           mn <- markName a o (Just (l,n)) c-          -- let (o', (Just (l',_)), c') =-          --       case mn of-          --        (o', (Just (l',n')), c') -> (o', (Just (l',n')), c')-          --        _ -> error "ExactPrint (LocatedN RdrName)"-          -- t' <- markTrailing t-          -- return (NameAnn a o' l' c' t')           case mn of             (o', (Just (l',_n)), c') -> do -- (o', (Just (l',n')), c')               t' <- markTrailing t@@ -4539,7 +4463,6 @@     let an = fixAnnListAnn an'     debugM $ "LocatedL [ExprLStmt"     (an'', stmts') <- markAnnList True an $ do-      -- markLocatedMAA an al_open       case snocView stmts of         Just (initStmts, ls@(L _ (LastStmt _ _body _ _))) -> do           debugM $ "LocatedL [ExprLStmt: snocView"@@ -4914,7 +4837,7 @@ -- | Print a comment, using the current layout offset to convert the -- @DeltaPos@ to an absolute position. printQueuedComment :: (Monad m, Monoid w) => RealSrcSpan -> Comment -> DeltaPos -> EP w m ()-printQueuedComment loc Comment{commentContents} dp = do+printQueuedComment _loc Comment{commentContents} dp = do   p <- getPosP   d <- getPriorEndD   colOffset <- getLayoutOffsetP@@ -4922,7 +4845,6 @@   -- do not lose comments against the left margin   when (isGoodDelta (deltaPos dr (max 0 dc))) $ do     printCommentAt (undelta p dp colOffset) commentContents-    -- setPriorEndASTD False loc   p' <- getPosP   d' <- getPriorEndD   debugM $ "printQueuedComment: (p,p',d,d')=" ++ show (p,p',d,d')@@ -4951,7 +4873,7 @@   debugM $ "setLayoutTopLevelP entered"   oldAnchorOffset <- getLayoutOffsetP   modify (\a -> a { pMarkLayout = False-                  , pLHS = 0} )+                  , pLHS = 1} )   r <- k   debugM $ "setLayoutTopLevelP:resetting"   setLayoutOffsetP oldAnchorOffset@@ -5081,11 +5003,11 @@       printWhitespace (undelta p dp colOffset)       -- Sync point. We only call advance as we start the sub-span       -- processing, so force the dPriorEndPosition to ???-      p <- getPosP+      p0 <- getPosP       d <- getPriorEndD       r <- getAnchorU       setPriorEndD (fst $ rs2range r)-      debugM $ "advance:after: (posp, posd, posd')=" ++ show (p,d,fst $ rs2range r)+      debugM $ "advance:after: (posp, posd, posd')=" ++ show (p0,d,fst $ rs2range r)     else       return () 
src/Language/Haskell/GHC/ExactPrint/Transform.hs view
@@ -87,6 +87,7 @@         , decl2Sig, decl2Bind         ) where +import Language.Haskell.GHC.ExactPrint.ExactPrint import Language.Haskell.GHC.ExactPrint.Types import Language.Haskell.GHC.ExactPrint.Utils @@ -311,13 +312,8 @@         in           (dp0, EpaCommentsBalanced (c':t) ts)       _ -> (dp, cs)-    -- go (L (Anchor rr (MovedAnchor ma)) c) = (dp, L (Anchor rr (MovedAnchor ma)) c)     go (L (Anchor rr (MovedAnchor ma)) c) = (d,  L (Anchor rr (MovedAnchor ma)) c)     go (L (Anchor rr                _) c) = (d,  L (Anchor rr (MovedAnchor dp)) c)--- setEntryDP (L (SrcSpanAnn (EpAnn (Anchor r (MovedAnchor _)) an cs) l) a) dp---   = L (SrcSpanAnn---            (EpAnn (Anchor r (MovedAnchor dp)) an cs)---            l) a setEntryDP (L (SrcSpanAnn (EpAnn (Anchor r _) an cs) l) a) dp   = case sortEpaComments (priorComments cs) of       [] ->@@ -331,7 +327,7 @@               where                 cs'' = setPriorComments cs (L (Anchor (anchor ca) (MovedAnchor dp)) c:cs')                 lc = head $ reverse $ (L ca c:cs')-                delta = ss2delta (ss2pos $ anchor $ getLoc lc) r+                delta = tweakDelta $ ss2delta (ss2pos $ anchor $ getLoc lc) r                 line = getDeltaLine delta                 col = deltaColumn delta                 edp' = if line == 0 then SameLine col@@ -383,7 +379,6 @@     -- TODO: what happens if the receiving side already has comments?     (L anc _:_) -> do       logDataWithAnnsTr "transferEntryDP':priorComments anc=" anc-      -- return (L (SrcSpanAnn (EpAnn anc an2 cs2) l2) b)       return (L (SrcSpanAnn (EpAnn anc1 (combine an1 an2) (cs1 <> cs2)) l2) b) transferEntryDP (L (SrcSpanAnn EpAnnNotUsed _l1) _) (L (SrcSpanAnn (EpAnn anc2 an2 cs2) l2) b) = do   logTr $ "transferEntryDP': EpAnnNotUsed,EpAnn"@@ -440,9 +435,6 @@   => LHsDecl GhcPs -> LHsDecl GhcPs   -> TransformT m (LHsDecl GhcPs, LHsDecl GhcPs) balanceComments first second = do-  -- ++AZ++ : replace the nested casts with appropriate gmapM-  -- logTr $ "balanceComments entered"-  -- logDataWithAnnsTr "first" first   case first of     (L l (ValD x fb@(FunBind{}))) -> do       (L l' fb',second') <- balanceCommentsFB (L l fb) second@@ -485,7 +477,6 @@         [] -> moveLeadingComments m'' lf'         _  -> (m'',lf')   logTr $ "balanceCommentsMatch done"-  -- return (L lf'' (FunBind x n (MG mx (L lm (reverse (m''':ms))) o) t), second')   balanceComments' (L lf'' (FunBind x n (MG mx (L lm (reverse (m''':ms))) o) t)) second' balanceCommentsFB f s = balanceComments' f s @@ -494,13 +485,7 @@ balanceCommentsMatch :: (Monad m)   => LMatch GhcPs (LHsExpr GhcPs) -> TransformT m (LMatch GhcPs (LHsExpr GhcPs)) balanceCommentsMatch (L l (Match am mctxt pats (GRHSs xg grhss binds))) = do-  logTr $ "balanceCommentsMatch: (loc1)=" ++ showGhc (ss2range (locA l))-  -- logTr $ "balanceCommentsMatch: (move',stay')=" ++ showAst (move',stay')   logTr $ "balanceCommentsMatch: (logInfo)=" ++ showAst (logInfo)-  -- logTr $ "balanceCommentsMatch: (loc1)=" ++ showGhc (ss2range (locA l))-  logTr $ "balanceCommentsMatch: (anc1,cs1f)=" ++ showAst (anc1,cs1f)-  logTr $ "balanceCommentsMatch: (move,stay)=" ++ showAst (move,stay)-  logTr $ "balanceCommentsMatch: (l'', grhss')=" ++ showAst (l'', grhss')   return (L l'' (Match am mctxt pats (GRHSs xg grhss' binds')))   where     simpleBreak (r,_) = r /= 0@@ -711,11 +696,15 @@ commentOrigDelta :: LEpaComment -> LEpaComment commentOrigDelta (L (GHC.Anchor la _) (GHC.EpaComment t pp))   = (L (GHC.Anchor la op) (GHC.EpaComment t pp))+                  `debug` ("commentOrigDelta: (la, pp, r,c, op)=" ++ showAst (la, pp, r,c, op))   where         (r,c) = ss2posEnd pp+         op' = if r == 0                then MovedAnchor (ss2delta (r,c+1) la)-               else MovedAnchor (ss2delta (r,c)   la)+               -- then MovedAnchor (ss2delta (r,c+0) la)+               -- else MovedAnchor (ss2delta (r,c)   la)+               else MovedAnchor (tweakDelta $ ss2delta (r,c)   la)         op = if t == EpaEofComment && op' == MovedAnchor (SameLine 0)                then MovedAnchor (DifferentLine 1 0)                else op'@@ -733,7 +722,7 @@ -- TODO: Until https://gitlab.haskell.org/ghc/ghc/-/issues/20715 is -- fixed we have to special-case a funbind.  Damn. tweakListComments :: LHsDecl GhcPs -> LHsDecl GhcPs-tweakListComments a@(L l (ValD x fb@(FunBind{}))) = tweakListCommentsFB a+tweakListComments a@(L _ (ValD _ (FunBind{}))) = tweakListCommentsFB a tweakListComments a = tweakListComments' a  -- A LocatedA item may have both trailing comments and trailing list items.@@ -762,32 +751,37 @@             -> [TrailingAnn]             -> [LEpaComment]             -> (AnnListItem, b)-    process f (ll,cc) [] cs = (AnnListItem (reverse ll), f (cc++cs))+    process f (ll,cc) [] cs0 = (AnnListItem (reverse ll), f (cc++cs0))     process f (ll,cc) li [] = (AnnListItem (reverse $ ll++li), f cc)-    process f (ll,cc) (l:li) cs@(L lc c:_) = r+    process f (ll,cc) (l0:li) cs0 = r       where-        r = case trailingAnnLoc l of-          EpaSpan s -> r+        r = case trailingAnnLoc l0 of+          EpaSpan s -> r0             where               condp (L lc _) = anchor lc >= anchor anc-              (before,rest) = break condp cs+              (before,rest) = break condp cs0               cond (L lc _) = anchor lc >= s               (these,those) = break cond rest-              r = case these of-                [] -> process f (l:ll,cc) li cs+              r0 = case these of+                [] -> process f (l0:ll,cc) li cs0                 priors ->                       -- We have at least one comment preceding the list item                       let                         -- dp is the delta from the end of the last comment to                         -- the start of the AddXXXAnn delta-                        dp = spanOrigDelta (anchor $ getLoc $ last priors) s+                        dp = tweakDelta $ spanOrigDelta (anchor $ getLoc $ last priors) s                          l' = EpaDelta dp (commentOrigDeltas these)-                        cs' = those+                        cs1 = those                       in-                        process f (setTrailingAnnLoc l l':ll,before++cc) li cs'-          EpaDelta d' cs' -> process f (l:ll,cc) li cs+                        process f (setTrailingAnnLoc l0 l':ll,before++cc) li cs1+          EpaDelta _d' _cs' -> process f (l0:ll,cc) li cs0 +-- | For comment-related deltas starting on a new line we have an+-- off-by-one problem. Adjust+tweakDelta :: DeltaPos  -> DeltaPos+tweakDelta (SameLine d) = SameLine d+tweakDelta (DifferentLine l d) = DifferentLine l (d-1)  -- TODO: Until https://gitlab.haskell.org/ghc/ghc/-/issues/20715 is -- fixed we have to special-case a funbind.  Damn.@@ -800,24 +794,24 @@     -- first match for processing     (l',matches') = case matches of       [] -> (l,matches)-      (L lm m:ms) -> (l', L lm' m:ms)-                          `debug` ("tweakListCommentsFB:(l',lm')=" ++ showAst (l',lm'))+      (L lm0 m:ms) -> (l1, L lm' m:ms)+                          `debug` ("tweakListCommentsFB:(l',lm')=" ++ showAst (l1,lm'))       -- (L lm m:ms) -> error $ "lm'=\n" ++ showAst lm'         where-          (l',cs',as) = case l of+          (l1,cs',as) = case l of             SrcSpanAnn EpAnnNotUsed _ -> (l,[], [])-            SrcSpanAnn (EpAnn anc an (EpaComments cs))            l-              -> (SrcSpanAnn (EpAnn anc (AnnListItem []) (EpaComments [])) l, cs, lann_trailing an)-            SrcSpanAnn (EpAnn anc an (EpaCommentsBalanced ls ts)) l-              -> (SrcSpanAnn (EpAnn anc (AnnListItem []) (EpaCommentsBalanced ls [])) l, ts, lann_trailing an)+            SrcSpanAnn (EpAnn anc an (EpaComments cs))            l0+              -> (SrcSpanAnn (EpAnn anc (AnnListItem []) (EpaComments [])) l0, cs, lann_trailing an)+            SrcSpanAnn (EpAnn anc an (EpaCommentsBalanced ls ts)) l0+              -> (SrcSpanAnn (EpAnn anc (AnnListItem []) (EpaCommentsBalanced ls [])) l0, ts, lann_trailing an) -          lm' = case lm of-            SrcSpanAnn EpAnnNotUsed                               l-              -> SrcSpanAnn (EpAnn (spanAsAnchor l) (AnnListItem as) (EpaComments cs')) l-            SrcSpanAnn (EpAnn anc (AnnListItem is) (EpaComments cs))            l-              -> SrcSpanAnn (EpAnn anc (AnnListItem (as<>is)) (EpaComments (cs'<>cs))) l-            SrcSpanAnn (EpAnn anc (AnnListItem is) (EpaCommentsBalanced ls ts)) l-              -> SrcSpanAnn (EpAnn anc (AnnListItem (as<>is)) (EpaCommentsBalanced (cs'<>ls) ts)) l+          lm' = case lm0 of+            SrcSpanAnn EpAnnNotUsed                               l0+              -> SrcSpanAnn (EpAnn (spanAsAnchor l0) (AnnListItem as) (EpaComments cs')) l0+            SrcSpanAnn (EpAnn anc (AnnListItem is) (EpaComments cs))            l0+              -> SrcSpanAnn (EpAnn anc (AnnListItem (as<>is)) (EpaComments (cs'<>cs))) l0+            SrcSpanAnn (EpAnn anc (AnnListItem is) (EpaCommentsBalanced ls ts)) l0+              -> SrcSpanAnn (EpAnn anc (AnnListItem (as<>is)) (EpaCommentsBalanced (cs'<>ls) ts)) l0      r = (L l' (ValD xv (FunBind x n (MG mx (L lm (map tweakListComments' matches')) o) t))) tweakListCommentsFB x = error $ "tweakListCommentsFB for " ++ showAst x@@ -1262,8 +1256,8 @@ newWhereAnnotation :: (Monad m) => WithWhere -> TransformT m (EpAnn AnnList) newWhereAnnotation ww = do   newSpan <- uniqueSrcSpanT-  let anc  = Anchor (rs newSpan) (MovedAnchor (DifferentLine 1 3))-  let anc2 = Anchor (rs newSpan) (MovedAnchor (DifferentLine 1 5))+  let anc  = Anchor (rs newSpan) (MovedAnchor (DifferentLine 1 2))+  let anc2 = Anchor (rs newSpan) (MovedAnchor (DifferentLine 1 4))   let w = case ww of         WithWhere -> [AddEpAnn AnnWhere (EpaDelta (SameLine 0) [])]         WithoutWhere -> []
src/Language/Haskell/GHC/ExactPrint/Utils.hs view
@@ -22,9 +22,6 @@ import Data.Maybe import Data.Ord (comparing) -import Data.Generics--import GHC.Hs.Dump import Language.Haskell.GHC.ExactPrint.Lookup import Language.Haskell.GHC.ExactPrint.Orphans () @@ -34,7 +31,7 @@ import GHC.Types.Name.Reader import GHC.Types.SrcLoc import GHC.Data.FastString-import GHC.Utils.Outputable (showSDocUnsafe, showPprUnsafe)+import GHC.Utils.Outputable ( showPprUnsafe )  import Data.List (sortBy, elemIndex) @@ -81,8 +78,7 @@ -- | A good delta has no negative values. isGoodDelta :: DeltaPos -> Bool isGoodDelta (SameLine co) = co >= 0--- isGoodDelta (DifferentLine ro co) = ro > 0 && co >= 0-isGoodDelta (DifferentLine ro co) = ro > 0+isGoodDelta (DifferentLine ro _co) = ro > 0   -- Note: DifferentLine invariant is ro is nonzero and positive  @@ -237,8 +233,8 @@ comment2LEpaComment :: Comment -> LEpaComment comment2LEpaComment (Comment s anc r _mk) = mkLEpaComment s anc r - mkLEpaComment :: String -> Anchor -> RealSrcSpan -> LEpaComment+mkLEpaComment "" anc r = (L anc (GHC.EpaComment (EpaEofComment) r)) mkLEpaComment s anc r = (L anc (GHC.EpaComment (EpaLineComment s) r))  mkComment :: String -> Anchor -> RealSrcSpan -> Comment@@ -318,20 +314,23 @@  -- --------------------------------------------------------------------- -showAst :: (Data a) => a -> String-showAst ast-  = showSDocUnsafe-    $ showAstData NoBlankSrcSpan NoBlankEpAnnotations ast+-- Note: moved to Language.Haskell.GHC.ExactPrint.ExactPrint as a hack+-- to avoid import loop problems while we have to use the local+-- version of Dump+-- showAst :: (Data a) => a -> String+-- showAst ast+--   = showSDocUnsafe+--     $ showAstData NoBlankSrcSpan NoBlankEpAnnotations ast  -- ---------------------------------------------------------------------  setAnchorAn :: (Default an) => LocatedAn an a -> Anchor -> EpAnnComments -> LocatedAn an a setAnchorAn (L (SrcSpanAnn EpAnnNotUsed l)    a) anc cs   = (L (SrcSpanAnn (EpAnn anc def cs) l) a)-     `debug` ("setAnchorAn: anc=" ++ showAst anc)+     -- `debug` ("setAnchorAn: anc=" ++ showAst anc) setAnchorAn (L (SrcSpanAnn (EpAnn _ an _) l) a) anc cs   = (L (SrcSpanAnn (EpAnn anc an cs) l) a)-     `debug` ("setAnchorAn: anc=" ++ showAst anc)+     -- `debug` ("setAnchorAn: anc=" ++ showAst anc)  setAnchorEpa :: (Default an) => EpAnn an -> Anchor -> EpAnnComments -> EpAnn an setAnchorEpa EpAnnNotUsed   anc cs = EpAnn anc def cs@@ -344,7 +343,6 @@ setAnchorHsModule :: HsModule -> Anchor -> EpAnnComments -> HsModule setAnchorHsModule hsmod anc cs = hsmod { hsmodAnn = an' }   where-    -- anc' = anc { anchor_op = MovedAnchor (SameLine 0)}     anc' = anc { anchor_op = UnchangedAnchor }     an' = setAnchorEpa (hsmodAnn hsmod) anc' cs 
tests/Test.hs view
@@ -191,12 +191,23 @@   let libdir = GHC.Paths.libdir   runTestText (putTextToHandle stdout True) $ TestList [ -    mkTestModChange libdir rmDecl7 "RmDecl7.hs"+    -- mkTestModChange libdir rmDecl7 "RmDecl7.hs" +    -- mkTestModChange libdir changeLocalDecls  "LocalDecls.hs"     -- mkTestModChange libdir changeLayoutLet2 "LayoutLet2.hs"-    -- mkParserTestMD libdir      "transform" "LayoutLet2.hs"-    -- mkParserTest libdir      "ghc80" "T10970a.hs"+    -- mkTestModChange libdir addLocaLDecl5  "AddLocalDecl5.hs"++   -- mkTestModChange libdir rmDecl1 "RmDecl1.hs"++   -- mkTestModChange libdir rmDecl4 "RmDecl4.hs"+    -- mkParserTestMD libdir      "ghc92" "Foo.hs"+    -- mkParserTest libdir      "ghc92" "Foo.hs"+    mkParserTestMD libdir      "ghc92" "Foo.hs"+    -- mkParserTest libdir      "ghc92" "Foo2.hs"+    -- mkParserTest libdir      "ghc710" "EmptyMostly.hs"     -- mkParserTestBC libdir "ghc710" "Control.hs"+    -- mkParserTestBC libdir "ghc92" "CommentPlacement3.hs"+    -- mkParserTestBC libdir "ghc92" "TopLevelSemis.hs"     -- Needs GHC changes 
tests/Test/Common.hs view
@@ -31,6 +31,7 @@   import Language.Haskell.GHC.ExactPrint+import Language.Haskell.GHC.ExactPrint.ExactPrint import Language.Haskell.GHC.ExactPrint.Utils import Language.Haskell.GHC.ExactPrint.Parsers import Language.Haskell.GHC.ExactPrint.Preprocess
tests/Test/NoAnnotations.hs view
@@ -15,6 +15,7 @@ -- import qualified Data.ByteString as B  import Language.Haskell.GHC.ExactPrint+import Language.Haskell.GHC.ExactPrint.ExactPrint import Language.Haskell.GHC.ExactPrint.Parsers import Language.Haskell.GHC.ExactPrint.Types import Language.Haskell.GHC.ExactPrint.Utils
tests/Test/Transform.hs view
@@ -7,6 +7,7 @@ module Test.Transform where  import Language.Haskell.GHC.ExactPrint+import Language.Haskell.GHC.ExactPrint.ExactPrint import Language.Haskell.GHC.ExactPrint.Types import Language.Haskell.GHC.ExactPrint.Parsers import Language.Haskell.GHC.ExactPrint.Utils@@ -186,8 +187,8 @@                         -> Transform (LMatch GhcPs (LHsExpr GhcPs))       replaceLocalBinds (L lm (Match ma mln pats (GRHSs _ rhs EmptyLocalBinds{}))) = do         newSpan <- uniqueSrcSpanT-        let anc = (Anchor (rs newSpan) (MovedAnchor (DifferentLine 1 3)))-        let anc2 = (Anchor (rs newSpan) (MovedAnchor (DifferentLine 1 5)))+        let anc = (Anchor (rs newSpan) (MovedAnchor (DifferentLine 1 2)))+        let anc2 = (Anchor (rs newSpan) (MovedAnchor (DifferentLine 1 4)))         let an = EpAnn anc                         (AnnList (Just anc2) Nothing Nothing                                  [AddEpAnn AnnWhere (EpaDelta (SameLine 0) [])] [])@@ -261,7 +262,7 @@         -- let (EpAnn anc (AnnList (Just (Anchor anc2 _)) a b c dd) cs) = van         -- let van' = (EpAnn anc (AnnList (Just (Anchor anc2 (MovedAnchor (DifferentLine 1 5)))) a b c dd) cs)         let (EpAnn anc (AnnList _ a b c dd) cs) = van-        let van' = (EpAnn anc (AnnList (Just (Anchor (anchor anc) (MovedAnchor (DifferentLine 1 5)))) a b c dd) cs)+        let van' = (EpAnn anc (AnnList (Just (Anchor (anchor anc) (MovedAnchor (DifferentLine 1 4)))) a b c dd) cs)         let binds' = (HsValBinds van'                           (ValBinds sortKey                                     (listToBag $ decl':oldBinds)@@ -473,7 +474,7 @@ addLocaLDecl1 :: Changer addLocaLDecl1 libdir lp = do   Right (L ld (ValD _ decl)) <- withDynFlags libdir (\df -> parseDecl df "decl" "nn = 2")-  let decl' = setEntryDP (makeDeltaAst (L ld decl)) (DifferentLine 1 5)+  let decl' = setEntryDP (makeDeltaAst (L ld decl)) (DifferentLine 1 4)       doAddLocal = do         (de1:d2:d3:_) <- hsDecls (makeDeltaAst lp)         (de1'',d2') <- balanceComments de1 d2
+ tests/examples/ghc92/Async.hs view
@@ -0,0 +1,11 @@++asyncUsing :: (IO () -> IO ThreadId)+           -> IO a -> IO (Async a)+asyncUsing doFork = \action -> do+   var <- newEmptyTMVarIO+   -- t <- forkFinally action (\r -> atomically $ putTMVar var r)+   -- slightly faster:+   t <- mask $ \restore ->+          doFork $ try (restore action) >>= atomically . putTMVar var+   return (Async t (readTMVar var))+
+ tests/examples/ghc92/Foo.hs view
@@ -0,0 +1,7 @@+module Operator2 where++main = do+  return ({- comment -} x >= 1 || y >= 2)++  putStrLn $ show $ {- comment here -} foo || bar+  print $ {- comment here -} foo || bar
+ tests/examples/ghc92/Foo2.hs view
@@ -0,0 +1,4 @@+yes p1001 p1002+  | g1001 = e1001+  | g1002 = e1002+  | otherwise = e1003
tests/examples/transform/RmDecl4.hs.expected view