Skip to content

Commit b681471

Browse files
committed
Refactor collectLiterals in AlternateNumberFormat.
- Re-enable the alternateNumberFormat plugin - Refactor collectLiterals to look for HsLit and HsOverLit directly rather than HsExpr. - This new change removes the issue of finding duplicate Literal entries, as well as drastically reducing the time to parse ISSUE: - Currently the parsing only captures literals on the RHS of the function declaration. Patterns are not being matched properly. This was found in the prior iteration, but was remediated (at the cost of performance).
1 parent acdb82e commit b681471

File tree

3 files changed

+33
-68
lines changed

3 files changed

+33
-68
lines changed

haskell-language-server.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ flag splice
165165

166166
flag alternateNumberFormat
167167
description: Enable Alternate Number Format plugin
168-
default: False
168+
default: True
169169
manual: True
170170

171171
flag qualifyImportedNames

plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/AlternateNumberFormat.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ collectLiteralsRule = define $ \CollectLiterals nfp -> do
6060
let fmts = getFormatTypes <$> pm
6161
-- collect all the literals for a file
6262
lits = collectLiterals . pm_parsed_source <$> pm
63+
6364
pure ([], CLR <$> lits <*> fmts)
6465
where
6566
getFormatTypes = toFormatTypes . toList . extensionFlags . ms_hspp_opts . pm_mod_summary
@@ -121,5 +122,5 @@ requestLiterals state = handleMaybeM "Error: Could not Collect Literals"
121122

122123

123124
logIO :: (MonadIO m, Show a) => IdeState -> a -> m ()
124-
logIO state = liftIO . Logger.logDebug (ideLogger state) . T.pack . show
125+
logIO state = liftIO . Logger.logError (ideLogger state) . T.pack . show
125126

plugins/hls-alternate-number-format-plugin/src/Ide/Plugin/Literals.hs

Lines changed: 30 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ module Ide.Plugin.Literals (
99
, getSrcSpan
1010
) where
1111

12+
import Data.Generics (mkQ)
13+
import Data.Maybe (catMaybes, mapMaybe,
14+
maybeToList)
1215
import Data.Set (Set)
1316
import qualified Data.Set as S
1417
import Data.Text (Text)
@@ -18,7 +21,7 @@ import Development.IDE.GHC.Util (unsafePrintSDoc)
1821
import Development.IDE.Graph.Classes (NFData (rnf))
1922
import qualified GHC.Generics as GHC
2023
import Generics.SYB (Data, Typeable, cast,
21-
everything)
24+
everything, listify)
2225

2326
-- data type to capture what type of literal we are dealing with
2427
-- provides location and possibly source text (for OverLits) as well as it's value
@@ -46,72 +49,33 @@ getSrcSpan = \case
4649
FracLiteral ss _ _ -> ss
4750

4851
-- | Find all literals in a Parsed Source File
49-
collectLiterals :: (Data ast, Typeable ast) => ast -> [Literal]
50-
collectLiterals = S.toList . collectLiterals'
51-
52-
collectLiterals' :: (Data ast, Typeable ast) => ast -> Set Literal
53-
collectLiterals' = everything (<>) (mkQ2 (S.empty :: Set Literal) traverseLExpr traverseLPat)
54-
55-
-- Located Patterns for whatever reason don't get picked up when using `(mkQ (S.empty :: Set Literal) traverseLExpr)
56-
-- as such we need to explicit traverse those in order to pull out any literals
57-
mkQ2 :: (Typeable a, Typeable b, Typeable c) => r -> (b -> r) -> (c -> r) -> a -> r
58-
mkQ2 def left right datum = case cast datum of
59-
Just datum' -> left datum'
60-
Nothing -> maybe def right (cast datum)
61-
62-
traverseLPat :: GenLocated SrcSpan (Pat GhcPs) -> Set Literal
63-
traverseLPat (L sSpan pat) = traversePat sSpan pat
64-
65-
traversePat :: SrcSpan -> Pat GhcPs -> Set Literal
66-
traversePat sSpan = \case
67-
LitPat _ lit -> getLiteralAsList sSpan lit
68-
NPat _ (L olSpan overLit) sexpr1 sexpr2 -> getOverLiteralAsList olSpan overLit
69-
<> collectLiterals' sexpr1
70-
<> collectLiterals' sexpr2
71-
NPlusKPat _ _ (L olSpan loverLit) overLit sexpr1 sexpr2 -> getOverLiteralAsList olSpan loverLit
72-
<> getOverLiteralAsList sSpan overLit
73-
<> collectLiterals' sexpr1
74-
<> collectLiterals' sexpr2
75-
ast -> collectLiterals' ast
76-
77-
traverseLExpr :: GenLocated SrcSpan (HsExpr GhcPs) -> Set Literal
78-
traverseLExpr (L sSpan hsExpr) = traverseExpr sSpan hsExpr
79-
80-
traverseExpr :: SrcSpan -> HsExpr GhcPs -> Set Literal
81-
traverseExpr sSpan = \case
82-
HsOverLit _ overLit -> getOverLiteralAsList sSpan overLit
83-
HsLit _ lit -> getLiteralAsList sSpan lit
84-
expr -> collectLiterals' expr
52+
collectLiterals' :: (Data ast, Typeable ast) => ast -> [Literal]
53+
collectLiterals' = mapMaybe getLiteral . listify isReal
54+
where
55+
isReal :: GenLocated SrcSpan (HsExpr GhcPs) -> Bool
56+
isReal (L (RealSrcSpan _ _) lit) = case lit of
57+
HsLit{} -> True
58+
HsOverLit{} -> True
59+
_ -> False
60+
isReal _ = False
8561

