Skip to content

Commit 1261489

Browse files
committed
Cleanup ExactPrint to split FunBind matches
1 parent b2236b8 commit 1261489

File tree

1 file changed

+28
-66
lines changed

1 file changed

+28
-66
lines changed

ghcide/src/Development/IDE/GHC/ExactPrint.hs

Lines changed: 28 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ import Language.LSP.Types.Capabilities (ClientCapabilities)
6363
import Outputable (Outputable, ppr, showSDoc)
6464
import Retrie.ExactPrint hiding (parseDecl, parseExpr, parsePattern, parseType)
6565
import Parser (parseIdentifier)
66-
import Data.List (isPrefixOf)
6766
import Data.Traversable (for)
67+
import Data.Foldable (Foldable(fold))
68+
import Data.Bool (bool)
6869
#if __GLASGOW_HASKELL__ == 808
6970
import Control.Arrow
7071
#endif
@@ -213,70 +214,6 @@ graftWithoutParentheses dst val = Graft $ \dflags a -> do
213214
a
214215

215216

216-
------------------------------------------------------------------------------
217-
-- | 'parseDecl' fails to parse decls that span multiple lines at the top
218-
-- layout --- eg. things like:
219-
--
220-
-- @
221-
-- not True = False
222-
-- not False = True
223-
-- @
224-
--
225-
-- This function splits up each top-layout declaration, parses them
226-
-- individually, and then merges them back into a single decl.
227-
parseDecls :: DynFlags -> FilePath -> String -> ParseResult (LHsDecl GhcPs)
228-
parseDecls dflags fp str = do
229-
let mono_decls = fmap unlines $ groupByFirstLine $ lines str
230-
decls <-
231-
for (zip [id @Int 0..] mono_decls) $ \(ix, line) ->
232-
parseDecl dflags (fp <> show ix) line
233-
mergeDecls decls
234-
235-
236-
------------------------------------------------------------------------------
237-
-- | Combine decls together. See 'parseDecl' for more information.
238-
mergeDecls :: [(Anns, LHsDecl GhcPs)] -> ParseResult (LHsDecl GhcPs)
239-
mergeDecls [x] = pure x
240-
mergeDecls ((anns, L _ (ValD ext fb@FunBind{fun_matches = mg@MG {mg_alts = L _ alts}}))
241-
-- Since 'groupByFirstLine' separates matches, we are guaranteed to
242-
-- only have a single alternative here. We want to add it to 'alts'
243-
-- above.
244-
: (anns', L _ (ValD _ FunBind{fun_matches = MG {mg_alts = L _ [alt]}}))
245-
: decls) =
246-
mergeDecls $
247-
( anns <> setPrecedingLines alt 1 0 anns'
248-
, noLoc $ ValD ext $ fb
249-
{ fun_matches = mg { mg_alts = noLoc $ alts <> [alt] }
250-
}
251-
) : decls
252-
mergeDecls _ = throwParseError "mergeDecls: attempted to merge something that wasn't a ValD FunBind"
253-
254-
255-
throwParseError :: String -> ParseResult a
256-
#if __GLASGOW_HASKELL__ > 808
257-
throwParseError
258-
= Left . listToBag . pure . mkErrMsg unsafeGlobalDynFlags noSrcSpan neverQualify . text
259-
#else
260-
throwParseError = Left . (noSrcSpan, )
261-
#endif
262-
263-
264-
------------------------------------------------------------------------------
265-
-- | Groups strings by the Haskell top-layout rules, assuming each element of
266-
-- the list corresponds to a line. For example, the list
267-
--
268-
-- @["a", " a1", " a2", "b", " b1"]@
269-
--
270-
-- will be grouped to
271-
--
272-
-- @[["a", " a1", " a2"], ["b", " b1"]]@
273-
groupByFirstLine :: [String] -> [[String]]
274-
groupByFirstLine [] = []
275-
groupByFirstLine (str : strs) =
276-
let (same, diff) = span (isPrefixOf " ") strs
277-
in (str : same) : groupByFirstLine diff
278-
279-
280217
------------------------------------------------------------------------------
281218

282219
graftWithM ::
@@ -468,13 +405,38 @@ annotate dflags ast = do
468405

469406
-- | Given an 'LHsDecl', compute its exactprint annotations.
470407
annotateDecl :: DynFlags -> LHsDecl GhcPs -> TransformT (Either String) (Anns, LHsDecl GhcPs)
408+
-- The 'parseDecl' function fails to parse 'FunBind' 'ValD's which contain
409+
-- multiple matches. To work around this, we split the single
410+
-- 'FunBind'-of-multiple-matches into multiple 'FunBind's-of-single-matchs, and
411+
-- then merge them all back together.
412+
annotateDecl dflags
413+
(L src (
414+
ValD ext fb@FunBind
415+
{ fun_matches = mg@MG { mg_alts = L alt_src alts@(_:_)}
416+
})) = do
417+
let set_matches matches =
418+
ValD ext fb { fun_matches = mg { mg_alts = L alt_src matches }}
419+
420+
(anns', alts') <- fmap unzip $ for (zip [0..] alts) $ \(ix :: Int, alt) -> do
421+
uniq <- show <$> uniqueSrcSpanT
422+
let rendered = render dflags $ set_matches [alt]
423+
lift (mapLeft show $ parseDecl dflags uniq rendered) >>= \case
424+
(ann, L _ (ValD _ FunBind { fun_matches = MG { mg_alts = L _ [alt']}}))
425+
-> pure (bool id (setPrecedingLines alt' 1 0) (ix /= 0) ann, alt')
426+
_ -> lift $ Left "annotateDecl: didn't parse a single FunBind match"
427+
428+
let expr' = L src $ set_matches alts'
429+
anns'' = setPrecedingLines expr' 1 0 $ fold anns'
430+
431+
pure (anns'', expr')
471432
annotateDecl dflags ast = do
472433
uniq <- show <$> uniqueSrcSpanT
473434
let rendered = render dflags ast
474-
(anns, expr') <- lift $ mapLeft show $ parseDecls dflags uniq rendered
435+
(anns, expr') <- lift $ mapLeft show $ parseDecl dflags uniq rendered
475436
let anns' = setPrecedingLines expr' 1 0 anns
476437
pure (anns', expr')
477438
------------------------------------------------------------------------------
439+
------------------------------------------------------------------------------
478440

479441
-- | Print out something 'Outputable'.
480442
render :: Outputable a => DynFlags -> a -> String

0 commit comments

Comments
 (0)