@@ -0,0 +1,235 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
4+
5+module Ormolu.Printer.Meat.Declaration.Value
6+ ( p_valDecl
7+ )
8+where
9+
10+import Bag (bagToList)
11+import Control.Monad
12+import Data.List (sortOn)
13+import GHC
14+import Ormolu.Printer.Combinators
15+import Ormolu.Printer.Meat.Common
16+import Ormolu.Printer.Meat.Declaration.Pat
17+import Ormolu.Printer.Meat.Declaration.Signature
18+import Ormolu.Utils
19+import SrcLoc (isOneLineSpan)
20+import qualified Data.List.NonEmpty as NE
21+
22+p_valDecl :: HsBindLR GhcPs GhcPs -> R ()
23+p_valDecl = line . p_valDecl'
24+
25+p_valDecl' :: HsBindLR GhcPs GhcPs -> R ()
26+p_valDecl' = \case
27+ FunBind funId funMatches _ _ _ -> p_funBind funId funMatches
28+ _ -> notImplemented "certain kinds of binding declarations"
29+
30+p_funBind
31+ :: Located RdrName -- ^
32+ -> MatchGroup GhcPs (LHsExpr GhcPs) -- ^
33+ -> R ()
34+p_funBind name mgroup =
35+ p_matchGroup (Function (unL name)) mgroup
36+
37+data MatchGroupStyle
38+ = Function RdrName
39+ | Case
40+ | Lambda
41+ | LambdaCase
42+
43+p_matchGroup
44+ :: MatchGroupStyle
45+ -> MatchGroup GhcPs (LHsExpr GhcPs)
46+ -> R ()
47+p_matchGroup style MG {..} =
48+ locatedVia Nothing mg_alts $
49+ newlineSep (located' (p_match style))
50+
51+p_match
52+ :: MatchGroupStyle
53+ -> Match GhcPs (LHsExpr GhcPs)
54+ -> R ()
55+p_match style Match {..} = do
56+ case style of
57+ Function name -> p_rdrName name
58+ _ -> return ()
59+ -- NOTE Normally, since patterns may be placed in a multi-line layout, it
60+ -- is necessary to bump indentation for the pattern group so it's more
61+ -- indented than function name. This in turn means that indentation for
62+ -- the body should also be bumped. Normally this would mean that bodies
63+ -- would start with two indentation steps applied, which is ugly, so we
64+ -- need to be a bit more clever here and bump indentation level only when
65+ -- pattern group is multiline.
66+ inci' <- case NE.nonEmpty m_pats of
67+ Nothing -> return id
68+ Just ne_pats -> do
69+ let combinedSpans = combineSrcSpans' $
70+ getSpan <$> ne_pats
71+ inci' = if isOneLineSpan combinedSpans
72+ then id
73+ else inci
74+ switchLayout combinedSpans $ do
75+ case style of
76+ Function _ -> breakpoint
77+ Case -> return ()
78+ Lambda -> txt "\\"
79+ LambdaCase -> return ()
80+ inci' (velt' (located' p_pat <$> m_pats))
81+ return inci'
82+ inci' $ do
83+ space
84+ let GRHSs {..} = m_grhss
85+ unless (length grhssGRHSs > 1) . txt $
86+ case style of
87+ Function _ -> "="
88+ _ -> "->"
89+ let combinedSpans = combineSrcSpans' $
90+ getGRHSSpan . unL <$> NE.fromList grhssGRHSs
91+ case style of
92+ Lambda -> breakpoint
93+ _ -> return ()
94+ switchLayout combinedSpans . inci $ do
95+ case style of
96+ Lambda -> return ()
97+ _ -> breakpoint
98+ newlineSep (located' p_grhs) grhssGRHSs
99+ unless (GHC.isEmptyLocalBinds (unL grhssLocalBinds)) $ do
100+ newline
101+ line (txt "where")
102+ inci (located grhssLocalBinds p_hsLocalBinds)
103+
104+getGRHSSpan :: GRHS GhcPs (LHsExpr GhcPs) -> SrcSpan
105+getGRHSSpan (GRHS _ body) = getSpan body
106+
107+p_grhs :: GRHS GhcPs (LHsExpr GhcPs) -> R ()
108+p_grhs (GRHS guards body) =
109+ case guards of
110+ [] -> p_body
111+ xs -> do
112+ txt "| "
113+ velt $ withSep comma (located' p_stmt) xs
114+ txt " ->"
115+ breakpoint
116+ p_body
117+ where
118+ p_body = located body p_hsExpr
119+
120+p_stmt :: Stmt GhcPs (LHsExpr GhcPs) -> R ()
121+p_stmt = \case
122+ LastStmt {} -> notImplemented "do notation"
123+ BindStmt {} -> notImplemented "do notation"
124+ ApplicativeStmt {} -> notImplemented "applicative stmt"
125+ BodyStmt body _ _ _ -> located body p_hsExpr
126+ LetStmt binds -> located binds p_hsLocalBinds
127+ ParStmt {} -> notImplemented "ParStmt"
128+ TransStmt {} -> notImplemented "TransStmt"
129+ RecStmt {} -> notImplemented "RecStmt"
130+
131+p_hsLocalBinds :: HsLocalBindsLR GhcPs GhcPs -> R ()
132+p_hsLocalBinds = \case
133+ HsValBinds (ValBindsIn bag lsigs) -> do
134+ let ssStart = either
135+ (srcSpanStart . getSpan)
136+ (srcSpanStart . getSpan)
137+ items =
138+ (Left <$> bagToList bag) ++ (Right <$> lsigs)
139+ p_item (Left x) = located x p_valDecl'
140+ p_item (Right x) = located x p_sigDecl'
141+ newlineSep p_item (sortOn ssStart items)
142+ HsValBinds _ -> notImplemented "HsValBinds"
143+ HsIPBinds _ -> notImplemented "HsIPBinds"
144+ EmptyLocalBinds -> return ()
145+
146+p_hsExpr :: HsExpr GhcPs -> R ()
147+p_hsExpr = \case
148+ HsVar name -> located name p_rdrName'
149+ HsUnboundVar _ -> notImplemented "HsUnboundVar"
150+ HsConLikeOut _ -> notImplemented "HsConLikeOut"
151+ HsRecFld x ->
152+ case x of
153+ Unambiguous name _ -> located name p_rdrName'
154+ Ambiguous name _ -> located name p_rdrName'
155+ HsOverLabel _ _ -> notImplemented "HsOverLabel"
156+ HsIPVar (HsIPName name) -> atom name
157+ HsOverLit v -> atom (ol_val v)
158+ HsLit lit -> atom lit
159+ HsLam mgroup ->
160+ p_matchGroup Lambda mgroup
161+ HsLamCase mgroup -> do
162+ txt "\\case"
163+ newline
164+ inci (p_matchGroup LambdaCase mgroup)
165+ HsApp f x -> do
166+ located f p_hsExpr
167+ breakpoint
168+ inci (located x p_hsExpr)
169+ HsAppType {} -> notImplemented "HsAppType"
170+ HsAppTypeOut {} -> notImplemented "HsAppTypeOut"
171+ OpApp x op _ y -> do
172+ located x p_hsExpr
173+ breakpoint
174+ inci $ do
175+ located op p_hsExpr
176+ space
177+ located y p_hsExpr
178+ NegApp e _ -> do
179+ txt "-"
180+ located e p_hsExpr
181+ HsPar e -> parens (located e p_hsExpr)
182+ SectionL {} -> notImplemented "SectionL"
183+ SectionR {} -> notImplemented "SectionR"
184+ ExplicitTuple {} -> notImplemented "ExplicitTuple"
185+ ExplicitSum {} -> notImplemented "ExplicitSum"
186+ HsCase e mgroup -> do
187+ txt "case "
188+ located e p_hsExpr
189+ txt " of"
190+ breakpoint
191+ inci (p_matchGroup Case mgroup)
192+ HsIf _ if' then' else' -> do
193+ txt "if "
194+ located if' p_hsExpr
195+ breakpoint
196+ inci (txt "then ")
197+ located then' p_hsExpr
198+ breakpoint
199+ inci (txt "else ")
200+ located else' p_hsExpr
201+ HsMultiIf {} -> notImplemented "MulitiIf"
202+ HsLet localBinds e -> do
203+ txt "let "
204+ inci (located localBinds p_hsLocalBinds)
205+ breakpoint
206+ txt "in "
207+ located e p_hsExpr
208+ HsDo {} -> notImplemented "HsDo"
209+ ExplicitList _ _ xs -> do
210+ brackets $ velt (withSep comma (located' p_hsExpr) xs)
211+ ExplicitPArr {} -> notImplemented "ExplicitPArr"
212+ RecordCon {} -> notImplemented "RecordCon"
213+ RecordUpd {} -> notImplemented "RecordUpd"
214+ ExprWithTySig {} -> notImplemented "ExprWithTySig"
215+ ExprWithTySigOut {} -> notImplemented "ExprWithTySigOut"
216+ ArithSeq {} -> notImplemented "ArithSeq"
217+ PArrSeq {} -> notImplemented "PArrSeq"
218+ HsSCC {} -> notImplemented "HsSCC"
219+ HsCoreAnn {} -> notImplemented "HsCoreAnn"
220+ HsBracket {} -> notImplemented "HsBracket"
221+ HsRnBracketOut {} -> notImplemented "HsRnBracketOut"
222+ HsTcBracketOut {} -> notImplemented "HsTcBracketOut"
223+ HsSpliceE {} -> notImplemented "HsSpliceE"
224+ HsProc {} -> notImplemented "HsProc"
225+ HsStatic {} -> notImplemented "HsStatic"
226+ HsArrApp {} -> notImplemented "HsArrApp"
227+ HsArrForm {} -> notImplemented "HsArrForm"
228+ HsTick {} -> notImplemented "HsTick"
229+ HsBinTick {} -> notImplemented "HsBinTick"
230+ HsTickPragma {} -> notImplemented "HsTickPragma"
231+ EWildPat -> notImplemented "EWildPat"
232+ EAsPat {} -> notImplemented "EAsPat"
233+ EViewPat {} -> notImplemented "EViewPat"
234+ ELazyPat {} -> notImplemented "ELazyPat"
235+ HsWrap {} -> notImplemented "HsWrap"