@@ -63,8 +63,9 @@ import Language.LSP.Types.Capabilities (ClientCapabilities)
63
63
import Outputable (Outputable , ppr , showSDoc )
64
64
import Retrie.ExactPrint hiding (parseDecl , parseExpr , parsePattern , parseType )
65
65
import Parser (parseIdentifier )
66
- import Data.List (isPrefixOf )
67
66
import Data.Traversable (for )
67
+ import Data.Foldable (Foldable (fold ))
68
+ import Data.Bool (bool )
68
69
#if __GLASGOW_HASKELL__ == 808
69
70
import Control.Arrow
70
71
#endif
@@ -213,70 +214,6 @@ graftWithoutParentheses dst val = Graft $ \dflags a -> do
213
214
a
214
215
215
216
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
-
280
217
------------------------------------------------------------------------------
281
218
282
219
graftWithM ::
@@ -468,13 +405,38 @@ annotate dflags ast = do
468
405
469
406
-- | Given an 'LHsDecl', compute its exactprint annotations.
470
407
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')
471
432
annotateDecl dflags ast = do
472
433
uniq <- show <$> uniqueSrcSpanT
473
434
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
475
436
let anns' = setPrecedingLines expr' 1 0 anns
476
437
pure (anns', expr')
477
438
------------------------------------------------------------------------------
439
+ ------------------------------------------------------------------------------
478
440
479
441
-- | Print out something 'Outputable'.
480
442
render :: Outputable a => DynFlags -> a -> String
0 commit comments