content: ------------------------------------------------------------------------
  -- |
  -- Module           : Lang.Crucible.LLVM.PrettyPrint
  -- Description      : Printing utilties for LLVM
  -- Copyright        : (c) Galois, Inc 2015-2016
  -- License          : BSD3
  -- Maintainer       : Rob Dockins <rdockins@galois.com>
  -- Stability        : provisional
  --
  -- This module defines several functions whose names clash with functions
  -- offered elsewhere in @llvm-pretty@ (e.g., "Text.LLVM.PP") and in
  -- @crucible-llvm@ (e.g., "Lang.Crucible.LLVM.MemModel.MemLog"). For this
  -- reason, it is recommended to import this module qualified.
  ------------------------------------------------------------------------
  
  {-# LANGUAGE ImplicitParams #-}
  {-# LANGUAGE RankNTypes #-}
  module Lang.Crucible.LLVM.PrettyPrint
    ( commaSepList
    , ppIntType
    , ppPtrType
    , ppArrayType
    , ppVectorType
    , ppIntVector
  
      -- * @llvm-pretty@ printing with the latest LLVM version
    , ppLLVMLatest
    , ppDeclare
    , ppIdent
    , ppSymbol
    , ppType
    , ppValue
    ) where
  
  import Numeric.Natural
  import Prettyprinter
  import qualified Text.PrettyPrint.HughesPJ as HPJ
  
  import qualified Text.LLVM.AST as L
  import qualified Text.LLVM.PP as L
  
  -- | Print list of documents separated by commas and spaces.
  commaSepList :: [Doc ann] -> Doc ann
  commaSepList l = hcat (punctuate (comma <> pretty ' ') l)
  
  -- | Pretty print int type with width.
  ppIntType :: Integral a => a -> Doc ann
  ppIntType i = pretty 'i' <> pretty (toInteger i)
  
  -- | Pretty print pointer type.
  ppPtrType :: Doc ann -> Doc ann
  ppPtrType tp = tp <> pretty '*'
  
  ppArrayType :: Natural -> Doc ann -> Doc ann
  ppArrayType n e = brackets (pretty (toInteger n) <+> pretty 'x' <+> e)
  
  ppVectorType :: Natural -> Doc ann -> Doc ann
  ppVectorType n e = angles (pretty (toInteger n) <+> pretty 'x' <+> e)
  
  ppIntVector :: Integral a => Natural -> a -> Doc ann
  ppIntVector n w = ppVectorType n (ppIntType w)
  
  -- | Pretty-print an LLVM-related AST in accordance with the latest LLVM version
  -- that @llvm-pretty@ currently supports (i.e., the value of 'L.llvmVlatest'.)
  --
  -- Note that we are mainly using the @llvm-pretty@ printer in @crucible-llvm@
  -- for the sake of defining 'Show' instances and creating error messages, not
  -- for creating machine-readable LLVM code. As a result, it doesn't particularly
  -- matter which LLVM version we use, as any version-specific differences in
  -- pretty-printer output won't be that impactful.
  ppLLVMLatest :: ((?config :: L.Config) => a) -> a
  ppLLVMLatest = L.withConfig (L.Config { L.cfgVer = L.llvmVlatest })
  
  -- | Invoke 'L.ppDeclare' in accordance with the latest LLVM version that
  -- @llvm-pretty@ supports.
  ppDeclare :: L.Declare -> HPJ.Doc
  ppDeclare = ppLLVMLatest L.ppDeclare
  
  -- | Invoke 'L.ppIdent' in accordance with the latest LLVM version that
  -- @llvm-pretty@ supports.
  ppIdent :: L.Ident -> HPJ.Doc
  ppIdent = ppLLVMLatest L.ppIdent
  
  -- | Invoke 'L.ppSymbol' in accordance with the latest LLVM version that
  -- @llvm-pretty@ supports.
  ppSymbol :: L.Symbol -> HPJ.Doc
  ppSymbol = ppLLVMLatest L.ppSymbol
  
  -- | Invoke 'L.ppType' in accordance with the latest LLVM version that
  -- @llvm-pretty@ supports.
  ppType :: L.Type -> HPJ.Doc
  ppType = ppLLVMLatest L.ppType
  
  -- | Invoke 'L.ppValue' in accordance with the latest LLVM version that
  -- @llvm-pretty@ supports.
  ppValue :: L.Value -> HPJ.Doc
  ppValue = ppLLVMLatest L.ppValue
  