packages feed

language-smtlib-0.1.0.0: src/Language/SMTLIB/Printer.hs

-- | Rendering the SMT-LIB AST to 'Text'.
--
-- The default layout puts each top-level form on a single line (no automatic
-- line breaks), which keeps the output deterministic and trivially
-- round-trippable.  t'RenderOptions' lets callers opt into a wrapped layout.
module Language.SMTLIB.Printer
  ( Pretty(..)
  , RenderOptions(..)
  , defaultRenderOptions
  , render
  , renderText
  , renderTextWith
  , renderScript
  ) where

import Data.Text (Text)
import qualified Data.Text as T
import Prettyprinter (Doc, LayoutOptions(..), PageWidth(..), layoutPretty)
import Prettyprinter.Render.Text (renderStrict)

import Language.SMTLIB.Printer.Class (Pretty(..))
import Language.SMTLIB.Syntax.Command (Script)

-- | Layout configuration.
newtype RenderOptions = RenderOptions
  { roPageWidth :: PageWidth
    -- ^ 'Unbounded' (the default) keeps every form on one line.
  }

-- | Single-line layout: each form rendered without automatic wrapping.
defaultRenderOptions :: RenderOptions
defaultRenderOptions = RenderOptions { roPageWidth = Unbounded }

-- | Render any 'Doc' to 'Text' with the given options.
render :: RenderOptions -> Doc ann -> Text
render opts = renderStrict . layoutPretty layoutOpts
  where layoutOpts = LayoutOptions { layoutPageWidth = roPageWidth opts }

-- | Render a single AST node to 'Text' using 'defaultRenderOptions'.
renderText :: Pretty a => a -> Text
renderText = renderTextWith defaultRenderOptions

-- | Render a single AST node to 'Text' with explicit options.
renderTextWith :: Pretty a => RenderOptions -> a -> Text
renderTextWith opts = render opts . pretty

-- | Render a whole script, one command per line, terminated by a newline.
renderScript :: Script a -> Text
renderScript [] = T.empty
renderScript cmds = T.unlines (map renderText cmds)