{- | Module : $Header$ Description : A pretty printer for Curry Copyright : (c) 1999 - 2004 Wolfgang Lux 2005 Martin Engelke 2011 - 2015 Björn Peemöller 2016 Finn Teegen License : BSD-3-clause Maintainer : bjp@informatik.uni-kiel.de Stability : experimental Portability : portable This module implements a pretty printer for Curry expressions. It was derived from the Haskell pretty printer provided in Simon Marlow's Haskell parser. -} {-# OPTIONS_GHC -Wno-orphans #-} module Curry.Syntax.Pretty ( pPrint, pPrintPrec, ppContext, ppInstanceType, ppIMethodImpl , ppIdent, ppQIdent, ppInfixOp, ppQInfixOp, ppMIdent ) where import Prelude hiding ((<>)) import Curry.Base.Ident import Curry.Base.Pretty import Curry.Syntax.Type import Curry.Syntax.Utils (opName) instance Pretty (Module a) where pPrint (Module _ _ ps m es is ds) = ppModuleHeader ps m es is $$ ppSepBlock ds ppModuleHeader :: [ModulePragma] -> ModuleIdent -> Maybe ExportSpec -> [ImportDecl] -> Doc ppModuleHeader ps m es is | null is = header | otherwise = header $+$ text "" $+$ vcat (map pPrint is) where header = vcat (map pPrint ps) $+$ text "module" <+> ppMIdent m <+> maybePP pPrint es <+> text "where" instance Pretty ModulePragma where pPrint (LanguagePragma _ exts) = ppPragma "LANGUAGE" $ list $ map pPrint exts pPrint (OptionsPragma _ tool args) = ppPragma "OPTIONS" $ maybe empty ((text "_" <>) . pPrint) tool <+> text args ppPragma :: String -> Doc -> Doc ppPragma kw doc = text "{-#" <+> text kw <+> doc <+> text "#-}" instance Pretty Extension where pPrint (KnownExtension _ e) = text (show e) pPrint (UnknownExtension _ e) = text e instance Pretty Tool where pPrint (UnknownTool t) = text t pPrint t = text (show t) instance Pretty ExportSpec where pPrint (Exporting _ es) = parenList (map pPrint es) instance Pretty Export where pPrint (Export _ x) = ppQIdent x pPrint (ExportTypeWith _ tc cs) = ppQIdent tc <> parenList (map ppIdent cs) pPrint (ExportTypeAll _ tc) = ppQIdent tc <> text "(..)" pPrint (ExportModule _ m) = text "module" <+> ppMIdent m instance Pretty ImportDecl where pPrint (ImportDecl _ m q asM is) = text "import" <+> ppQualified q <+> ppMIdent m <+> maybePP ppAs asM <+> maybePP pPrint is where ppQualified q' = if q' then text "qualified" else empty ppAs m' = text "as" <+> ppMIdent m' instance Pretty ImportSpec where pPrint (Importing _ is) = parenList (map pPrint is) pPrint (Hiding _ is) = text "hiding" <+> parenList (map pPrint is) instance Pretty Import where pPrint (Import _ x) = ppIdent x pPrint (ImportTypeWith _ tc cs) = ppIdent tc <> parenList (map ppIdent cs) pPrint (ImportTypeAll _ tc) = ppIdent tc <> text "(..)" ppBlock :: Pretty a => [a] -> Doc ppBlock = vcat . map pPrint ppSepBlock :: Pretty a => [a] -> Doc ppSepBlock = vcat . map (\d -> text "" $+$ pPrint d) instance Pretty (Decl a) where pPrint (InfixDecl _ fix p ops) = ppPrec fix p <+> list (map ppInfixOp ops) pPrint (DataDecl _ tc tvs cs clss) = sep (ppTypeDeclLhs "data" tc tvs : map indent (zipWith (<+>) (equals : repeat vbar) (map pPrint cs) ++ [ppDeriving clss])) pPrint (ExternalDataDecl _ tc tvs) = ppTypeDeclLhs "external data" tc tvs pPrint (NewtypeDecl _ tc tvs nc clss) = sep (ppTypeDeclLhs "newtype" tc tvs <+> equals : map indent [pPrint nc, ppDeriving clss]) pPrint (TypeDecl _ tc tvs ty) = sep [ppTypeDeclLhs "type" tc tvs <+> equals,indent (pPrintPrec 0 ty)] pPrint (TypeSig _ fs ty) = list (map ppIdent fs) <+> text "::" <+> pPrintPrec 0 ty pPrint (FunctionDecl _ _ _ eqs) = vcat (map pPrint eqs) pPrint (ExternalDecl _ vs) = list (map pPrint vs) <+> text "external" pPrint (PatternDecl _ t rhs) = ppRule (pPrintPrec 0 t) equals rhs pPrint (FreeDecl _ vs) = list (map pPrint vs) <+> text "free" pPrint (DefaultDecl _ tys) = text "default" <+> parenList (map (pPrintPrec 0) tys) pPrint (ClassDecl _ _ cx cls clsvar ds) = ppClassInstHead "class" cx (ppIdent cls) (ppIdent clsvar) <+> ppIf (not $ null ds) (text "where") $$ ppIf (not $ null ds) (indent $ ppBlock ds) pPrint (InstanceDecl _ _ cx qcls inst ds) = ppClassInstHead "instance" cx (ppQIdent qcls) (ppInstanceType inst) <+> ppIf (not $ null ds) (text "where") $$ ppIf (not $ null ds) (indent $ ppBlock ds) ppClassInstHead :: String -> Context -> Doc -> Doc -> Doc ppClassInstHead kw cx cls ty = text kw <+> ppContext cx <+> cls <+> ty ppContext :: Context -> Doc ppContext [] = empty ppContext [c] = pPrint c <+> darrow ppContext cs = parenList (map pPrint cs) <+> darrow instance Pretty Constraint where pPrint (Constraint _ qcls ty) = ppQIdent qcls <+> pPrintPrec 2 ty ppInstanceType :: InstanceType -> Doc ppInstanceType = pPrintPrec 2 ppDeriving :: [QualIdent] -> Doc ppDeriving [] = empty ppDeriving [qcls] = text "deriving" <+> ppQIdent qcls ppDeriving qclss = text "deriving" <+> parenList (map ppQIdent qclss) ppPrec :: Infix -> Maybe Precedence -> Doc ppPrec fix p = pPrint fix <+> ppPrio p where ppPrio Nothing = empty ppPrio (Just p') = integer p' ppTypeDeclLhs :: String -> Ident -> [Ident] -> Doc ppTypeDeclLhs kw tc tvs = text kw <+> ppIdent tc <+> hsep (map ppIdent tvs) instance Pretty ConstrDecl where pPrint (ConstrDecl _ c tys) = sep [ ppIdent c <+> fsep (map (pPrintPrec 2) tys) ] pPrint (ConOpDecl _ ty1 op ty2) = sep [ pPrintPrec 1 ty1, ppInfixOp op <+> pPrintPrec 1 ty2 ] pPrint (RecordDecl _ c fs) = sep [ ppIdent c <+> record (list (map pPrint fs)) ] instance Pretty FieldDecl where pPrint (FieldDecl _ ls ty) = list (map ppIdent ls) <+> text "::" <+> pPrintPrec 0 ty instance Pretty NewConstrDecl where pPrint (NewConstrDecl _ c ty) = sep [ppIdent c <+> pPrintPrec 2 ty] pPrint (NewRecordDecl _ c (i,ty)) = sep [ppIdent c <+> record (ppIdent i <+> text "::" <+> pPrintPrec 0 ty)] ppQuantifiedVars :: [Ident] -> Doc ppQuantifiedVars tvs | null tvs = empty | otherwise = text "forall" <+> hsep (map ppIdent tvs) <+> char '.' instance Pretty (Equation a) where pPrint (Equation _ lhs rhs) = ppRule (pPrint lhs) equals rhs instance Pretty (Lhs a) where pPrint (FunLhs _ f ts) = ppIdent f <+> fsep (map (pPrintPrec 2) ts) pPrint (OpLhs _ t1 f t2) = pPrintPrec 1 t1 <+> ppInfixOp f <+> pPrintPrec 1 t2 pPrint (ApLhs _ lhs ts) = parens (pPrint lhs) <+> fsep (map (pPrintPrec 2) ts) ppRule :: Doc -> Doc -> Rhs a -> Doc ppRule lhs eq (SimpleRhs _ _ e ds) = sep [lhs <+> eq, indent (pPrintPrec 0 e)] $$ ppLocalDefs ds ppRule lhs eq (GuardedRhs _ _ es ds) = sep [lhs, indent (vcat (map (ppCondExpr eq) es))] $$ ppLocalDefs ds ppLocalDefs :: [Decl a] -> Doc ppLocalDefs ds | null ds = empty | otherwise = indent (text "where" <+> ppBlock ds) -- --------------------------------------------------------------------------- -- Interfaces -- --------------------------------------------------------------------------- instance Pretty Interface where pPrint (Interface m is ds) = text "interface" <+> ppMIdent m <+> text "where" <+> lbrace $$ vcat (punctuate semi $ map pPrint is ++ map pPrint ds) $$ rbrace instance Pretty IImportDecl where pPrint (IImportDecl _ m) = text "import" <+> ppMIdent m instance Pretty IDecl where pPrint (IInfixDecl _ fix p op) = ppPrec fix (Just p) <+> ppQInfixOp op pPrint (HidingDataDecl _ tc k tvs) = text "hiding" <+> ppITypeDeclLhs "data" tc k tvs pPrint (IDataDecl _ tc k tvs cs hs) = sep (ppITypeDeclLhs "data" tc k tvs : map indent (zipWith (<+>) (equals : repeat vbar) (map pPrint cs)) ++ [indent (ppHiding hs)]) pPrint (INewtypeDecl _ tc k tvs nc hs) = sep [ ppITypeDeclLhs "newtype" tc k tvs <+> equals , indent (pPrint nc) , indent (ppHiding hs) ] pPrint (ITypeDecl _ tc k tvs ty) = sep [ppITypeDeclLhs "type" tc k tvs <+> equals,indent (pPrintPrec 0 ty)] pPrint (IFunctionDecl _ f cm a ty) = sep [ ppQIdent f, maybePP (ppPragma "METHOD" . ppIdent) cm , int a, text "::", pPrintPrec 0 ty ] pPrint (HidingClassDecl _ cx qcls k clsvar) = text "hiding" <+> ppClassInstHead "class" cx (ppQIdentWithKind qcls k) (ppIdent clsvar) pPrint (IClassDecl _ cx qcls k clsvar ms hs) = ppClassInstHead "class" cx (ppQIdentWithKind qcls k) (ppIdent clsvar) <+> lbrace $$ vcat (punctuate semi $ map (indent . pPrint) ms) $$ rbrace <+> ppHiding hs pPrint (IInstanceDecl _ cx qcls inst impls m) = ppClassInstHead "instance" cx (ppQIdent qcls) (ppInstanceType inst) <+> lbrace $$ vcat (punctuate semi $ map (indent . ppIMethodImpl) impls) $$ rbrace <+> maybePP (ppPragma "MODULE" . ppMIdent) m ppITypeDeclLhs :: String -> QualIdent -> Maybe KindExpr -> [Ident] -> Doc ppITypeDeclLhs kw tc k tvs = text kw <+> ppQIdentWithKind tc k <+> hsep (map ppIdent tvs) instance Pretty IMethodDecl where pPrint (IMethodDecl _ f a qty) = ppIdent f <+> maybePP int a <+> text "::" <+> pPrintPrec 0 qty ppIMethodImpl :: IMethodImpl -> Doc ppIMethodImpl (f, a) = ppIdent f <+> int a ppQIdentWithKind :: QualIdent -> Maybe KindExpr -> Doc ppQIdentWithKind tc (Just k) = parens $ ppQIdent tc <+> text "::" <+> pPrintPrec 0 k ppQIdentWithKind tc Nothing = ppQIdent tc ppHiding :: [Ident] -> Doc ppHiding hs | null hs = empty | otherwise = ppPragma "HIDING" $ list $ map ppIdent hs -- --------------------------------------------------------------------------- -- Kinds -- --------------------------------------------------------------------------- instance Pretty KindExpr where pPrintPrec _ Star = char '*' pPrintPrec p (ArrowKind k1 k2) = parenIf (p > 0) (fsep (ppArrowKind (ArrowKind k1 k2))) where ppArrowKind (ArrowKind k1' k2') = pPrintPrec 1 k1' <+> rarrow : ppArrowKind k2' ppArrowKind k = [pPrintPrec 0 k] -- --------------------------------------------------------------------------- -- Types -- --------------------------------------------------------------------------- instance Pretty QualTypeExpr where pPrint (QualTypeExpr _ cx ty) = ppContext cx <+> pPrintPrec 0 ty instance Pretty TypeExpr where pPrintPrec _ (ConstructorType _ tc) = ppQIdent tc pPrintPrec p (ApplyType _ ty1 ty2) = parenIf (p > 1) (ppApplyType ty1 [ty2]) where ppApplyType (ApplyType _ ty1' ty2') tys = ppApplyType ty1' (ty2' : tys) ppApplyType ty tys = pPrintPrec 1 ty <+> fsep (map (pPrintPrec 2) tys) pPrintPrec _ (VariableType _ tv) = ppIdent tv pPrintPrec _ (TupleType _ tys) = parenList (map (pPrintPrec 0) tys) pPrintPrec _ (ListType _ ty) = brackets (pPrintPrec 0 ty) pPrintPrec p (ArrowType spi ty1 ty2) = parenIf (p > 0) (fsep (ppArrowType (ArrowType spi ty1 ty2))) where ppArrowType (ArrowType _ ty1' ty2') = pPrintPrec 1 ty1' <+> rarrow : ppArrowType ty2' ppArrowType ty = [pPrintPrec 0 ty] pPrintPrec _ (ParenType _ ty) = parens (pPrintPrec 0 ty) pPrintPrec p (ForallType _ vs ty) | null vs = pPrintPrec p ty | otherwise = parenIf (p > 0) $ ppQuantifiedVars vs <+> pPrintPrec 0 ty -- --------------------------------------------------------------------------- -- Literals -- --------------------------------------------------------------------------- instance Pretty Literal where pPrint (Char c) = text (show c) pPrint (Int i) = integer i pPrint (Float f) = double f pPrint (String s) = text (show s) -- --------------------------------------------------------------------------- -- Patterns -- --------------------------------------------------------------------------- instance Pretty (Pattern a) where pPrintPrec p (LiteralPattern _ _ l) = parenIf (p > 1 && isNegative l) (pPrint l) where isNegative (Char _) = False isNegative (Int i) = i < 0 isNegative (Float f) = f < 0.0 isNegative (String _) = False pPrintPrec p (NegativePattern _ _ l) = parenIf (p > 1) (ppInfixOp minusId <> pPrint l) pPrintPrec _ (VariablePattern _ _ v) = ppIdent v pPrintPrec p (ConstructorPattern _ _ c ts) = parenIf (p > 1 && not (null ts)) (ppQIdent c <+> fsep (map (pPrintPrec 2) ts)) pPrintPrec p (InfixPattern _ _ t1 c t2) = parenIf (p > 0) (sep [pPrintPrec 1 t1 <+> ppQInfixOp c, indent (pPrintPrec 0 t2)]) pPrintPrec _ (ParenPattern _ t) = parens (pPrintPrec 0 t) pPrintPrec _ (TuplePattern _ ts) = parenList (map (pPrintPrec 0) ts) pPrintPrec _ (ListPattern _ _ ts) = bracketList (map (pPrintPrec 0) ts) pPrintPrec _ (AsPattern _ v t) = ppIdent v <> char '@' <> pPrintPrec 2 t pPrintPrec _ (LazyPattern _ t) = char '~' <> pPrintPrec 2 t pPrintPrec p (FunctionPattern _ _ f ts) = parenIf (p > 1 && not (null ts)) (ppQIdent f <+> fsep (map (pPrintPrec 2) ts)) pPrintPrec p (InfixFuncPattern _ _ t1 f t2) = parenIf (p > 0) (sep [pPrintPrec 1 t1 <+> ppQInfixOp f, indent (pPrintPrec 0 t2)]) pPrintPrec p (RecordPattern _ _ c fs) = parenIf (p > 1) (ppQIdent c <+> record (list (map pPrint fs))) instance Pretty a => Pretty (Field a) where pPrint (Field _ l t) = ppQIdent l <+> equals <+> pPrintPrec 0 t -- --------------------------------------------------------------------------- -- Expressions -- --------------------------------------------------------------------------- ppCondExpr :: Doc -> CondExpr a -> Doc ppCondExpr eq (CondExpr _ g e) = vbar <+> sep [pPrintPrec 0 g <+> eq, indent (pPrintPrec 0 e)] instance Pretty (Expression a) where pPrintPrec _ (Literal _ _ l) = pPrint l pPrintPrec _ (Variable _ _ v) = ppQIdent v pPrintPrec _ (Constructor _ _ c) = ppQIdent c pPrintPrec _ (Paren _ e) = parens (pPrintPrec 0 e) pPrintPrec p (Typed _ e ty) = parenIf (p > 0) (pPrintPrec 0 e <+> text "::" <+> pPrintPrec 0 ty) pPrintPrec _ (Tuple _ es) = parenList (map (pPrintPrec 0) es) pPrintPrec _ (List _ _ es) = bracketList (map (pPrintPrec 0) es) pPrintPrec _ (ListCompr _ e qs) = brackets (pPrintPrec 0 e <+> vbar <+> list (map pPrint qs)) pPrintPrec _ (EnumFrom _ e) = brackets (pPrintPrec 0 e <+> text "..") pPrintPrec _ (EnumFromThen _ e1 e2) = brackets (pPrintPrec 0 e1 <> comma <+> pPrintPrec 0 e2 <+> text "..") pPrintPrec _ (EnumFromTo _ e1 e2) = brackets (pPrintPrec 0 e1 <+> text ".." <+> pPrintPrec 0 e2) pPrintPrec _ (EnumFromThenTo _ e1 e2 e3) = brackets (pPrintPrec 0 e1 <> comma <+> pPrintPrec 0 e2 <+> text ".." <+> pPrintPrec 0 e3) pPrintPrec p (UnaryMinus _ e) = parenIf (p > 1) (ppInfixOp minusId <> pPrintPrec 1 e) pPrintPrec p (Apply _ e1 e2) = parenIf (p > 1) (sep [pPrintPrec 1 e1, indent (pPrintPrec 2 e2)]) pPrintPrec p (InfixApply _ e1 op e2) = parenIf (p > 0) (sep [pPrintPrec 1 e1 <+> ppQInfixOp (opName op), indent (pPrintPrec 1 e2)]) pPrintPrec _ (LeftSection _ e op) = parens (pPrintPrec 1 e <+> ppQInfixOp (opName op)) pPrintPrec _ (RightSection _ op e) = parens (ppQInfixOp (opName op) <+> pPrintPrec 1 e) pPrintPrec p (Lambda _ t e) = parenIf (p > 0) $ sep [backsl <> fsep (map (pPrintPrec 2) t) <+> rarrow, indent (pPrintPrec 0 e)] pPrintPrec p (Let _ _ ds e) = parenIf (p > 0) (sep [text "let" <+> ppBlock ds, text "in" <+> pPrintPrec 0 e]) pPrintPrec p (Do _ _ sts e) = parenIf (p > 0) (text "do" <+> (vcat (map pPrint sts) $$ pPrintPrec 0 e)) pPrintPrec p (IfThenElse _ e1 e2 e3) = parenIf (p > 0) (text "if" <+> sep [pPrintPrec 0 e1, text "then" <+> pPrintPrec 0 e2, text "else" <+> pPrintPrec 0 e3]) pPrintPrec p (Case _ _ ct e alts) = parenIf (p > 0) (pPrint ct <+> pPrintPrec 0 e <+> text "of" $$ indent (vcat (map pPrint alts))) pPrintPrec p (Record _ _ c fs) = parenIf (p > 0) (ppQIdent c <+> record (list (map pPrint fs))) pPrintPrec _ (RecordUpdate _ e fs) = pPrintPrec 0 e <+> record (list (map pPrint fs)) instance Pretty (Statement a) where pPrint (StmtExpr _ e) = pPrintPrec 0 e pPrint (StmtBind _ t e) = sep [pPrintPrec 0 t <+> larrow, indent (pPrintPrec 0 e)] pPrint (StmtDecl _ _ ds) = text "let" <+> ppBlock ds instance Pretty CaseType where pPrint Rigid = text "case" pPrint Flex = text "fcase" instance Pretty (Alt a) where pPrint (Alt _ t rhs) = ppRule (pPrintPrec 0 t) rarrow rhs instance Pretty (Var a) where pPrint (Var _ ident) = ppIdent ident instance Pretty (InfixOp a) where pPrint (InfixOp _ op) = ppQInfixOp op pPrint (InfixConstr _ op) = ppQInfixOp op -- --------------------------------------------------------------------------- -- Names -- --------------------------------------------------------------------------- -- |Pretty print an identifier ppIdent :: Ident -> Doc ppIdent x = parenIf (isInfixOp x) (text (idName x)) ppQIdent :: QualIdent -> Doc ppQIdent x = parenIf (isQInfixOp x) (text (qualName x)) ppInfixOp :: Ident -> Doc ppInfixOp x = bquotesIf (not (isInfixOp x)) (text (idName x)) ppQInfixOp :: QualIdent -> Doc ppQInfixOp x = bquotesIf (not (isQInfixOp x)) (text (qualName x)) ppMIdent :: ModuleIdent -> Doc ppMIdent m = text (moduleName m) -- --------------------------------------------------------------------------- -- Print printing utilities -- --------------------------------------------------------------------------- indent :: Doc -> Doc indent = nest 2 parenList :: [Doc] -> Doc parenList = parens . list record :: Doc -> Doc record doc | isEmpty doc = braces empty | otherwise = braces $ space <> doc <> space bracketList :: [Doc] -> Doc bracketList = brackets . list