@@ -1,24 +1,32 @@
1+{-# LANGUAGE BangPatterns #-}
1{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE LambdaCase #-}
5+{-# LANGUAGE TupleSections #-}
5-- | Functions for working with comment stream.
7-- | Functions for working with comment stream.
7−module Ormolu.CommentStream
9+module Ormolu.Parser.CommentStream
8 ( CommentStream (..)
10 ( CommentStream (..)
9 , Comment (..)
11 , Comment (..)
10 , mkCommentStream
12 , mkCommentStream
11 , isPrevHaddock
13 , isPrevHaddock
15import Data.Char (isSpace)
18import Data.Char (isSpace)
16import Data.Data (Data)
19import Data.Data (Data)
20+import Data.Either (partitionEithers)
17import Data.List (isPrefixOf, sortOn)
21import Data.List (isPrefixOf, sortOn)
18import Data.List.NonEmpty (NonEmpty (..))
22import Data.List.NonEmpty (NonEmpty (..))
19import Data.Maybe (mapMaybe)
23import Data.Maybe (mapMaybe)
25+import Ormolu.Parser.LanguagePragma
26+import Ormolu.Utils (showOutputable)
20import SrcLoc
27import SrcLoc
21import qualified Data.List.NonEmpty as NE
28import qualified Data.List.NonEmpty as NE
29+import qualified Data.Set as S
22import qualified GHC
30import qualified GHC
23import qualified Lexer as GHC
31import qualified Lexer as GHC
@@ -34,28 +42,31 @@ newtype CommentStream = CommentStream [RealLocated Comment]
34newtype Comment = Comment (NonEmpty String)
42newtype Comment = Comment (NonEmpty String)
35 deriving (Eq, Show, Data)
43 deriving (Eq, Show, Data)
37−-- | Create 'CommentStream' from 'GHC.PState'.
45+-- | Create 'CommentStream' from 'GHC.PState'. We also create a 'Set' of
46+-- extensions here, which is not sorted in any way. The pragma comment are
47+-- removed from the 'CommentStream'.
39mkCommentStream
49mkCommentStream
40 :: [Located String] -- ^ Extra comments to include
50 :: [Located String] -- ^ Extra comments to include
41 -> GHC.PState -- ^ Parser state to use for comment extraction
51 -> GHC.PState -- ^ Parser state to use for comment extraction
42− -> CommentStream
52+ -> (CommentStream, Set String)
53+ -- ^ Comment stream and a set of extensions enabled
43−mkCommentStream extraComments pstate
54+mkCommentStream extraComments pstate =
44− = CommentStream
55+ ( CommentStream $
45− -- NOTE It's easier to normalize pragmas right when we construct comment
56+ -- NOTE It's easier to normalize pragmas right when we construct comment
46− -- streams. Because this way we need to do it only once and when we
57+ -- streams. Because this way we need to do it only once and when we
47− -- perform checking later they'll automatically match.
58+ -- perform checking later they'll automatically match.
48− . fmap (mkComment . (fmap normalizePragma))
59+ mkComment . fmap normalizePragma
49− . sortOn startOfSpan
60+ <$> sortOn (realSrcSpanStart . getLoc) comments
64+ (comments, exts) = partitionEithers (partitionComments <$> rawComments)
50− . mapMaybe toRealSpan $
65+ rawComments = mapMaybe toRealSpan $
51 extraComments ++
66 extraComments ++
52 (fmap unAnnotationComment <$> GHC.comment_q pstate) ++
67 (fmap unAnnotationComment <$> GHC.comment_q pstate) ++
53 concatMap (fmap (fmap unAnnotationComment) . snd)
68 concatMap (fmap (fmap unAnnotationComment) . snd)
54 (GHC.annotations_comments pstate)
69 (GHC.annotations_comments pstate)
56− startOfSpan (L l _) = realSrcSpanStart l
57− toRealSpan (L (RealSrcSpan l) a) = Just (L l a)
58− toRealSpan _ = Nothing
60-- | Test whether a 'Comment' looks like a Haddock following a definition,
71-- | Test whether a 'Comment' looks like a Haddock following a definition,
61-- i.e. something starting with @-- ^@.
72-- i.e. something starting with @-- ^@.
@@ -63,6 +74,14 @@ mkCommentStream extraComments pstate
63isPrevHaddock :: Comment -> Bool
74isPrevHaddock :: Comment -> Bool
64isPrevHaddock (Comment (x :| _)) = "-- ^" `isPrefixOf` x
75isPrevHaddock (Comment (x :| _)) = "-- ^" `isPrefixOf` x
77+-- | Pretty-print a 'CommentStream'.
79+showCommentStream :: CommentStream -> String
80+showCommentStream (CommentStream xs) = unlines $
83+ showComment (GHC.L l str) = showOutputable l ++ " " ++ show str
66----------------------------------------------------------------------------
85----------------------------------------------------------------------------
@@ -105,3 +124,18 @@ unAnnotationComment = \case
105 GHC.AnnDocOptions s -> s
124 GHC.AnnDocOptions s -> s
106 GHC.AnnLineComment s -> s
125 GHC.AnnLineComment s -> s
107 GHC.AnnBlockComment s -> s
126 GHC.AnnBlockComment s -> s
128+toRealSpan :: Located a -> Maybe (RealLocated a)
129+toRealSpan (L (RealSrcSpan l) a) = Just (L l a)
130+toRealSpan _ = Nothing
132+-- | If a given comment is a LANGUAGE pragma, return the set of extensions
133+-- it enables in 'Right'. Otherwise return the original comment unchanged.
136+ :: RealLocated String
137+ -> Either (RealLocated String) (Set String)
138+partitionComments input =
139+ case parseLanguagePragma (unLoc input) of
140+ Nothing -> Left input
141+ Just exts -> Right exts