86-
getLiteralAsList :: SrcSpan -> HsLit GhcPs -> Set Literal
87-
getLiteralAsList sSpan lit = case sSpan of
88-
RealSrcSpan rss _ -> getLiteralAsList' lit rss
89-
_ -> S.empty
90-
91-
getLiteralAsList' :: HsLit GhcPs -> RealSrcSpan -> Set Literal
92-
getLiteralAsList' lit = maybe S.empty S.singleton . flip getLiteral lit
93-
94-
-- Translate from Hs Type to our Literal type
95-
getLiteral :: RealSrcSpan -> HsLit GhcPs -> Maybe Literal
96-
getLiteral sSpan = \case
97-
HsInt _ val -> fromIntegralLit sSpan val
98-
HsRat _ val _ -> fromFractionalLit sSpan val
99-
_ -> Nothing
100-
101-
getOverLiteralAsList :: SrcSpan -> HsOverLit GhcPs -> Set Literal
102-
getOverLiteralAsList sSpan lit = case sSpan of
103-
RealSrcSpan rss _ -> getOverLiteralAsList' lit rss
104-
_ -> S.empty
105-
106-
getOverLiteralAsList' :: HsOverLit GhcPs -> RealSrcSpan -> Set Literal
107-
getOverLiteralAsList' lit sSpan = maybe S.empty S.singleton (getOverLiteral sSpan lit)
108-
109-
getOverLiteral :: RealSrcSpan -> HsOverLit GhcPs -> Maybe Literal
110-
getOverLiteral sSpan OverLit{..} = case ol_val of
111-
HsIntegral il -> fromIntegralLit sSpan il
112-
HsFractional fl -> fromFractionalLit sSpan fl
113-
_ -> Nothing
114-
getOverLiteral _ _ = Nothing
62+
collectLiterals :: (Data ast, Typeable ast) => ast -> [Literal]
63+
collectLiterals = everything (<>) (mkQ ([] :: [Literal]) (maybeToList . getLiteral))
64+
65+
-- | Translate from HsLit and HsOverLit Types to our Literal Type
66+
getLiteral :: GenLocated SrcSpan (HsExpr GhcPs) -> Maybe Literal
67+
getLiteral (L (UnhelpfulSpan _) _) = Nothing
68+
getLiteral (L (RealSrcSpan sSpan _ ) lit) = case lit of
69+
-- only want
70+
HsLit _ lit -> case lit of
71+
HsInt _ val -> fromIntegralLit sSpan val
72+
HsRat _ val _ -> fromFractionalLit sSpan val
73+
_ -> Nothing
74+
HsOverLit _ OverLit{..} -> case ol_val of
75+
HsIntegral il -> fromIntegralLit sSpan il
76+
HsFractional fl -> fromFractionalLit sSpan fl
77+
_ -> Nothing
78+
_ -> Nothing
11579

11680
fromIntegralLit :: RealSrcSpan -> IntegralLit -> Maybe Literal
11781
fromIntegralLit s (IL txt _ val) = fmap (\txt' -> IntLiteral s txt' val) (fromSourceText txt)

0 commit comments

Comments
 (0)