packages feed

hs-bindgen-1.0.0.0: src-internal/HsBindgen/Backend/HsModule/Pretty/Common.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}

module HsBindgen.Backend.HsModule.Pretty.Common (
    -- * Names
    prettyResolvedNamePlain

    -- * Tuples
  , prettyBoxedTuple
  , prettyUnboxedTuple

    -- * Helpers
  , withFreshNames
  , panicWith
  ) where

import Data.Text qualified as Text
import DeBruijn (Add (..), Env (..))
import Text.SimplePrettyPrint (CtxDoc, Pretty (..))
import Text.SimplePrettyPrint qualified as PP

import HsBindgen.Backend.Hs.Name qualified as Hs
import HsBindgen.Backend.HsModule.Names
import HsBindgen.Backend.SHs.AST
import HsBindgen.Errors
import HsBindgen.Imports
import HsBindgen.Language.Haskell qualified as Hs
import HsBindgen.NameHint

{-------------------------------------------------------------------------------
  Names
-------------------------------------------------------------------------------}

instance Pretty (Hs.Name ns) where
  pretty nm = PP.text nm.text

instance Pretty Hs.TermName where
  pretty = PP.text . Hs.termNameToText

-- | Pretty-print a 'HsBindgen.Backend.HsModule.Names.ResolvedName' in prefix notation
--
-- Operators are parenthesized.
instance Pretty ResolvedName where
  pretty resolved =
    PP.parensWhen (resolved.typ == OperatorName) $ prettyResolvedNamePlain resolved

-- | Pretty-print a 'HsBindgen.Backend.HsModule.Names.ResolvedName'
--
-- This auxialary function pretty-prints without parenthesizing operators or
-- surrounding identifiers with backticks.
prettyResolvedNamePlain :: ResolvedName -> CtxDoc
prettyResolvedNamePlain resolved =
    case resolved.hsImport of
      Hs.QualifiedImport name alias ->
        let q = fromMaybe (Hs.moduleNameToString name) alias
        in  PP.string $ q ++ '.' : resolved.string
      _otherwise ->
        PP.string resolved.string

{-------------------------------------------------------------------------------
  External references
-------------------------------------------------------------------------------}

instance Pretty Hs.ModuleName where
  pretty = PP.string . Hs.moduleNameToString

instance Pretty Hs.SomeName where
  pretty = PP.string . Text.unpack . (.text)

instance Pretty Hs.ExtRef where
  pretty extRef = PP.hcat [
        pretty extRef.moduleName
      , PP.char '.'
      , PP.text extRef.name.text
      ]

{-------------------------------------------------------------------------------
  Tuples
-------------------------------------------------------------------------------}

prettyTupleWith :: String -> String -> Plus2 -> [CtxDoc] -> CtxDoc
prettyTupleWith pre pos n decls = case compare arity nDecls of
    LT ->
      panicPure $ mconcat [
          "Too many declarations ("
        , show nDecls
        , ") for "
        , show arity ++ "-tuple"
        ]
    _otherwise ->
      let nMissing :: Int
          nMissing = arity - nDecls

          fakeDecls :: [CtxDoc]
          fakeDecls = decls ++ replicate nMissing ""

          lsOneLn   = PP.hlist pre pos fakeDecls
          lsMulLn   = PP.vlist pre pos fakeDecls
      in  PP.ifFits lsOneLn lsOneLn lsMulLn
  where
    arity, nDecls :: Int
    arity  = fromIntegral $ applyPlus2 n
    nDecls = length decls

prettyBoxedTuple, prettyUnboxedTuple :: Plus2 -> [CtxDoc] -> CtxDoc
prettyBoxedTuple   = prettyTupleWith "(" ")"
prettyUnboxedTuple = prettyTupleWith "(#" "#)"

{-------------------------------------------------------------------------------
  Helpers
-------------------------------------------------------------------------------}

withFreshNames ::
     Env ctx CtxDoc
  -> Add n ctx ctx'
  -> Vec n NameHint
  -> (Env ctx' CtxDoc -> [CtxDoc] -> CtxDoc)
  -> CtxDoc
withFreshNames env AZ     _                         kont = kont env []
withFreshNames env (AS a) (NameHint hint ::: hints) kont = PP.withFreshName hint $ \name ->
    withFreshNames env a hints $ \env' names -> kont (env' :> name) (name : names)

panicWith :: Show a => String -> a -> b
panicWith msg x = panicPure $ msg ++ "; " ++ show x