diff options
Diffstat (limited to 'src/Haddock/Backends/Xhtml/Decl.hs')
| -rw-r--r-- | src/Haddock/Backends/Xhtml/Decl.hs | 874 | 
1 files changed, 874 insertions, 0 deletions
| diff --git a/src/Haddock/Backends/Xhtml/Decl.hs b/src/Haddock/Backends/Xhtml/Decl.hs new file mode 100644 index 00000000..db6d90a0 --- /dev/null +++ b/src/Haddock/Backends/Xhtml/Decl.hs @@ -0,0 +1,874 @@ +----------------------------------------------------------------------------- +-- | +-- Module      :  Haddock.Backends.Html.Decl +-- Copyright   :  (c) Simon Marlow   2003-2006, +--                    David Waern    2006-2009, +--                    Mark Lentczner 2010 +-- License     :  BSD-like +-- +-- Maintainer  :  haddock@projects.haskell.org +-- Stability   :  experimental +-- Portability :  portable +----------------------------------------------------------------------------- + +module Haddock.Backends.Xhtml.Decl where + +import Haddock.Backends.Xhtml.DocMarkup +import Haddock.Backends.Xhtml.Layout +import Haddock.Backends.Xhtml.Names +import Haddock.Backends.Xhtml.Types +import Haddock.Backends.Xhtml.Util +import Haddock.GhcUtils +import Haddock.Types + +import           Control.Monad         ( join ) +import qualified Data.Map as Map +import           Data.Maybe +import           Text.XHtml hiding     ( name, title, p, quote ) + +import BasicTypes            ( IPName(..), Boxity(..) ) +import GHC +import Name +import Outputable            ( ppr, showSDoc, Outputable ) + + +-- TODO: use DeclInfo DocName or something +ppDecl' :: Bool -> LinksInfo -> LHsDecl DocName ->  +          DocForDecl DocName -> [DocInstance DocName] -> [(DocName, DocForDecl DocName)] -> Bool -> Html +ppDecl' s k l m i d u = vanillaTable << ppDecl s k l m i d u + +ppDecl :: Bool -> LinksInfo -> LHsDecl DocName ->  +          DocForDecl DocName -> [DocInstance DocName] -> [(DocName, DocForDecl DocName)] -> Bool -> HtmlTable +ppDecl summ links (L loc decl) (mbDoc, fnArgsDoc) instances subdocs unicode = case decl of +  TyClD d@(TyFamily {})          -> ppTyFam summ False links loc mbDoc d unicode +  TyClD d@(TyData {}) +    | Nothing <- tcdTyPats d     -> ppDataDecl summ links instances subdocs loc mbDoc d unicode +    | Just _  <- tcdTyPats d     -> ppDataInst summ links loc mbDoc d  +  TyClD d@(TySynonym {}) +    | Nothing <- tcdTyPats d     -> ppTySyn summ links loc (mbDoc, fnArgsDoc) d unicode +    | Just _  <- tcdTyPats d     -> ppTyInst summ False links loc mbDoc d unicode +  TyClD d@(ClassDecl {})         -> ppClassDecl summ links instances loc mbDoc subdocs d unicode +  SigD (TypeSig (L _ n) (L _ t)) -> ppFunSig summ links loc (mbDoc, fnArgsDoc) n t unicode +  ForD d                         -> ppFor summ links loc (mbDoc, fnArgsDoc) d unicode +  InstD _                        -> emptyTable +  _                              -> error "declaration not supported by ppDecl" + +ppFunSig :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName -> +            DocName -> HsType DocName -> Bool -> HtmlTable +ppFunSig summary links loc doc docname typ unicode = +  ppTypeOrFunSig summary links loc docname typ doc +    (ppTypeSig summary occname typ unicode, ppBinder False occname, dcolon unicode) unicode +  where +    occname = docNameOcc docname + +ppTypeOrFunSig :: Bool -> LinksInfo -> SrcSpan -> DocName -> HsType DocName -> +                  DocForDecl DocName -> (Html, Html, Html) -> Bool -> HtmlTable +ppTypeOrFunSig summary links loc docname typ (doc, argDocs) (pref1, pref2, sep) unicode +  | summary || Map.null argDocs = declWithDoc summary links loc docname doc pref1 +  | otherwise = topDeclBox links loc docname pref2 </> +    (tda [theclass "body"] << vanillaTable <<  ( +      do_args 0 sep typ </> +        (case doc of +          Just d -> ndocBox (docToHtml d) +          Nothing -> emptyTable) +        )) +  where  +    argDocHtml n = case Map.lookup n argDocs of +                    Just adoc -> docToHtml adoc +                    Nothing -> noHtml + +    do_largs n leader (L _ t) = do_args n leader t   +    do_args :: Int -> Html -> (HsType DocName) -> HtmlTable +    do_args n leader (HsForAllTy Explicit tvs lctxt ltype) +      = (argBox ( +          leader <+>  +          hsep (forallSymbol unicode : ppTyVars tvs ++ [dot]) <+> +          ppLContextNoArrow lctxt unicode) +            <-> rdocBox noHtml) </>  +            do_largs n (darrow unicode) ltype +    do_args n leader (HsForAllTy Implicit _ lctxt ltype) +      | not (null (unLoc lctxt)) +      = (argBox (leader <+> ppLContextNoArrow lctxt unicode) +          <-> rdocBox noHtml) </>  +          do_largs n (darrow unicode) ltype +      -- if we're not showing any 'forall' or class constraints or +      -- anything, skip having an empty line for the context. +      | otherwise +      = do_largs n leader ltype +    do_args n leader (HsFunTy lt r) +      = (argBox (leader <+> ppLFunLhType unicode lt) <-> rdocBox (argDocHtml n)) +          </> do_largs (n+1) (arrow unicode) r +    do_args n leader t +      = argBox (leader <+> ppType unicode t) <-> rdocBox (argDocHtml n) + + +ppTyVars :: [LHsTyVarBndr DocName] -> [Html] +ppTyVars tvs = map ppTyName (tyvarNames tvs) + + +tyvarNames :: [LHsTyVarBndr DocName] -> [Name] +tyvarNames = map (getName . hsTyVarName . unLoc) +   + +ppFor :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName -> ForeignDecl DocName -> Bool -> HtmlTable +ppFor summary links loc doc (ForeignImport (L _ name) (L _ typ) _) unicode +  = ppFunSig summary links loc doc name typ unicode +ppFor _ _ _ _ _ _ = error "ppFor" + + +-- we skip type patterns for now +ppTySyn :: Bool -> LinksInfo -> SrcSpan -> DocForDecl DocName -> TyClDecl DocName -> Bool -> HtmlTable +ppTySyn summary links loc doc (TySynonym (L _ name) ltyvars _ ltype) unicode +  = ppTypeOrFunSig summary links loc name (unLoc ltype) doc  +                   (full, hdr, spaceHtml +++ equals) unicode +  where +    hdr  = hsep ([keyword "type", ppBinder summary occ] ++ ppTyVars ltyvars) +    full = hdr <+> equals <+> ppLType unicode ltype +    occ  = docNameOcc name +ppTySyn _ _ _ _ _ _ = error "declaration not supported by ppTySyn" + + +ppTypeSig :: Bool -> OccName -> HsType DocName  -> Bool -> Html +ppTypeSig summary nm ty unicode = ppBinder summary nm <+> dcolon unicode <+> ppType unicode ty + + +ppTyName :: Name -> Html +ppTyName name +  | isNameSym name = parens (ppName name) +  | otherwise = ppName name + + +-------------------------------------------------------------------------------- +-- Type families +-------------------------------------------------------------------------------- + + +ppTyFamHeader :: Bool -> Bool -> TyClDecl DocName -> Bool -> Html +ppTyFamHeader summary associated decl unicode = + +  (case tcdFlavour decl of +     TypeFamily +       | associated -> keyword "type" +       | otherwise  -> keyword "type family" +     DataFamily +       | associated -> keyword "data" +       | otherwise  -> keyword "data family" +  ) <+> + +  ppTyClBinderWithVars summary decl <+> + +  case tcdKind decl of +    Just kind -> dcolon unicode  <+> ppKind kind  +    Nothing -> empty + + +ppTyFam :: Bool -> Bool -> LinksInfo -> SrcSpan -> Maybe (Doc DocName) -> +              TyClDecl DocName -> Bool -> HtmlTable +ppTyFam summary associated links loc mbDoc decl unicode +   +  | summary = declWithDoc summary links loc docname mbDoc  +              (ppTyFamHeader True associated decl unicode) +   +  | associated, isJust mbDoc         = header_ </> bodyBox << doc  +  | associated                       = header_  +  | null instances, isJust mbDoc     = header_ </> bodyBox << doc +  | null instances                   = header_ +  | isJust mbDoc                     = header_ </> bodyBox << (doc </> instancesBit) +  | otherwise                        = header_ </> bodyBox << instancesBit + +  where +    docname = tcdName decl + +    header_ = topDeclBox links loc docname (ppTyFamHeader summary associated decl unicode) + +    doc = ndocBox . docToHtml . fromJust $ mbDoc  + +    instId = collapseId (getName docname) + +    instancesBit = instHdr instId </> +          tda [theclass "body"] <<  +            collapsed thediv instId ( +              spacedTable1 << ( +                aboves (map (ppDocInstance unicode) instances) +              ) +            ) + +    -- TODO: get the instances +    instances = [] + + +-------------------------------------------------------------------------------- +-- Indexed data types +-------------------------------------------------------------------------------- + + +ppDataInst :: a +ppDataInst = undefined + + +-------------------------------------------------------------------------------- +-- Indexed newtypes +-------------------------------------------------------------------------------- + +-- TODO +-- ppNewTyInst = undefined + + +-------------------------------------------------------------------------------- +-- Indexed types +-------------------------------------------------------------------------------- + +  +ppTyInst :: Bool -> Bool -> LinksInfo -> SrcSpan -> Maybe (Doc DocName) -> +            TyClDecl DocName -> Bool -> HtmlTable +ppTyInst summary associated links loc mbDoc decl unicode +   +  | summary = declWithDoc summary links loc docname mbDoc +              (ppTyInstHeader True associated decl unicode) +   +  | isJust mbDoc = header_ </> bodyBox << doc  +  | otherwise    = header_ + +  where +    docname = tcdName decl + +    header_ = topDeclBox links loc docname (ppTyInstHeader summary associated decl unicode) + +    doc = case mbDoc of +      Just d -> ndocBox (docToHtml d) +      Nothing -> emptyTable + + +ppTyInstHeader :: Bool -> Bool -> TyClDecl DocName -> Bool -> Html +ppTyInstHeader _ _ decl unicode = +  keyword "type instance" <+> +  ppAppNameTypes (tcdName decl) typeArgs unicode +  where +    typeArgs = map unLoc . fromJust . tcdTyPats $ decl + + +-------------------------------------------------------------------------------- +-- Associated Types +-------------------------------------------------------------------------------- +     + +ppAssocType :: Bool -> LinksInfo -> DocForDecl DocName -> LTyClDecl DocName -> Bool -> HtmlTable +ppAssocType summ links doc (L loc decl) unicode =  +  case decl of +    TyFamily  {} -> ppTyFam summ True links loc (fst doc) decl unicode +    TySynonym {} -> ppTySyn summ links loc doc decl unicode +    _            -> error "declaration type not supported by ppAssocType"  + + +-------------------------------------------------------------------------------- +-- TyClDecl helpers +-------------------------------------------------------------------------------- + + +-- | Print a type family / newtype / data / class binder and its variables  +ppTyClBinderWithVars :: Bool -> TyClDecl DocName -> Html +ppTyClBinderWithVars summ decl =  +  ppAppDocNameNames summ (unLoc $ tcdLName decl) (tyvarNames $ tcdTyVars decl) + + +-------------------------------------------------------------------------------- +-- Type applications +-------------------------------------------------------------------------------- + + +-- | Print an application of a DocName and a list of HsTypes +ppAppNameTypes :: DocName -> [HsType DocName] -> Bool -> Html +ppAppNameTypes n ts unicode = ppTypeApp n ts ppDocName (ppParendType unicode) + + +-- | Print an application of a DocName and a list of Names  +ppAppDocNameNames :: Bool -> DocName -> [Name] -> Html +ppAppDocNameNames summ n ns =  +  ppTypeApp n ns (ppBinder summ . docNameOcc) ppTyName + + +-- | General printing of type applications +ppTypeApp :: DocName -> [a] -> (DocName -> Html) -> (a -> Html) -> Html +ppTypeApp n (t1:t2:rest) ppDN ppT +  | operator, not . null $ rest = parens opApp <+> hsep (map ppT rest) +  | operator                    = opApp +  where +    operator = isNameSym . getName $ n +    opApp = ppT t1 <+> ppDN n <+> ppT t2 + +ppTypeApp n ts ppDN ppT = ppDN n <+> hsep (map ppT ts) + + +------------------------------------------------------------------------------- +-- Contexts  +------------------------------------------------------------------------------- + + +ppLContext, ppLContextNoArrow :: Located (HsContext DocName) -> Bool -> Html +ppLContext        = ppContext        . unLoc +ppLContextNoArrow = ppContextNoArrow . unLoc + + +ppContextNoArrow :: HsContext DocName -> Bool -> Html +ppContextNoArrow []  _ = empty +ppContextNoArrow cxt unicode = pp_hs_context (map unLoc cxt) unicode + + +ppContextNoLocs :: [HsPred DocName] -> Bool -> Html +ppContextNoLocs []  _ = empty +ppContextNoLocs cxt unicode = pp_hs_context cxt unicode <+> darrow unicode + + +ppContext :: HsContext DocName -> Bool -> Html +ppContext cxt unicode = ppContextNoLocs (map unLoc cxt) unicode + + +pp_hs_context :: [HsPred DocName] -> Bool -> Html +pp_hs_context []  _       = empty +pp_hs_context [p] unicode = ppPred unicode p +pp_hs_context cxt unicode = parenList (map (ppPred unicode) cxt) + + +ppPred :: Bool -> HsPred DocName -> Html +ppPred unicode (HsClassP n ts) = ppAppNameTypes n (map unLoc ts) unicode +ppPred unicode (HsEqualP t1 t2) = ppLType unicode t1 <+> toHtml "~" <+> ppLType unicode t2 +ppPred unicode (HsIParam (IPName n) t) +  = toHtml "?" +++ ppDocName n <+> dcolon unicode <+> ppLType unicode t + + +------------------------------------------------------------------------------- +-- Class declarations +------------------------------------------------------------------------------- + + +ppClassHdr :: Bool -> Located [LHsPred DocName] -> DocName +           -> [Located (HsTyVarBndr DocName)] -> [Located ([DocName], [DocName])] +           -> Bool -> Html +ppClassHdr summ lctxt n tvs fds unicode =  +  keyword "class"  +  <+> (if not . null . unLoc $ lctxt then ppLContext lctxt unicode else empty) +  <+> ppAppDocNameNames summ n (tyvarNames $ tvs) +        <+> ppFds fds unicode + + +ppFds :: [Located ([DocName], [DocName])] -> Bool -> Html +ppFds fds unicode = +  if null fds then noHtml else  +        char '|' <+> hsep (punctuate comma (map (fundep . unLoc) fds)) +  where +        fundep (vars1,vars2) = hsep (map ppDocName vars1) <+> arrow unicode <+> +                               hsep (map ppDocName vars2) + +ppShortClassDecl :: Bool -> LinksInfo -> TyClDecl DocName -> SrcSpan -> [(DocName, DocForDecl DocName)] -> Bool -> HtmlTable +ppShortClassDecl summary links (ClassDecl lctxt lname tvs fds sigs _ ats _) loc subdocs unicode =  +  if null sigs && null ats +    then (if summary then declBox else topDeclBox links loc nm) hdr +    else (if summary then declBox else topDeclBox links loc nm) (hdr <+> keyword "where") +            </>  +      ( +                                bodyBox << +                                        aboves +                                        ( +                                                [ ppAssocType summary links doc at unicode | at <- ats +                                                , let doc = lookupAnySubdoc (tcdName $ unL at) subdocs ]  ++ + +                                                [ ppFunSig summary links loc doc n typ unicode +                                                | L _ (TypeSig (L _ n) (L _ typ)) <- sigs +                                                , let doc = lookupAnySubdoc n subdocs ]  +                                        ) +                                ) +  where +    hdr = ppClassHdr summary lctxt (unLoc lname) tvs fds unicode +    nm  = unLoc lname +ppShortClassDecl _ _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl" +     + + +ppClassDecl :: Bool -> LinksInfo -> [DocInstance DocName] -> SrcSpan +            -> Maybe (Doc DocName) -> [(DocName, DocForDecl DocName)] +            -> TyClDecl DocName -> Bool -> HtmlTable +ppClassDecl summary links instances loc mbDoc subdocs +        decl@(ClassDecl lctxt lname ltyvars lfds lsigs _ ats _) unicode +  | summary = ppShortClassDecl summary links decl loc subdocs unicode +  | otherwise = classheader </> bodyBox << (classdoc </> body_ </> instancesBit) +  where  +    classheader +      | null lsigs = topDeclBox links loc nm (hdr unicode) +      | otherwise  = topDeclBox links loc nm (hdr unicode <+> keyword "where") + +    nm   = unLoc $ tcdLName decl + +    hdr = ppClassHdr summary lctxt (unLoc lname) ltyvars lfds +     +    classdoc = case mbDoc of +      Nothing -> emptyTable +      Just d -> ndocBox (docToHtml d) + +    body_ +      | null lsigs, null ats = emptyTable +      | null ats  = s8 </> methHdr </> bodyBox << methodTable +      | otherwise = s8 </> atHdr </> bodyBox << atTable </>  +                    s8 </> methHdr </> bodyBox << methodTable  +  +    methodTable = +      abovesSep s8 [ ppFunSig summary links loc doc n typ unicode +                   | L _ (TypeSig (L _ n) (L _ typ)) <- lsigs +                   , let doc = lookupAnySubdoc n subdocs ] + +    atTable = abovesSep s8 $ [ ppAssocType summary links doc at unicode | at <- ats +                             , let doc = lookupAnySubdoc (tcdName $ unL at) subdocs ] + +    instId = collapseId (getName nm) +    instancesBit +      | null instances = emptyTable +      | otherwise  +        =  s8 </> instHdr instId </> +           tda [theclass "body"] <<  +             collapsed thediv instId ( +               spacedTable1 << aboves (map (ppDocInstance unicode) instances) +             ) +ppClassDecl _ _ _ _ _ _ _ _ = error "declaration type not supported by ppShortClassDecl" + + +-- | Print a possibly commented instance. The instance header is printed inside +-- an 'argBox'. The comment is printed to the right of the box in normal comment +-- style. +ppDocInstance :: Bool -> DocInstance DocName -> HtmlTable +ppDocInstance unicode (instHead, maybeDoc) = +  argBox (ppInstHead unicode instHead) <-> maybeRDocBox maybeDoc + + +ppInstHead :: Bool -> InstHead DocName -> Html +ppInstHead unicode ([],   n, ts) = ppAppNameTypes n ts unicode +ppInstHead unicode (ctxt, n, ts) = ppContextNoLocs ctxt unicode <+> ppAppNameTypes n ts unicode + + +lookupAnySubdoc :: (Eq name1) => +                   name1 -> [(name1, DocForDecl name2)] -> DocForDecl name2 +lookupAnySubdoc n subdocs = case lookup n subdocs of +  Nothing -> noDocForDecl +  Just docs -> docs +       + + +-- ----------------------------------------------------------------------------- +-- Data & newtype declarations + + +-- TODO: print contexts +ppShortDataDecl :: Bool -> LinksInfo -> SrcSpan -> TyClDecl DocName -> Bool -> Html +ppShortDataDecl summary links loc dataDecl unicode + +  | [lcon] <- cons, ResTyH98 <- resTy =  +    ppDataHeader summary dataDecl unicode +    <+> equals <+> ppShortConstr summary (unLoc lcon) unicode + +  | [] <- cons = ppDataHeader summary dataDecl unicode + +  | otherwise = vanillaTable << ( +      case resTy of  +        ResTyH98 -> dataHeader </>  +          tda [theclass "body"] << vanillaTable << ( +            aboves (zipWith doConstr ('=':repeat '|') cons) +          ) +        ResTyGADT _ -> dataHeader </>  +          tda [theclass "body"] << vanillaTable << ( +            aboves (map doGADTConstr cons) +          ) +    ) +   +  where +    dataHeader =  +      (if summary then declBox else topDeclBox links loc docname) +      ((ppDataHeader summary dataDecl unicode) <+>  +      case resTy of ResTyGADT _ -> keyword "where"; _ -> empty) + +    doConstr c con = declBox (toHtml [c] <+> ppShortConstr summary (unLoc con) unicode) +    doGADTConstr con = declBox (ppShortConstr summary (unLoc con) unicode) + +    docname   = unLoc . tcdLName $ dataDecl +    cons      = tcdCons dataDecl +    resTy     = (con_res . unLoc . head) cons  + +ppDataDecl :: Bool -> LinksInfo -> [DocInstance DocName] -> +              [(DocName, DocForDecl DocName)] -> +              SrcSpan -> Maybe (Doc DocName) -> TyClDecl DocName -> Bool -> HtmlTable +ppDataDecl summary links instances subdocs loc mbDoc dataDecl unicode +   +  | summary = declWithDoc summary links loc docname mbDoc  +              (ppShortDataDecl summary links loc dataDecl unicode) +   +  | otherwise +      = (if validTable then (</>) else const) header_ $ +              tda [theclass "body"] << vanillaTable << ( +                      datadoc </>  +                      constrBit </> +                      instancesBit +        ) + + +  where +    docname   = unLoc . tcdLName $ dataDecl +    cons      = tcdCons dataDecl +    resTy     = (con_res . unLoc . head) cons  +       +    header_ = topDeclBox links loc docname (ppDataHeader summary dataDecl unicode +             <+> whereBit) + +    whereBit  +      | null cons = empty  +      | otherwise = case resTy of  +        ResTyGADT _ -> keyword "where" +        _ -> empty                          + +    constrTable +      | any isRecCon cons = spacedTable5 +      | otherwise         = spacedTable1 + +    datadoc = case mbDoc of +      Just doc -> ndocBox (docToHtml doc) +      Nothing -> emptyTable + +    constrBit  +      | null cons = emptyTable +      | otherwise = constrHdr </> (  +          tda [theclass "body"] << constrTable <<  +          aboves (map (ppSideBySideConstr subdocs unicode) cons) +        ) + +    instId = collapseId (getName docname) + +    instancesBit +      | null instances = emptyTable +      | otherwise  +        = instHdr instId </> +          tda [theclass "body"] <<  +          collapsed thediv instId ( +            spacedTable1 << aboves (map (ppDocInstance unicode) instances +            ) +          ) + +    validTable = isJust mbDoc || not (null cons) || not (null instances) + + +isRecCon :: Located (ConDecl a) -> Bool +isRecCon lcon = case con_details (unLoc lcon) of  +  RecCon _ -> True +  _ -> False + + +ppShortConstr :: Bool -> ConDecl DocName -> Bool -> Html +ppShortConstr summary con unicode = case con_res con of  +  ResTyH98 -> case con_details con of  +    PrefixCon args -> header_ unicode +++ hsep (ppBinder summary occ : map (ppLParendType unicode) args) +    RecCon fields -> header_ unicode +++ ppBinder summary occ <+> +                                              doRecordFields fields +    InfixCon arg1 arg2 -> header_ unicode +++  +      hsep [ppLParendType unicode arg1, ppBinder summary occ, ppLParendType unicode arg2]     + +  ResTyGADT resTy -> case con_details con of  +    -- prefix & infix could use hsConDeclArgTys if it seemed to +    -- simplify the code. +    PrefixCon args -> doGADTCon args resTy +    -- display GADT records with the new syntax, +    -- Constr :: (Context) => { field :: a, field2 :: b } -> Ty (a, b) +    -- (except each field gets its own line in docs, to match +    -- non-GADT records) +    RecCon fields -> ppBinder summary occ <+> dcolon unicode <+> hsep [ +                            ppForAll forall ltvs lcontext unicode, +                            doRecordFields fields, +                            arrow unicode <+> ppLType unicode resTy ] +    InfixCon arg1 arg2 -> doGADTCon [arg1, arg2] resTy  +     +  where +    doRecordFields fields = braces (vanillaTable << +                        aboves (map (ppShortField summary unicode) fields)) +    doGADTCon args resTy = ppBinder summary occ <+> dcolon unicode <+> hsep [ +                             ppForAll forall ltvs lcontext unicode, +                             ppLType unicode (foldr mkFunTy resTy args) ] + +    header_  = ppConstrHdr forall tyVars context +    occ      = docNameOcc . unLoc . con_name $ con +    ltvs     = con_qvars con +    tyVars   = tyvarNames ltvs  +    lcontext = con_cxt con +    context  = unLoc (con_cxt con) +    forall   = con_explicit con +    mkFunTy a b = noLoc (HsFunTy a b) + +-- ppConstrHdr is for (non-GADT) existentials constructors' syntax +ppConstrHdr :: HsExplicitForAll -> [Name] -> HsContext DocName -> Bool -> Html +ppConstrHdr forall tvs ctxt unicode + = (if null tvs then noHtml else ppForall) +   +++ +   (if null ctxt then noHtml else ppContextNoArrow ctxt unicode <+> darrow unicode +++ toHtml " ") +  where +    ppForall = case forall of  +      Explicit -> forallSymbol unicode <+> hsep (map ppName tvs) <+> toHtml ". " +      Implicit -> empty + +ppSideBySideConstr :: [(DocName, DocForDecl DocName)] -> Bool -> LConDecl DocName -> HtmlTable +ppSideBySideConstr subdocs unicode (L _ con) = case con_res con of  +  +  ResTyH98 -> case con_details con of  + +    PrefixCon args ->  +      argBox (hsep ((header_ unicode +++ ppBinder False occ) : map (ppLParendType unicode) args))  +      <-> maybeRDocBox mbDoc   + +    RecCon fields ->  +      argBox (header_ unicode +++ ppBinder False occ) <-> +      maybeRDocBox mbDoc +      </> +      doRecordFields fields + +    InfixCon arg1 arg2 ->  +      argBox (hsep [header_ unicode+++ppLParendType unicode arg1, ppBinder False occ, ppLParendType unicode arg2]) +      <-> maybeRDocBox mbDoc +  +  ResTyGADT resTy -> case con_details con of +    -- prefix & infix could also use hsConDeclArgTys if it seemed to +    -- simplify the code. +    PrefixCon args -> doGADTCon args resTy +    cd@(RecCon fields) -> doGADTCon (hsConDeclArgTys cd) resTy +                                          </> doRecordFields fields +    InfixCon arg1 arg2 -> doGADTCon [arg1, arg2] resTy  + + where  +    doRecordFields fields = +        (tda [theclass "body"] << spacedTable1 << +        aboves (map (ppSideBySideField subdocs unicode) fields)) +    doGADTCon args resTy = argBox (ppBinder False occ <+> dcolon unicode <+> hsep [ +                               ppForAll forall ltvs (con_cxt con) unicode, +                               ppLType unicode (foldr mkFunTy resTy args) ] +                            ) <-> maybeRDocBox mbDoc + + +    header_ = ppConstrHdr forall tyVars context +    occ     = docNameOcc . unLoc . con_name $ con +    ltvs    = con_qvars con +    tyVars  = tyvarNames (con_qvars con) +    context = unLoc (con_cxt con) +    forall  = con_explicit con +    -- don't use "con_doc con", in case it's reconstructed from a .hi file, +    -- or also because we want Haddock to do the doc-parsing, not GHC. +    -- 'join' is in Maybe. +    mbDoc = join $ fmap fst $ lookup (unLoc $ con_name con) subdocs +    mkFunTy a b = noLoc (HsFunTy a b) + +ppSideBySideField :: [(DocName, DocForDecl DocName)] -> Bool -> ConDeclField DocName ->  HtmlTable +ppSideBySideField subdocs unicode (ConDeclField (L _ name) ltype _) = +  argBox (ppBinder False (docNameOcc name) +    <+> dcolon unicode <+> ppLType unicode ltype) <-> maybeRDocBox mbDoc +  where +    -- don't use cd_fld_doc for same reason we don't use con_doc above +    mbDoc = join $ fmap fst $ lookup name subdocs + +{- +ppHsFullConstr :: HsConDecl -> Html +ppHsFullConstr (HsConDecl _ nm tvs ctxt typeList doc) =  +     declWithDoc False doc ( +        hsep ((ppHsConstrHdr tvs ctxt +++  +                ppHsBinder False nm) : map ppHsBangType typeList) +      ) +ppHsFullConstr (HsRecDecl _ nm tvs ctxt fields doc) = +   td << vanillaTable << ( +     case doc of +       Nothing -> aboves [hdr, fields_html] +       Just _  -> aboves [hdr, constr_doc, fields_html] +   ) + +  where hdr = declBox (ppHsConstrHdr tvs ctxt +++ ppHsBinder False nm) + +        constr_doc       +          | isJust doc = docBox (docToHtml (fromJust doc)) +          | otherwise  = emptyTable + +        fields_html =  +           td <<  +              table ! [width "100%", cellpadding 0, cellspacing 8] << ( +                   aboves (map ppFullField (concat (map expandField fields))) +                ) +-} + +ppShortField :: Bool -> Bool -> ConDeclField DocName -> HtmlTable +ppShortField summary unicode (ConDeclField (L _ name) ltype _) +  = tda [theclass "recfield"] << ( +      ppBinder summary (docNameOcc name) +      <+> dcolon unicode <+> ppLType unicode ltype +    ) + +{- +ppFullField :: HsFieldDecl -> Html +ppFullField (HsFieldDecl [n] ty doc)  +  = declWithDoc False doc ( +        ppHsBinder False n <+> dcolon <+> ppHsBangType ty +    ) +ppFullField _ = error "ppFullField" + +expandField :: HsFieldDecl -> [HsFieldDecl] +expandField (HsFieldDecl ns ty doc) = [ HsFieldDecl [n] ty doc | n <- ns ] +-} + +-- | Print the LHS of a data\/newtype declaration. +-- Currently doesn't handle 'data instance' decls or kind signatures +ppDataHeader :: Bool -> TyClDecl DocName -> Bool -> Html +ppDataHeader summary decl unicode +  | not (isDataDecl decl) = error "ppDataHeader: illegal argument" +  | otherwise =  +    -- newtype or data +    (if tcdND decl == NewType then keyword "newtype" else keyword "data") <+>  +    -- context +    ppLContext (tcdCtxt decl) unicode <+> +    -- T a b c ..., or a :+: b +    ppTyClBinderWithVars summary decl + + +-- ---------------------------------------------------------------------------- +-- Types and contexts + + +ppKind :: Outputable a => a -> Html +ppKind k = toHtml $ showSDoc (ppr k) + + +{- +ppForAll Implicit _ lctxt = ppCtxtPart lctxt +ppForAll Explicit ltvs lctxt =  +  hsep (keyword "forall" : ppTyVars ltvs ++ [dot]) <+> ppCtxtPart lctxt  +-} + + +ppBang :: HsBang -> Html +ppBang HsNoBang = empty  +ppBang HsStrict = toHtml "!" +ppBang HsUnbox  = toHtml "!" -- unboxed args is an implementation detail, +                             -- so we just show the strictness annotation + + +tupleParens :: Boxity -> [Html] -> Html +tupleParens Boxed   = parenList +tupleParens Unboxed = ubxParenList  +{- +ppType :: HsType DocName -> Html +ppType t = case t of +  t@(HsForAllTy expl ltvs lcontext ltype) -> ppForAllTy t <+> ppLType ltype +  HsTyVar n -> ppDocName n +  HsBangTy HsStrict lt -> toHtml "!" <+> ppLType lt +  HsBangTy HsUnbox lt -> toHtml "!!" <+> ppLType lt +  HsAppTy a b -> ppLType a <+> ppLType b  +  HsFunTy a b -> hsep [ppLType a, toHtml "->", ppLType b] +  HsListTy t -> brackets $ ppLType t +  HsPArrTy t -> toHtml "[:" +++ ppLType t +++ toHtml ":]" +  HsTupleTy Boxed ts -> parenList $ map ppLType ts +  HsTupleTy Unboxed ts -> ubxParenList $ map ppLType ts +  HsOpTy a n b -> ppLType a <+> ppLDocName n <+> ppLType b +  HsParTy t -> parens $ ppLType t +  HsNumTy n -> toHtml (show n) +  HsPredTy p -> ppPred p +  HsKindSig t k -> hsep [ppLType t, dcolon, ppKind k] +  HsSpliceTy _ -> error "ppType" +  HsDocTy t _ -> ppLType t +-} + + +-------------------------------------------------------------------------------- +-- Rendering of HsType  +-------------------------------------------------------------------------------- + + +pREC_TOP, pREC_FUN, pREC_OP, pREC_CON :: Int + +pREC_TOP = (0 :: Int)   -- type in ParseIface.y in GHC +pREC_FUN = (1 :: Int)   -- btype in ParseIface.y in GHC +                        -- Used for LH arg of (->) +pREC_OP  = (2 :: Int)   -- Used for arg of any infix operator +                        -- (we don't keep their fixities around) +pREC_CON = (3 :: Int)   -- Used for arg of type applicn: +                        -- always parenthesise unless atomic + +maybeParen :: Int           -- Precedence of context +           -> Int           -- Precedence of top-level operator +           -> Html -> Html  -- Wrap in parens if (ctxt >= op) +maybeParen ctxt_prec op_prec p | ctxt_prec >= op_prec = parens p +                               | otherwise            = p + + +ppLType, ppLParendType, ppLFunLhType :: Bool -> Located (HsType DocName) -> Html +ppLType       unicode y = ppType unicode (unLoc y) +ppLParendType unicode y = ppParendType unicode (unLoc y)  +ppLFunLhType  unicode y = ppFunLhType unicode (unLoc y) + + +ppType, ppParendType, ppFunLhType :: Bool -> HsType DocName -> Html +ppType       unicode ty = ppr_mono_ty pREC_TOP ty unicode  +ppParendType unicode ty = ppr_mono_ty pREC_CON ty unicode  +ppFunLhType  unicode ty = ppr_mono_ty pREC_FUN ty unicode + + +-- Drop top-level for-all type variables in user style +-- since they are implicit in Haskell + +ppForAll :: HsExplicitForAll -> [Located (HsTyVarBndr DocName)] +         -> Located (HsContext DocName) -> Bool -> Html +ppForAll expl tvs cxt unicode +  | show_forall = forall_part <+> ppLContext cxt unicode +  | otherwise   = ppLContext cxt unicode +  where +    show_forall = not (null tvs) && is_explicit +    is_explicit = case expl of {Explicit -> True; Implicit -> False} +    forall_part = hsep (forallSymbol unicode : ppTyVars tvs) +++ dot  + + +ppr_mono_lty :: Int -> LHsType DocName -> Bool -> Html +ppr_mono_lty ctxt_prec ty unicode = ppr_mono_ty ctxt_prec (unLoc ty) unicode  + + +ppr_mono_ty :: Int -> HsType DocName -> Bool -> Html +ppr_mono_ty ctxt_prec (HsForAllTy expl tvs ctxt ty) unicode  +  = maybeParen ctxt_prec pREC_FUN $ +    hsep [ppForAll expl tvs ctxt unicode, ppr_mono_lty pREC_TOP ty unicode] + +-- gaw 2004 +ppr_mono_ty _         (HsBangTy b ty)     u = ppBang b +++ ppLParendType u ty +ppr_mono_ty _         (HsTyVar name)      _ = ppDocName name +ppr_mono_ty ctxt_prec (HsFunTy ty1 ty2)   u = ppr_fun_ty ctxt_prec ty1 ty2 u +ppr_mono_ty _         (HsTupleTy con tys) u = tupleParens con (map (ppLType u) tys) +ppr_mono_ty _         (HsKindSig ty kind) u = parens (ppr_mono_lty pREC_TOP ty u <+> dcolon u <+> ppKind kind) +ppr_mono_ty _         (HsListTy ty)       u = brackets (ppr_mono_lty pREC_TOP ty u) +ppr_mono_ty _         (HsPArrTy ty)       u = pabrackets (ppr_mono_lty pREC_TOP ty u) +ppr_mono_ty _         (HsPredTy p)        u = parens (ppPred u p) +ppr_mono_ty _         (HsNumTy n)         _ = toHtml (show n) -- generics only +ppr_mono_ty _         (HsSpliceTy _)      _ = error "ppr_mono_ty HsSpliceTy" +ppr_mono_ty _         (HsSpliceTyOut _)   _ = error "ppr_mono_ty HsSpliceTyOut" +ppr_mono_ty _         (HsRecTy _)         _ = error "ppr_mono_ty HsRecTy" + + +ppr_mono_ty ctxt_prec (HsAppTy fun_ty arg_ty) unicode  +  = maybeParen ctxt_prec pREC_CON $ +    hsep [ppr_mono_lty pREC_FUN fun_ty unicode, ppr_mono_lty pREC_CON arg_ty unicode] + +ppr_mono_ty ctxt_prec (HsOpTy ty1 op ty2) unicode  +  = maybeParen ctxt_prec pREC_FUN $ +    ppr_mono_lty pREC_OP ty1 unicode <+> ppr_op <+> ppr_mono_lty pREC_OP ty2 unicode +  where +    ppr_op = if not (isSymOcc occName) then quote (ppLDocName op) else ppLDocName op +    occName = docNameOcc . unLoc $ op + +ppr_mono_ty ctxt_prec (HsParTy ty) unicode  +--  = parens (ppr_mono_lty pREC_TOP ty) +  = ppr_mono_lty ctxt_prec ty unicode + +ppr_mono_ty ctxt_prec (HsDocTy ty _) unicode  +  = ppr_mono_lty ctxt_prec ty unicode + + +ppr_fun_ty :: Int -> LHsType DocName -> LHsType DocName -> Bool -> Html  +ppr_fun_ty ctxt_prec ty1 ty2 unicode +  = let p1 = ppr_mono_lty pREC_FUN ty1 unicode +        p2 = ppr_mono_lty pREC_TOP ty2 unicode +    in +    maybeParen ctxt_prec pREC_FUN $ +    hsep [p1, arrow unicode <+> p2] + + | 
