fourmolu-0.9.0.0: src/Ormolu/Printer/Meat/Declaration/Class.hs
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
-- | Rendering of type class declarations.
module Ormolu.Printer.Meat.Declaration.Class
( p_classDecl,
)
where
import Control.Arrow
import Control.Monad
import Data.Foldable
import Data.Function (on)
import Data.List (sortBy)
import Data.Maybe
import GHC.Hs
import GHC.Types.Fixity
import GHC.Types.Name.Reader
import GHC.Types.SrcLoc
import Ormolu.Config
import Ormolu.Printer.Combinators
import Ormolu.Printer.Meat.Common
import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration
import Ormolu.Printer.Meat.Type
p_classDecl ::
Maybe (LHsContext GhcPs) ->
LocatedN RdrName ->
LHsQTyVars GhcPs ->
LexicalFixity ->
[LHsFunDep GhcPs] ->
[LSig GhcPs] ->
LHsBinds GhcPs ->
[LFamilyDecl GhcPs] ->
[LTyFamDefltDecl GhcPs] ->
[LDocDecl GhcPs] ->
R ()
p_classDecl ctx name HsQTvs {..} fixity fdeps csigs cdefs cats catdefs cdocs = do
let variableSpans = getLocA <$> hsq_explicit
signatureSpans = getLocA name : variableSpans
dependencySpans = getLocA <$> fdeps
combinedSpans = maybeToList (getLocA <$> ctx) ++ signatureSpans ++ dependencySpans
-- GHC's AST does not necessarily store each kind of element in source
-- location order. This happens because different declarations are stored
-- in different lists. Consequently, to get all the declarations in proper
-- order, they need to be manually sorted.
sigs = (getLocA &&& fmap (SigD NoExtField)) <$> csigs
vals = (getLocA &&& fmap (ValD NoExtField)) <$> toList cdefs
tyFams = (getLocA &&& fmap (TyClD NoExtField . FamDecl NoExtField)) <$> cats
docs = (getLocA &&& fmap (DocD NoExtField)) <$> cdocs
tyFamDefs =
( getLocA &&& fmap (InstD NoExtField . TyFamInstD NoExtField)
)
<$> catdefs
allDecls =
snd <$> sortBy (leftmost_smallest `on` fst) (sigs <> vals <> tyFams <> tyFamDefs <> docs)
txt "class"
switchLayout combinedSpans $ do
breakpoint
inci $ do
for_ ctx p_classContext
switchLayout signatureSpans $
p_infixDefHelper
(isInfix fixity)
True
(p_rdrName name)
(located' p_hsTyVarBndr <$> hsq_explicit)
inci (p_classFundeps fdeps)
unless (null allDecls) $ do
breakpoint
txt "where"
unless (null allDecls) $ do
breakpoint -- Ensure whitespace is added after where clause.
inci (p_hsDeclsRespectGrouping Associated allDecls)
p_classContext :: LHsContext GhcPs -> R ()
p_classContext ctx = unless (null (unLoc ctx)) $ do
located ctx p_hsContext
space
darrow
breakpoint
p_classFundeps :: [LHsFunDep GhcPs] -> R ()
p_classFundeps fdeps = unless (null fdeps) $ do
breakpoint
txt "|"
space
inci' $ sep commaDel (sitcc . located' p_funDep) fdeps
where
inci' x =
getPrinterOpt poCommaStyle >>= \case
Leading -> id x
Trailing -> inci x
p_funDep :: FunDep GhcPs -> R ()
p_funDep (FunDep _ before after) = do
sep space p_rdrName before
space
rarrow
space
sep space p_rdrName after
----------------------------------------------------------------------------
-- Helpers
isInfix :: LexicalFixity -> Bool
isInfix = \case
Infix -> True
Prefix -> False