blob: b937d1402219253c80828fd303eed34cde55f4e4 (
plain) (
tree)
|
|
-- vim: et ts=2 sw=2 ai:
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
module SPL.PrettyPrinter
where
import SPL.Syntax
import Control.Applicative
import Control.Monad
import Control.Monad.State.Lazy
import Control.Monad.Identity
import Data.Char
prettyPrint :: Pprint t => t -> String
prettyPrint t = result $ execState (pprint t) (St 0 0 "")
-- For Extensibility
data St = St
{ indentation :: Int
, priority :: Int
, result :: String
}
type Print = State St ()
decIndent :: Print
decIndent = modify (\st -> st {indentation=indentation st + 1})
incIndent :: Print
incIndent = modify (\st -> st {indentation=indentation st - 1})
indent :: (Pprint t) => t -> Print
indent p = do
newline
decIndent
pprint p
newline
incIndent
newline :: Print
newline = do
i <- gets indentation
pprint $ replicate i '\t'
pprint "\n"
class Pprint t where
pprint :: t -> Print
instance Pprint Print where pprint = id
instance Pprint Program where
pprint p = do
printersperse "\n\n" $ funs p
pprint $ if length (vars p) `min` length (funs p) == 0 then "" else "\n\n"
printersperse "\n" $ vars p
instance Pprint Function where
pprint f = do
pprint "}"
newline
decIndent
pprint $ fcode f
case fvars f of
[] -> pure ()
_ -> newline
printersperse newline $ fvars f
newline
incIndent
pprint " {"
case ftype f of
Nothing -> pprint "-> Void"
Just x -> pprint x
pprint ") :: "
printersperse ", " $ fargs f
pprint "("
pprint $ fname f
instance Pprint Variable where
pprint v = do
pprint ";"
pprint $ vval v
pprint " = "
pprint $ vname v
pprint " "
case vtype v of
Nothing -> pprint "var"
Just t -> pprint t
instance Pprint Type where
pprint TInt = pprint "Int"
pprint TBool = pprint "Bool"
pprint TChar = pprint "Char"
pprint TVoid = pprint "Void"
pprint (TList t) = do
pprint "]"
pprint t
pprint "["
pprint (TTuple t1 t2) = do
pprint ")"
pprint t2
pprint ", "
pprint t1
pprint "("
pprint (TArrow ts t) = do
pprint t
pprint $ if (null ts) then "-> " else " -> "
printersperse " " ts
pprint (TVar v) = pprint v
instance Pprint Statement where
pprint (If expr smt1 (Just smt2)) = do
pprint "}"
indent smt2
pprint "} else {"
indent smt1
pprint ") {"
pprint expr
pprint "if ("
pprint (If expr smt1 Nothing) = do
pprint "}"
indent smt1
pprint ") {"
pprint expr
pprint "if ("
pprint (While expr stmt) = do
pprint "}"
indent stmt
pprint ") {"
pprint expr
pprint "while ("
pprint (Assign name fields expr) = do
pprint ";"
pprint expr
pprint " = "
pprint fields
pprint name
pprint (Eval expr) = do
pprint ";"
pprint expr
pprint (Return (Just x)) = do
pprint ";"
pprint x
pprint "return "
pprint (Return Nothing) = do
pprint "return;"
pprint (Seq stmt1 stmt2) = do
pprint stmt2
newline
pprint stmt1
pprint Nop = return ()
pprint _ = error "Cannot pprint unknown statement"
instance Pprint Expression where
pprint (Var v) = pprint v
pprint (Field name field) = do
pprint field
pprint name
pprint (Op2 e1 op e2) = do
p <- gets priority
pprint $ if (prio op > p && p /= 0) then ")" else ""
modify (\st -> st {priority = prio op})
pprint e2
pprint " "
pprint op
pprint " "
pprint e1
modify (\st -> st {priority = p})
pprint $ if (prio op > p && p /= 0) then "(" else ""
pprint (Op1 op e) = do
pprint e
pprint op
pprint (Literal l) = do
pprint l
pprint (FunCall name xs) = do
pprint ")"
printersperse ", " xs
pprint "("
pprint name
pprint (Tuple e1 e2) = do
pprint ")"
pprint e2
pprint ", "
pprint e1
pprint "("
pprint _ = error "Cannot pprint unknown expression"
instance Pprint Field where
pprint Hd = pprint ".hd"
pprint Tl = pprint ".tl"
pprint Fst = pprint ".fst"
pprint Snd = pprint ".snd"
pprint _ = error "Cannot pprint unknown field"
instance Pprint Op2 where
pprint Add = pprint "+"
pprint Sub = pprint "-"
pprint Mul = pprint "*"
pprint Div = pprint "/"
pprint Mod = pprint "%"
pprint Eq = pprint "=="
pprint Lt = pprint "<"
pprint Gt = pprint ">"
pprint Le = pprint "<="
pprint Ge = pprint ">="
pprint Ne = pprint "!="
pprint And = pprint "&&"
pprint Or = pprint "||"
pprint Cons = pprint ":"
pprint _ = error "Cannot pprint unknown binary operator"
instance Pprint Op1 where
pprint Not = pprint "!"
pprint Neg = pprint "-"
pprint _ = error "Cannot pprint unknown unary operator"
instance Pprint Literal where
pprint (LInt x) = pprint $ show x
pprint (LChar x) = pprint $ "'" ++ show x ++ "'"
pprint (LBool x) = pprint $ show x
pprint LNil = pprint "[]"
pprint _ = error "Cannot pprint unknown literal"
instance Pprint a => Pprint [a] where
pprint = mapM_ pprint . reverse
printersperse :: (Pprint a, Pprint g) => g -> [a] -> Print
printersperse _ [] = pure ()
printersperse _ [x] = pprint x
printersperse g (x:xs) = do
printersperse g xs
pprint g
pprint x
instance Pprint Char where
pprint c = modify (\st -> st { result = (c : result st) })
|