@@ -0,0 +1,94 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
4+
5+-- | Rendering of type class declarations.
6+
7+module Ormolu.Printer.Meat.Declaration.Class
8+ ( p_classDecl
9+ )
10+where
11+
12+import Class
13+import Control.Arrow
14+import Control.Monad
15+import Data.Foldable
16+import Data.Function
17+import Data.List (sortBy)
18+import Ormolu.Printer.Combinators
19+import Ormolu.Printer.Meat.Declaration.Signature
20+import Ormolu.Printer.Meat.Declaration.Value
21+import Ormolu.Printer.Meat.Declaration.TypeFamily
22+import Ormolu.Printer.Meat.Common
23+import Ormolu.Printer.Meat.Type
24+import Ormolu.Utils
25+import GHC
26+import RdrName (RdrName (..))
27+import SrcLoc (Located, combineSrcSpans)
28+
29+p_classDecl
30+ :: LHsContext GhcPs
31+ -> Located RdrName
32+ -> LHsQTyVars GhcPs
33+ -> [Located (FunDep (Located RdrName))]
34+ -> [LSig GhcPs]
35+ -> LHsBinds GhcPs
36+ -> [LFamilyDecl GhcPs]
37+ -> [LTyFamDefltEqn GhcPs]
38+ -> R ()
39+p_classDecl ctx name tvars fdeps csigs cdefs cats catdefs = do
40+ let HsQTvs {..} = tvars
41+ combinedSpans =
42+ getLoc ctx `combineSrcSpans`
43+ getLoc name `combineSrcSpans`
44+ foldr (combineSrcSpans . getLoc) noSrcSpan hsq_explicit `combineSrcSpans`
45+ foldr (combineSrcSpans . getLoc) noSrcSpan fdeps
46+ txt "class "
47+ sitcc $ do
48+ switchLayout combinedSpans $ do
49+ unless (null (unLoc ctx)) $ do
50+ located ctx p_hsContext
51+ breakpoint
52+ txt "=> "
53+ p_rdrName name
54+ unless (null hsq_explicit) space
55+ spaceSep (located' p_hsTyVarBndr) hsq_explicit
56+ unless (null fdeps) $ do
57+ breakpoint
58+ txt "| "
59+ velt (withSep comma (located' p_funDep) fdeps)
60+ -- GHC's AST does not necessarily store each kind of element in source
61+ -- location order. This happens because different declarations are stored in
62+ -- different lists. Consequently, to get all the declarations in proper order,
63+ -- they need to be manually sorted.
64+ let sigs = (getLoc &&& located' p_sigDecl) <$> csigs
65+ defs = (getLoc &&& located' p_valDecl) <$> cdefs
66+ tyfam_decls = (getLoc &&& located' (p_famDecl Associated)) <$> cats
67+ tyfam_defs = (getLoc &&& located' p_famDefDecl) <$> catdefs
68+ decls =
69+ snd <$>
70+ sortBy
71+ (compare `on` fst)
72+ (sigs <> toList defs <> tyfam_decls <> tyfam_defs)
73+ if not (null decls)
74+ then do
75+ txt " where"
76+ newline
77+ inci (sequence_ decls)
78+ else newline
79+
80+p_famDefDecl :: TyFamDefltEqn GhcPs -> R ()
81+p_famDefDecl FamEqn {..} = do
82+ txt "type"
83+ breakpoint
84+ let eqn = FamEqn { feqn_pats = tyVarsToTypes feqn_pats, .. }
85+ hsib = HsIB { hsib_ext = NoExt, hsib_body = eqn }
86+ inci (p_tyFamInstEqn hsib)
87+ newline
88+p_famDefDecl XFamEqn {} = notImplemented "XFamEqn"
89+
90+p_funDep :: FunDep (Located RdrName) -> R ()
91+p_funDep (before, after) = do
92+ spaceSep p_rdrName before
93+ txt " -> "
94+ spaceSep p_rdrName after