content: {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
  module Test.QuickFuzz.Gen.Bnfc.PrintGrammar where
  
  -- pretty-printer generated by the BNF converter
  
  import Test.QuickFuzz.Gen.Bnfc.AbsGrammar
  import Data.Char
  
  
  -- the top-level printing method
  printTree :: Print a => a -> String
  printTree = render . prt 0
  
  type Doc = [ShowS] -> [ShowS]
  
  doc :: ShowS -> Doc
  doc = (:)
  
  render :: Doc -> String
  render d = rend 0 (map ($ "") $ d []) "" where
    rend i ss = case ss of
      "["      :ts -> showChar '[' . rend i ts
      "("      :ts -> showChar '(' . rend i ts
      "{"      :ts -> showChar '{' . new (i+1) . rend (i+1) ts
      "}" : ";":ts -> new (i-1) . space "}" . showChar ';' . new (i-1) . rend (i-1) ts
      "}"      :ts -> new (i-1) . showChar '}' . new (i-1) . rend (i-1) ts
      ";"      :ts -> showChar ';' . new i . rend i ts
      t  : "," :ts -> showString t . space "," . rend i ts
      t  : ")" :ts -> showString t . showChar ')' . rend i ts
      t  : "]" :ts -> showString t . showChar ']' . rend i ts
      t        :ts -> space t . rend i ts
      _            -> id
    new i   = showChar '\n' . replicateS (2*i) (showChar ' ') . dropWhile isSpace
    space t = showString t . (\s -> if null s then "" else (' ':s))
  
  parenth :: Doc -> Doc
  parenth ss = doc (showChar '(') . ss . doc (showChar ')')
  
  concatS :: [ShowS] -> ShowS
  concatS = foldr (.) id
  
  concatD :: [Doc] -> Doc
  concatD = foldr (.) id
  
  replicateS :: Int -> ShowS -> ShowS
  replicateS n f = concatS (replicate n f)
  
  -- the printer class does the job
  class Print a where
    prt :: Int -> a -> Doc
    prtList :: Int -> [a] -> Doc
    prtList i = concatD . map (prt i)
  
  instance Print a => Print [a] where
    prt = prtList
  
  instance Print Char where
    prt _ s = doc (showChar '\'' . mkEsc '\'' s . showChar '\'')
    prtList _ s = doc (showChar '"' . concatS (map (mkEsc '"') s) . showChar '"')
  
  mkEsc :: Char -> Char -> ShowS
  mkEsc q s = case s of
    _ | s == q -> showChar '\\' . showChar s
    '\\'-> showString "\\\\"
    '\n' -> showString "\\n"
    '\t' -> showString "\\t"
    _ -> showChar s
  
  prPrec :: Int -> Int -> Doc -> Doc
  prPrec i j = if j<i then parenth else id
  
  
  instance Print Integer where
    prt _ x = doc (shows x)
  
  
  instance Print Double where
    prt _ x = doc (shows x)
  
  
  
  
  instance Print Exp where
    prt i e = case e of
      EAdd exp1 exp2 -> prPrec i 0 (concatD [prt 0 exp1, doc (showString "+"), prt 1 exp2])
      ESub exp1 exp2 -> prPrec i 0 (concatD [prt 0 exp1, doc (showString "-"), prt 1 exp2])
      EMul exp1 exp2 -> prPrec i 1 (concatD [prt 1 exp1, doc (showString "*"), prt 2 exp2])
      EDiv exp1 exp2 -> prPrec i 1 (concatD [prt 1 exp1, doc (showString "/"), prt 2 exp2])
      EInt n -> prPrec i 2 (concatD [prt 0 n])
  
  
  