module CPSPrint where
import Text.PrettyPrint
import Data.Char
import Control.Arrow ((***))
import Data.Map (unions, singleton)
import Data.Monoid hiding ((<>))
import CPSScheme
import Common
ppProg :: Bool -> Prog -> Doc
ppProg el = ppLambda el
renderProg :: Bool -> Prog -> String
renderProg el = render . ppProg el
ppLambda :: Bool -> Lambda -> Doc
ppLambda el (Lambda l vs c) = parens $
embeddLabel el l <> text "λ" <+> sep
[ hsep (map (\(Var _ n) -> text n) vs) <> text "."
, ppCall el c
]
ppCall :: Bool -> Call -> Doc
ppCall el (App l (P (If lt lf)) [b,c1,c2]) = sep
[ embeddLabel el l <> text "if" <+> ppVal el b
, embeddLabel el lt <> text "then" <+> ppVal el c1
, embeddLabel el lf <> text "else" <+> ppVal el c2
]
ppCall el (App l f as) =
embeddLabel el l <> ppVal el f <+> sep (map (ppVal el) as)
ppCall el (Let l binds c) =
embeddLabel el l <> text "let" <+> vcat (map ppBind binds) $$
text "in" <+> ppCall el c
where ppBind (Var _ n,l) = text n <+> text "=" $$ nest 6 (ppLambda el l)
ppVal :: Bool -> Val -> Doc
ppVal el (L l) = ppLambda el l
ppVal el (R _ (Var _ v)) = text v
ppVal el (C _ c) = integer c
ppVal el (P (Plus l)) = embeddLabel el l <> text "(+)"
ppVal el (P (If l _)) = embeddLabel el l <> text "if"
startAt :: Integer
startAt = 0x100000
labelToChar :: Label -> Char
labelToChar (Label i) = chr (fromIntegral (startAt + i))
charToLabel :: Char -> Maybe Label
charToLabel c = if i >= startAt then Just $ Label (i startAt)
else Nothing
where i = fromIntegral (ord c)
embeddLabel :: Bool -> Label -> Doc
embeddLabel False _ = empty
embeddLabel True l = char (labelToChar l)
labelPositions :: Char -> String -> (Label :⇀ (Integer, Integer), String)
labelPositions rep = (unions *** unlines) . unzip . zipWith labelLines [1..] . lines
where labelLines :: Integer -> String -> (Label :⇀ (Integer, Integer), String)
labelLines row = (unions *** id) . unzip . zipWith labelChar [1..]
where labelChar :: Integer -> Char -> (Label :⇀ (Integer, Integer), Char)
labelChar col c = case charToLabel c of
Just l -> (l `singleton` (row,col), rep)
Nothing -> (mempty, c)
removeLambdas :: String -> String
removeLambdas = map (\c -> if c == 'λ' then '\\' else c)
ipProg :: Prog -> Doc
ipProg = ipLambda
renderProgToIsa :: Prog -> String
renderProgToIsa = renderStyle myStyle . ipProg
where myStyle = style { mode = OneLineMode }
ipLambda :: Lambda -> Doc
ipLambda (Lambda (Label i) vs c) = parens $
text "Lambda" <+> integer i <+> sep
[ brackets $ hsep (punctuate (char ',') (map ipVar vs))
, ipCall c
]
ipVar :: Var -> Doc
ipVar (Var (Label i) n) = parens $ integer i <> char ',' <>
text "''" <> text (quote n) <> text "''"
where quote = map (\c -> if c == '\'' then '_' else c)
ipCall :: Call -> Doc
ipCall (App (Label l) f as) = parens $
text "App" <+> integer l <+> ipVal f <+> brackets (sep (punctuate (char ',') (map ipVal as)))
ipCall (Let (Label l) binds c) = parens $
text "Let" <+> integer l <+> brackets (sep (punctuate (char ',') (map ipBind binds))) $$
ipCall c
where ipBind (v,l) = parens $ ipVar v <> char ',' <> ipLambda l
ipVal :: Val -> Doc
ipVal (L l) = parens $ text "L" <+> ipLambda l
ipVal (R (Label l) v) = parens $ text "R" <+> integer l <+> ipVar v
ipVal (C (Label l) c) = parens $ text "C" <+> integer l <+> integer c
ipVal (P prim) = parens $ text "P" <+> ipPrim prim
ipPrim :: Prim -> Doc
ipPrim (Plus (Label l)) = parens $ text "Plus" <+> integer l
ipPrim (If (Label lt) (Label lf)) = parens $ text "If" <+> integer lt <+> integer lf