on master help sign in
Make function arguments look more consistent

This change modifies the ‘HsApp’ printer to handle all function parameters at once instead of following the AST order. This allows us to consistently put each function argument on separate lines. Previously, when printing the function f a b c, the AST would look like (((f a) b) c), which would cause inconsistencies regarding to newlines (imagine f a\n b). Otherwise I tried to preserve the same behaviour as the previous printer, and added a few tests. This only changes the ‘p_hsExpr’ function, rest of the changes are caused by the formatting change.

commit3abadaefa5e190ff346f9aeb309465ac890495c2 authorUtku Demir <me@utdemir.com> dateTue 8 Oct 2019, 12:27 (7 years ago) parent1d3eeba
12 files changed+89−26
data/examples/declaration/rewrite-rule/basic1-out.hs+2−1 data/examples/declaration/rewrite-rule/phase-out.hs+4−2 data/examples/declaration/value/function/application-out.hs+17 data/examples/declaration/value/function/application.hs+12 data/examples/declaration/value/function/block-arguments-out.hs+2 data/examples/declaration/value/function/block-arguments.hs+2 data/examples/declaration/value/function/static-pointers-out.hs+2−1 src/Ormolu/Exception.hs+3−1 src/Ormolu/Parser/CommentStream.hs+2−1 src/Ormolu/Printer.hs+2−1 src/Ormolu/Printer/Meat/Declaration/Value.hs+39−18 src/Ormolu/Printer/Meat/Type.hs+2−1
data/examples/declaration/rewrite-rule/basic1-out.hs+2−1
@@ -10,7 +10,8 @@
1010
1111{-# RULES
1212"map/map"
13− map f
13+ map
14+ f
1415 (map g xs) =
1516 map
1617 (f . g)
data/examples/declaration/rewrite-rule/phase-out.hs+4−2
@@ -1,6 +1,7 @@
11{-# RULES
22"map/map" [2]
3− map f
3+ map
4+ f
45 (map g xs) =
56 map
67 (f . g)
@@ -9,7 +10,8 @@
910
1011{-# RULES
1112"map/map" [1] forall x y z.
12− map f
13+ map
14+ f
1315 (map g xs) =
1416 map
1517 (f . g)
data/examples/declaration/value/function/application-out.hsnew file+17
@@ -0,0 +1,17 @@
1+foo =
2+ f1
3+ p1
4+ p2
5+ p3
6+
7+foo' =
8+ f2
9+ p1
10+ p2
11+ p3
12+
13+foo'' =
14+ f3
15+ p1
16+ p2
17+ p3
data/examples/declaration/value/function/application.hsnew file+12
@@ -0,0 +1,12 @@
1+foo =
2+ f1
3+ p1
4+ p2 p3
5+
6+foo' = f2 p1
7+ p2
8+ p3
9+
10+foo'' =
11+ f3 p1 p2
12+ p3
data/examples/declaration/value/function/block-arguments-out.hs+2
@@ -25,3 +25,5 @@ f7 = foo \x -> y
2525
2626f8 = foo \x ->
2727 y
28+
29+f9 = foo do { bar } baz
data/examples/declaration/value/function/block-arguments.hs+2
@@ -21,3 +21,5 @@ f7 = foo \x -> y
2121
2222f8 = foo \x ->
2323 y
24+
25+f9 = foo do { bar } baz
data/examples/declaration/value/function/static-pointers-out.hs+2−1
@@ -14,6 +14,7 @@ bar =
1414baz :: StaticPtr Bool
1515baz =
1616 static
17− ( fun 1
17+ ( fun
18+ 1
1819 2
1920 )
src/Ormolu/Exception.hs+3−1
@@ -51,7 +51,9 @@ instance Exception OrmoluException where
5151 )
5252 ++ ["Please, consider reporting the bug."]
5353 OrmoluNonIdempotentOutput loc left right ->
54− showParsingErr "Formatting is not idempotent:" loc
54+ showParsingErr
55+ "Formatting is not idempotent:"
56+ loc
5557 ["before: " ++ show left, "after: " ++ show right]
5658 ++ "Please, consider reporting the bug.\n"
5759
src/Ormolu/Parser/CommentStream.hs+2−1
@@ -62,7 +62,8 @@ mkCommentStream extraComments pstate =
6262 mapMaybe toRealSpan $
6363 extraComments
6464 ++ mapMaybe (liftMaybe . fmap unAnnotationComment) (GHC.comment_q pstate)
65− ++ concatMap (mapMaybe (liftMaybe . fmap unAnnotationComment) . snd)
65+ ++ concatMap
66+ (mapMaybe (liftMaybe . fmap unAnnotationComment) . snd)
6667 (GHC.annotations_comments pstate)
6768
6869-- | Test whether a 'Comment' looks like a Haddock following a definition,
src/Ormolu/Printer.hs+2−1
@@ -21,7 +21,8 @@ printModule ::
2121 -- | Resulting rendition
2222 Text
2323printModule ParseResult {..} =
24− runR (p_hsModule prExtensions prParsedSource)
24+ runR
25+ (p_hsModule prExtensions prParsedSource)
2526 (mkSpanStream prParsedSource)
2627 prCommentStream
2728 prAnns
src/Ormolu/Printer/Meat/Declaration/Value.hs+39−18
@@ -19,7 +19,7 @@ import Data.Bool (bool)
1919import Data.Char (isPunctuation, isSymbol)
2020import Data.Data hiding (Infix, Prefix)
2121import Data.List (intersperse, sortOn)
22−import Data.List.NonEmpty (NonEmpty ((:|)))
22+import Data.List.NonEmpty ((<|), NonEmpty ((:|)))
2323import qualified Data.List.NonEmpty as NE
2424import Data.Text (Text)
2525import qualified Data.Text as Text
@@ -237,7 +237,8 @@ p_match' placer render style isInfix strictness m_pats m_grhss = do
237237 combineSrcSpans' $
238238 getGRHSSpan . unLoc <$> NE.fromList grhssGRHSs
239239 patGrhssSpan =
240− maybe grhssSpan
240+ maybe
241+ grhssSpan
241242 (combineSrcSpans grhssSpan . srcLocSpan)
242243 endOfPats
243244 placement =
@@ -525,25 +526,44 @@ p_hsExpr' s = \case
525526 breakpoint
526527 inci (p_matchGroup LambdaCase mgroup)
527528 HsApp NoExt f x -> do
528− -- We hang only the last function argument. In order to do this, we only
529− -- call 'placeHanging' on the topmost 'HsApp', and then use
530− -- 'p_withoutHanging' for the descendants.
531− let p_withoutHanging (HsApp NoExt f' x') = do
529+ let -- In order to format function applications with multiple parameters
530+ -- nicer, traverse the AST to gather the function and all the
531+ -- parameters together.
532+ gatherArgs f' knownArgs =
532533 case f' of
533− L _ (HsApp _ _ _) -> located f' p_withoutHanging
534− _ -> located f' (p_hsExpr' s)
535− breakpoint
536− inci $ located x' p_hsExpr
537− p_withoutHanging e = p_hsExpr e
538− -- Only use the hanging placement if the function spans a single
534+ L _ (HsApp _ l r) -> gatherArgs l (r <| knownArgs)
535+ _ -> (f', knownArgs)
536+ (func, args) = gatherArgs f (x :| [])
537+ -- We need to handle the last argument specially if it is a
538+ -- hanging construct, so separate it from the rest.
539+ (initp, lastp) = (NE.init args, NE.last args)
540+ initSpan = combineSrcSpans' $ getLoc f :| map getLoc initp
541+ -- Hang the last argument only if the initial arguments spans one
539542 -- line.
540543 placement =
541− if isOneLineSpan (getLoc f)
542− then exprPlacement (unLoc x)
544+ if isOneLineSpan initSpan
545+ then exprPlacement (unLoc lastp)
543546 else Normal
544− useBraces (located f p_withoutHanging)
545− placeHanging placement $
546− located x p_hsExpr
547+ -- If the last argument is not hanging, just separate every argument as
548+ -- usual. If it is hanging, print the initial arguments and hang the
549+ -- last one. Also, use braces around the every argument except the last
550+ -- one.
551+ case placement of
552+ Normal -> do
553+ useBraces $ do
554+ located func (p_hsExpr' s)
555+ breakpoint
556+ inci $ sep breakpoint (located' p_hsExpr) initp
557+ inci $ do
558+ unless (null initp) breakpoint
559+ located lastp p_hsExpr
560+ Hanging -> do
561+ useBraces . switchLayout [initSpan] $ do
562+ located func (p_hsExpr' s)
563+ breakpoint
564+ sep breakpoint (located' p_hsExpr) initp
565+ placeHanging placement $
566+ located lastp p_hsExpr
547567 HsAppType a e -> do
548568 located e p_hsExpr
549569 breakpoint
@@ -1089,7 +1109,8 @@ p_stringLit src =
10891109 zipPrevNext :: [a] -> [(Maybe a, a, Maybe a)]
10901110 zipPrevNext xs =
10911111 let z =
1092− zip (zip (Nothing : map Just xs) xs)
1112+ zip
1113+ (zip (Nothing : map Just xs) xs)
10931114 (map Just (tail xs) ++ repeat Nothing)
10941115 in map (\((p, x), n) -> (p, x, n)) z
10951116 orig (_, x, _) = x
src/Ormolu/Printer/Meat/Type.hs+2−1
@@ -191,7 +191,8 @@ p_conDeclField :: ConDeclField GhcPs -> R ()
191191p_conDeclField ConDeclField {..} = do
192192 mapM_ (p_hsDocString Pipe True) cd_fld_doc
193193 sitcc $
194− sep (comma >> breakpoint)
194+ sep
195+ (comma >> breakpoint)
195196 (located' (p_rdrName . rdrNameFieldOcc))
196197 cd_fld_names
197198 space