packages feed

inch-0.1.0: src/Language/Inch/PrettyPrinter.lhs

> {-# LANGUAGE TypeSynonymInstances, FlexibleInstances, FlexibleContexts,
>              TypeOperators, GADTs, PatternGuards #-}

> module Language.Inch.PrettyPrinter where

> import Data.Foldable
> import Data.List
> import Text.PrettyPrint.HughesPJ

> import Language.Inch.Kind
> import Language.Inch.Type
> import Language.Inch.BwdFwd
> import Language.Inch.Syntax
> import Language.Inch.ModuleSyntax
> import Language.Inch.Kit


> data Size = ArgSize | AppSize | ArrSize | LamSize
>     deriving (Bounded, Eq, Ord, Show)

> class Pretty x where
>     pretty :: x -> Size -> Doc

> prettyLow :: Pretty x => x -> Doc
> prettyLow = flip pretty minBound

> prettyHigh :: Pretty x => x -> Doc
> prettyHigh = flip pretty maxBound

> wrapDoc :: Size -> Doc -> Size -> Doc
> wrapDoc dSize d curSize
>   | dSize > curSize  = parens d
>   | otherwise        = d

> prettyVar :: Var () k -> Doc
> prettyVar = prettyHigh . fogVar

> prettySysVar :: Var () k -> Doc
> prettySysVar = prettyHigh . fogSysVar

> prettyFog :: (TravTypes1 t, Pretty (t RAW ())) => t OK () -> Doc
> prettyFog = prettyHigh . fog1

> prettyFogSys :: (TravTypes1 t, Pretty (t RAW ())) => t OK () -> Doc
> prettyFogSys = prettyHigh . fogSys

> renderMe :: Pretty a => a -> String
> renderMe x = renderStyle style{ribbonsPerLine=1.2, lineLength=80} (prettyHigh x)

> (<++>) :: Doc -> Doc -> Doc
> d1 <++> d2 = sep [d1, nest 2 d2]
> infix 2 <++>


> instance Pretty String where
>     pretty s _ = text s

> instance Pretty [STopDeclaration] where
>     pretty ds _ = vcat (map prettyHigh ds)

> instance Pretty SKind where
>     pretty SKSet       = const $ text "*"
>     pretty SKNum       = const $ text "Integer"
>     pretty SKNat       = const $ text "Nat"
>     pretty SKConstraint = const $ text "Constraint"
>     pretty (k :--> l)  = wrapDoc AppSize $
>         pretty k ArgSize <+> text "->" <+> pretty l AppSize

> instance Pretty Binder where
>     pretty Pi _   = text "pi"
>     pretty All _  = text "forall"

> instance Pretty ty => Pretty (Pred ty) where
>     pretty (P c n m) = wrapDoc AppSize $
>         pretty n ArgSize <+> pretty c ArgSize <+> pretty m ArgSize
>     pretty (p :=> q) = wrapDoc AppSize $ 
>         pretty p ArgSize <+> text "=>" <++> pretty q ArgSize

> instance Pretty Comparator where
>     pretty LS _ = text "<"
>     pretty LE _ = text "<=" 
>     pretty GR _ = text ">"
>     pretty GE _ = text ">="
>     pretty EL _ = text "~"

> instance Pretty UnOp where
>     pretty o _ = text $ unOpString o

> instance Pretty BinOp where
>     pretty o _ | binOpInfix o  = text $ "(" ++ binOpString o ++ ")"
>                | otherwise     = text $ binOpString o

> instance Pretty SType where
>     pretty (STyVar v)                  = const $ text v
>     pretty (STyCon c)                  = const $ text c
>     pretty (STyApp (STyCon l) t) | l == listTypeName  = const $ brackets (prettyHigh t)
>     pretty (STyApp (STyApp (STyCon c) s) t) | c == tupleTypeName = const $ parens (prettyHigh s <> text "," <+> prettyHigh t)
>     pretty (STyApp (STyApp f s) t) | Just fx <- infixName f = wrapDoc ArrSize $ 
>         pretty s AppSize <+> text fx <++> pretty t AppSize
>     pretty (STyApp f s)  = wrapDoc AppSize $ 
>         pretty f AppSize <+> pretty s ArgSize
>     pretty (SBind b a k t)  = prettyBind b (B0 :< (a, k)) t
>     pretty (SQual p t)      = prettyQual (B0 :< p) t
>     pretty SArr             = const $ text "(->)"
>     pretty (STyInt k)       = wrapDoc (if k < 0 then ArrSize else minBound) $
>                                   integer k
>     pretty (SBinOp o)       = pretty o
>     pretty (SUnOp o)        = pretty o
>     pretty (STyComp c)      = const . parens $ prettyHigh c
 
> infixName :: SType -> Maybe String
> infixName SArr                       = Just "->"
> infixName (SBinOp o) | binOpInfix o  = Just (binOpString o)
> infixName (STyCon ('(':s))           = Just (init s)
> infixName (STyComp c)                = Just (show (prettyHigh c))
> infixName _                          = Nothing


> prettyBind :: Binder -> Bwd (String, SKind) ->
>     SType -> Size -> Doc
> prettyBind b bs (SBind b' a k t) | b == b' = prettyBind b (bs :< (a, k)) t
> -- prettyBind b (bs :< (a, SKNum)) (SQual (P LE 0 (STyVar a')) t) | a == a' = prettyBind b (bs :< (a, SKNat)) t
> prettyBind b bs t = wrapDoc LamSize $ prettyHigh b
>         <+> prettyBits (trail bs)
>         <+> text "." <++> pretty t ArrSize
>   where
>     prettyBits []             = empty
>     prettyBits ((a, SKSet) : aks) = text a <+> prettyBits aks
>     prettyBits ((a, k) : aks) = parens (text a <+> text "::" <+> prettyHigh k) <+> prettyBits aks


> prettyQual :: Bwd SType -> SType -> Size -> Doc
> prettyQual ps (SQual p t) = prettyQual (ps :< p) t
> prettyQual ps t = wrapDoc ArrSize $
>     prettyPreds (trail ps) <+> text "=>" <++> pretty t ArrSize
>   where
>     prettyPreds xs = parens (hsep (punctuate (text ",") (map prettyHigh xs)))


> instance Pretty (STerm a) where
>     pretty (TmVar x)    = const $ text x
>     pretty (TmCon s)    = const $ text s
>     pretty (TmInt k)    = wrapDoc (if k < 0 then ArrSize else minBound) $
>                               integer k
>     pretty (CharLit c)  = const $ text $ show c
>     pretty (StrLit s)   = const $ text $ show s
>     -- pretty (TmApp (TmApp f m) n) | Just s <- infixTmName f =
>     --    wrapDoc AppSize $ pretty m ArgSize <+> text s <+> pretty n ArgSize
>     pretty (TmApp f s)  = wrapDoc AppSize $
>         pretty f AppSize <++> pretty s ArgSize
>     pretty (TmBrace n)  = const $ braces $ prettyHigh n 
>     pretty (Lam x t)    = prettyLam (text x) t
>     pretty (NumLam x t) = prettyLam (braces (text x)) t
>     pretty (Let ds t)   = wrapDoc maxBound $ text "let" <+> vcatSpacePretty ds $$ text "in" <+> prettyHigh t
>     pretty (Case t as)  = wrapDoc maxBound $ text "case" <+> prettyHigh t <+> text "of" <++> vcatPretty as
>     pretty (t :? ty)    = wrapDoc ArrSize $ 
>         pretty t AppSize <+> text "::" <+> pretty ty maxBound

> infixTmName :: STerm a -> Maybe String
> infixTmName (TmVar ('(':v)) = Just (init v)
> infixTmName _ = Nothing

> prettyLam :: Doc -> STerm a -> Size -> Doc
> prettyLam d (Lam x t) = prettyLam (d <+> text x) t
> prettyLam d (NumLam a t) = prettyLam (d <+> braces (text a)) t
> prettyLam d t = wrapDoc LamSize $
>         text "\\" <+> d <+> text "->" <+> pretty t AppSize


> parenCommaList :: Doc -> [String] -> Doc
> parenCommaList _ [] = empty
> parenCommaList d xs = d <+> parens (hsep (punctuate (text ",") (map text xs)))


> instance Pretty SModule where
>     pretty (Mod mh is ds) _ = maybe empty prettyModHeader mh
>                                   $$ vcat (map prettyHigh is)
>                                   $$ vcat (intersperse (text " ") (map prettyHigh ds))
>       where
>         prettyModHeader (s, es) = text "module" <+> text s <+> parenCommaList empty es <+> text "where"


> instance Pretty Import where
>     pretty (Import q n as imp) _ = text "import"
>                                            <+> (if q then text "qualified" else empty)
>                                            <+> text n
>                                            <+> (maybe empty (\ s -> text "as" <+> text s) as)
>                                            <+> prettyHigh imp

> instance Pretty ImpSpec where
>     pretty ImpAll          _ = empty
>     pretty (Imp xs)        _ = parens (hsep (punctuate (text ",") (map text xs)))
>     pretty (ImpHiding xs)  _ = text "hiding" <+> parens (hsep (punctuate (text ",") (map text xs)))


> instance Pretty STypeSyn where
>     pretty (SSynTy t)      _ = text "=" <+> prettyHigh t
>     pretty (SSynAll x k t) _ = kindBracket k <+> prettyHigh t
>       where
>         kindBracket SKSet  = text x
>         kindBracket l      = parens (text x <+> text "::" <+> prettyHigh l)

> instance Pretty STopDeclaration where
>     pretty (DataDecl n k cs ds) _ = hang (text "data" <+> text n
>         <+> (if k /= SKSet then text "::" <+> prettyHigh k else empty)
>         <+> text "where") 2 $
>             vcat (map prettyHigh cs) $$ derivingClause ds
>       where
>         derivingClause []  = empty
>         derivingClause xs  = text "deriving" <+>
>                                parens (hsep (punctuate  (text ",") (map text xs)))
>     pretty (TypeDecl x t) _ = text "type" <+> text x <+> prettyHigh t
>     pretty (CDecl x (ClassDecl vs ss ms)) _ =
>         hang (text "class"
>               <+> (if null ss then empty else parens (fsepPretty ss) <+> text "=>")
>               <+> text x <+> fsep (map prettyHigh vs)
>               <+> text "where") 2 $
>                   vcat (map prettyHigh ms)
>     pretty (IDecl x (InstDecl ts cs zs)) _ =
>         hang (text "instance"
>               <+> (if null cs then empty else parens (fsepPretty cs) <+> text "=>")
>               <+> text x  <+> fsep (map prettyLow ts)
>               <+> text "where") 2 $
>                   vcat (map (prettyHigh . uncurry FunDecl) zs)
>     pretty (Decl d) s = pretty d s

> instance Pretty (SDeclaration a) where
>     pretty (FunDecl n ps) _ = vcat (map ((text n <+>) . prettyHigh) ps)
>     pretty (SigDecl n ty) _ = text n <+> text "::" <+> prettyHigh ty


> instance (Pretty x, Pretty p) => Pretty (x ::: p) where
>   pretty (x ::: p) _ = prettyHigh x <+> text "::" <+> prettyHigh p



> instance Pretty (SCaseAlternative a) where
>     pretty (CaseAlt v gt) _ = prettyHigh v <+> prettyGuardTerms (text "->") gt

> instance Pretty (SAlternative a) where
>     pretty (Alt vs gt) _ = prettyLow vs <+> prettyGuardTerms (text "=") gt


> prettyGuardTerms :: Doc -> SGuardTerms a -> Doc
> prettyGuardTerms d (Unguarded e ds) = d <++> prettyHigh e $$ prettyWhere ds
> prettyGuardTerms d (Guarded gts ds) =
>     vcat (map (\ (g :*: e) -> text "|" <+> prettyLow g <+> d <+> prettyHigh e) gts)
>     $$ prettyWhere ds

> prettyWhere :: [SDeclaration a] -> Doc 
> prettyWhere []  = empty
> prettyWhere ds  = text "where" <+> vcat (map prettyHigh ds)



> instance Pretty (SPatternList a b) where
>     pretty P0         _  = empty
>     pretty (p :! ps)  z  = pretty p z <+> pretty ps z

> instance Pretty (SPattern a b) where
>     pretty (PatVar x)    = const $ text x
>     pretty (PatCon c P0) = const $ text c
>     pretty (PatCon "+" (a :! b:! P0)) = wrapDoc AppSize $
>         prettyLow a <+> text "+" <+> prettyLow b
>     pretty (PatCon c ps) = wrapDoc AppSize $
>                                text c <+> prettyLow ps
>     pretty PatIgnore = const $ text "_"
>     pretty (PatBraceK k)   = const $ braces $ integer k
>     pretty (PatBrace a 0)  = const $ braces $ text a
>     pretty (PatBrace a k)  = const $ braces $
>                                     text a <+> text "+" <+> integer k
>     pretty (PatIntLit i)   = const $ integer i
>     pretty (PatCharLit c)  = const $ text $ show c
>     pretty (PatStrLit s)   = const $ text $ show s
>     pretty (PatNPlusK n k) = const $ parens $ text n <+> text "+" <+> integer k

> instance Pretty (SGuard a) where
>     pretty (ExpGuard t)  = const $ fsepPretty t
>     pretty (NumGuard p)  = const $ braces (fsepPretty p)


> instance Pretty (VarList RAW a b) where
>     pretty P0         _  = empty
>     pretty (p :! ps)  z  = pretty p z <+> pretty ps z

> instance Pretty (VarBinding RAW a b) where
>     pretty (VB x SKSet) _ = prettyHigh x
>     pretty (VB x k)     _ = parens (prettyHigh x <+> text "::" <+> prettyHigh k)

> instance Pretty (TyList RAW a b) where
>     pretty P0               _  = empty
>     pretty (TyK t _ :! ps)  z  = pretty t z <+> pretty ps z

> instance Pretty (VarKind RAW ()) where
>     pretty (VK v _) = pretty v

> {-
> instance Pretty SNormalPred where
>     pretty p = pretty (reifyPred p)

> instance Pretty SNormalNum where
>     pretty n _ = prettyHigh $ reifyNum n
> -}

> instance Pretty x => Pretty (Bwd x) where
>     pretty bs _ = fsep $ punctuate (text ",") (map prettyHigh (trail bs))

> instance Pretty x => Pretty (Fwd x) where
>     pretty bs _ = fsep $ punctuate (text ",") $ map prettyHigh $ Data.Foldable.foldr (:) [] bs


> fsepPretty :: Pretty a => [a] -> Doc
> fsepPretty xs  = fsep . punctuate (text ",") . map prettyHigh $ xs

> vcatSpacePretty :: Pretty a => [a] -> Doc
> vcatSpacePretty xs  = vcat . intersperse (text " ") . map prettyHigh $ xs

> vcatPretty :: Pretty a => [a] -> Doc
> vcatPretty xs  = vcat . map prettyHigh $ xs