Doc.hs revision d049e21661c3d0a2cf6339d3b94e4cd188b0188c
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkModule : $Header$
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkCopyright : (c) Christian Maeder and Uni Bremen 2006
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkLicense : similar to LGPL, see HetCATS/LICENSE.txt or LIZENZ.txt
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkMaintainer : maeder@tzi.de
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkStability : provisional
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkPortability : portable
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdocument data type for displaying (heterogenous) CASL specifications
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkat least as plain text and latex (and maybe in html as well)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkinspired by John Hughes's and Simon Peyton Jones's Pretty Printer Combinators
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkin "Text.PrettyPrint.HughesPJ", Thomas Hallgren's
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk<http://www.cse.ogi.edu/~hallgren/Programatica/tools/pfe.cgi?PrettyDoc>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkDaan Leijen's PPrint: A prettier printer 2001, Olaf Chiti's
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkPretty printing with lazy Dequeues 2003
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk ( -- * The document type
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Doc -- Abstract
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk -- * Primitive Documents
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk -- * Converting values into documents
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk -- * Wrapping documents in delimiters
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , doubleQuotes
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk -- * Combining documents
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , flushRight
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk -- * keywords
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk -- * symbols
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , rightArrow
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk -- * docifying annotations and ids
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk -- * transforming to existing formats
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkimport qualified Common.Lib.Map as Map
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkimport qualified Common.Lib.Pretty as Pretty
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkimport Data.Char (toLower)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdata TextKind = IdKind | Symbol | Keyword | TopKey | Indexed | StructId
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdata Format = Small | FlushRight
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdata ComposeKind
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk = Vert -- ($+$) (no support for $$!)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | Horiz -- (<>)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | HorizOrVert -- either Horiz or Vert
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk = Empty -- creates an empty line if composed vertically
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | AnnoDoc Annotation -- we know how to print annotations
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | IdDoc Id -- for plain ids outside applications
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | IdApplDoc Id [Doc] -- for mixfix applications and literal terms
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | Text TextKind String -- non-empty and no white spaces inside
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | Cat ComposeKind [Doc]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | Attr Format Doc -- for annotations
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk | IndentBy Doc Doc Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkIdentBy refDoc startDoc hangDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkis: startDoc <> (length refDoc - length startDoc) <> hangDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkif refDoc >= startDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk (i.e indent hangBlock by refDoc and put it beside startDoc)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkis: startDoc <> hangDoc if it fits on a single line!
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkis: startDoc $+$
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk nest refDoc hangDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkif refDoc < startDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkisEmpty :: Doc -> Bool
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkisEmpty d = case d of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Empty -> True
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkempty :: Doc -- ^ An empty document
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkempty = Empty
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenktext :: String -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenktext = Text IdKind
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenksemi :: Doc -- ^ A ';' character
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenksemi = text ";"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcomma :: Doc -- ^ A ',' character
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcomma = text ","
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcolon :: Doc -- ^ A ':' character
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcolon = text ":"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- the only legal white space within Text
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkspace :: Doc -- ^ A horizontal space (omitted at end of line)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkspace = text " "
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkequals :: Doc -- ^ A '=' character
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkequals = text "="
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- use symbol for strings that need (i.e. latex) escaping
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenksymbol :: String -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenksymbol = Text Symbol
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenklparen, rparen, lbrack, rbrack, lbrace, rbrace, quote, doubleQuote :: Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenklparen = text "("
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkrparen = text ")"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenklbrack = text "["
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkrbrack = text "]"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenklbrace = symbol "{" -- to allow for latex translations
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkrbrace = symbol "}"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkquote = text "\'"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdoubleQuote = text "\""
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkparens :: Doc -> Doc -- ^ Wrap document in @(...)@
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkparens d = fcat [lparen, d, rparen]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkbrackets :: Doc -> Doc -- ^ Wrap document in @[...]@
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkbrackets d = fcat [lbrack, d, rbrack]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkbraces :: Doc -> Doc -- ^ Wrap document in @{...}@
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkbraces d = cat [lbrace <> d, rbrace]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkquotes :: Doc -> Doc -- ^ Wrap document in @\'...\'@
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkquotes d = hcat [quote, d, quote]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdoubleQuotes :: Doc -> Doc -- ^ Wrap document in @\"...\"@
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdoubleQuotes d = hcat [doubleQuote, d, doubleQuote]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk(<>) :: Doc -> Doc -> Doc -- ^Beside
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenka <> b = Cat Horiz [a, b]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkhcat :: [Doc] -> Doc -- ^List version of '<>'
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkhcat = Cat Horiz
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk(<+>) :: Doc -> Doc -> Doc -- ^Beside, separated by space
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenka <+> b = if isEmpty a then b else
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if isEmpty b then a else Cat Horiz [a, space, b]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkpunctuate :: Doc -> [Doc] -> [Doc]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkpunctuate d l = case l of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk x : r@(_ : _) -> (x <> d) : punctuate d r
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkhsep :: [Doc] -> Doc -- ^List version of '<+>'
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkhsep = hcat . punctuate space
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk($+$) :: Doc -> Doc -> Doc; -- ^Above, without dovetailing.
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenka $+$ b = Cat Vert [a, b]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkvcat :: [Doc] -> Doc -- ^List version of '$+$'
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkvcat = Cat Vert
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcat :: [Doc] -> Doc -- ^ Either hcat or vcat
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcat = Cat HorizOrVert
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenksep :: [Doc] -> Doc -- ^ Either hsep or vcat
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenksep = cat . punctuate space
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkfcat :: [Doc] -> Doc -- ^ \"Paragraph fill\" version of cat
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkfcat = Cat Fill
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkfsep :: [Doc] -> Doc -- ^ \"Paragraph fill\" version of sep
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkfsep = fcat . punctuate space
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkkeyword, topKey, indexed, structId :: String -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkkeyword = Text Keyword
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkindexed = Text Indexed
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkstructId = Text StructId
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenktopKey = Text TopKey
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- | docs possibly rendered differently for Text or LaTeX
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdot, bullet, defn, less, lambda, mapsto, rightArrow, pfun, cfun, pcfun,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk exequal, forallDoc, exists, unique, cross, bar, notDoc, inDoc, andDoc,
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk orDoc, implies, equiv :: Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdot = text "."
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkbullet = symbol "."
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdefn = symbol "::="
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkless = text "<"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenklambda = symbol "lambda"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkmapsto = symbol "|->"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkrightArrow = symbol "->"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkpfun = symbol "->?"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcfun = symbol "-->"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkpcfun = symbol "-->?"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkexequal = symbol "=e="
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkforallDoc = symbol "forall"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkexists = symbol "exists"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkunique = symbol "exists!"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcross = symbol "*"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkbar = symbol "|"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenknotDoc = symbol "not"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkinDoc = symbol "in"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkandDoc = symbol "/\\"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkorDoc = symbol "\\/"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkimplies = symbol "=>"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkequiv = symbol "<=>"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- | we know how to print annotations
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannoDoc :: Annotation -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannoDoc = AnnoDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- | for plain ids outside applications
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkidDoc :: Id -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkidDoc = IdDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- | for mixfix applications and literal terms (may print \"\" for empty)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkidApplDoc :: Id -> [Doc] -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkidApplDoc = IdApplDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- | put document as far to the right as fits (for annotations)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkflushRight :: Doc -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkflushRight = Attr FlushRight
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenksmall :: Doc -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenksmall = Attr Small
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{- | print second argument and then indent the last one by the width
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkof the first one -}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkindentBy :: Doc -> Doc -> Doc -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkindentBy = IndentBy
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk{- | transform document according to a specific display map and other
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkglobal annotations like precedences, associativities, and literal
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannotations. -}
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcodeOut :: GlobalAnnos -> Map.Map Id [Token] -> Doc -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcodeOut ga m = foldDoc idRecord
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk { foldAnnoDoc = \ _ -> small . codeOutAnno m
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIdDoc = \ _ -> codeOutId m
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIdApplDoc = \ _ -> codeOutAppl ga m
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- | convert for outputting latex
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenktoLatex :: Doc -> Pretty.Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenktoLatex = undefined
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- | simple conversion to a standard text document
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenktoText :: Doc -> Pretty.Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenktoText = foldDoc DocRecord
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk { foldEmpty = \ _ -> Pretty.empty
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldAnnoDoc = error "Doc.toText.AnnoDoc"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIdDoc = error "Doc.toText.IdDoc"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIdApplDoc = error "Doc.toText.IdApplDoc"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldText = \ _ _ -> Pretty.text
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldCat = \ _ c -> case c of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk HorizOrVert -> Pretty.cat
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldAttr = \ _ _ -> id
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIndentBy = \ _ d1 d2 d3 ->
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk d2 Pretty.$$ Pretty.nest (length $ show d1) d3
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk } . codeOut emptyGlobalAnnos Map.empty
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkdata DocRecord a = DocRecord
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk { foldEmpty :: Doc -> a
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk , foldAnnoDoc :: Doc -> Annotation -> a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIdDoc :: Doc -> Id -> a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIdApplDoc :: Doc -> Id -> [a] -> a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldText :: Doc -> TextKind -> String -> a
dff2cc5646d4437ab9e0cb1dcb59da65462a5938jeff.schenk , foldCat :: Doc -> ComposeKind -> [a] -> a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldAttr :: Doc -> Format -> a -> a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIndentBy :: Doc -> a -> a -> a -> a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkidRecord :: DocRecord Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkidRecord = DocRecord
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk { foldEmpty = \ _ -> Empty
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldAnnoDoc = \ _ -> AnnoDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIdDoc = \ _ -> IdDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIdApplDoc = \ _ -> IdApplDoc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldText = \ _ -> Text
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldCat = \ _ -> Cat
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldAttr = \ _ -> Attr
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , foldIndentBy = \ _ -> IndentBy
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkfoldDoc :: DocRecord a -> Doc -> a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkfoldDoc r d = case d of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Empty -> foldEmpty r d
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk AnnoDoc a -> foldAnnoDoc r d a
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk IdDoc i -> foldIdDoc r d i
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk IdApplDoc i l -> foldIdApplDoc r d i $ map (foldDoc r) l
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Text k s -> foldText r d k s
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Cat k l -> foldCat r d k $ map (foldDoc r) l
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Attr a e -> foldAttr r d a $ foldDoc r e
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk IndentBy e f g ->
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk foldIndentBy r d (foldDoc r e) (foldDoc r f) $ foldDoc r g
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannoLine :: String -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannoLine w = symbol "%" <> text w
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannoLparen :: String -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannoLparen w = symbol "%" <> text w <> lparen
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkwrapAnnoLines :: Doc -> [Doc] -> Doc -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkwrapAnnoLines a l b = case l of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk [] -> a <> b
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk [x] -> fcat [a, x, b]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk x : r -> vcat $ fcat [a, x] : init r ++ [fcat [last r, b]]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkpercent :: Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkpercent = symbol "%"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannoRparen :: Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkannoRparen = rparen <> percent
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcCommaT :: Map.Map Id [Token] -> [Id] -> [Doc]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcCommaT m = punctuate comma . map (codeOutId m)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkhCommaT :: Map.Map Id [Token] -> [Id] -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkhCommaT m = hsep . cCommaT m
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkfCommaT :: Map.Map Id [Token] -> [Id] -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkfCommaT m = fsep . cCommaT m
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcodeOutAnno :: Map.Map Id [Token] -> Annotation -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcodeOutAnno m a = case a of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Unparsed_anno aw at _ -> case at of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Line_anno s -> (case aw of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Annote_word w -> annoLine w
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Comment_start -> symbol "%%") <> symbol s
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Group_anno l -> let ds = map symbol l in case aw of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Annote_word w -> wrapAnnoLines (annoLparen w) ds annoRparen
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Comment_start -> wrapAnnoLines (percent <> lbrace) ds rbrace
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Display_anno i ds _ -> annoLparen "display" <+> fsep
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk [ codeOutId m i
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , vcat $ map ( \ (d, s) ->
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk percent <> text (lookupDisplayFormat d) <+> symbol s) ds
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk List_anno i1 i2 i3 _ -> annoLine "list" <+> hCommaT m [i1, i2, i3]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Number_anno i _ -> annoLine "number" <+> codeOutId m i
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Float_anno i1 i2 _ -> annoLine "floating" <+> hCommaT m [i1, i2]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk String_anno i1 i2 _ -> annoLine "string" <+> hCommaT m [i1, i2]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Prec_anno p l1 l2 _ -> annoLparen "prec" <+>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk fsep [ braces $ fCommaT m l1
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , symbol $ case p of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Lower -> "<"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Higher -> ">"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk BothDirections -> "<>"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk NoDirection -> error "codeOutAnno"
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , braces $ fCommaT m l2
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk , annoRparen ]
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Assoc_anno d l _ -> annoLparen "assoc" <>
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk symbol "_" <> text (map toLower $ tail $ show d)
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk <+> fsep (cCommaT m l ++ [annoRparen])
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Label l _ -> wrapAnnoLines (annoLparen "") (map symbol l) annoRparen
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Semantic_anno sa _ -> annoLine $ lookupSemanticAnno sa
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcodeOutId :: Map.Map Id [Token] -> Id -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcodeOutId m i = fcat $ case Map.lookup i m of
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Nothing -> map (symbol . tokStr) $ getTokenList place i
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk Just ts -> map (\ t -> let s = tokStr t in
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk if isPlace t then symbol s else text s) ts
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenk-- print literal terms and mixfix applications
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcodeOutAppl :: GlobalAnnos -> Map.Map Id [Token] -> Id -> [Doc] -> Doc
5b64d5d44892834ba97f003080f3467299b7c5c5jeff.schenkcodeOutAppl _ m i args = codeOutId m i <> parens (fsep $ punctuate comma args)