{-# OPTIONS_GHC -fno-warn-orphans #-} module Puppet.Parser.PrettyPrinter ( ppStatements ) where import XPrelude.Extra hiding ((<$>)) import XPrelude.PP import qualified Data.Maybe.Strict as S import qualified Data.Text as Text import qualified Data.Tuple.Strict as Tuple import qualified Data.Vector as V import Text.PrettyPrint.ANSI.Leijen ((<$>)) import Puppet.Language import Puppet.Parser.Types parensList :: Pretty a => Vector a -> Doc parensList = tupled . fmap pretty . V.toList hashComma :: (Pretty a, Pretty b) => Vector (Pair a b) -> Doc hashComma = encloseSep lbrace rbrace comma . fmap showC . V.toList where showC (a :!: b) = pretty a <+> "=>" <+> pretty b instance Pretty UDataType where pretty t = case t of UDTType -> "Type" UDTString ma mb -> bounded "String" ma mb UDTInteger ma mb -> bounded "Integer" ma mb UDTFloat ma mb -> bounded "Float" ma mb UDTBoolean -> "Boolean" UDTArray dt mi mmx -> "Array" <> list (pretty dt : pretty mi : maybe [] (pure . pretty) mmx) UDTHash kt dt mi mmx -> "Hash" <> list (pretty kt : pretty dt : pretty mi : maybe [] (pure . pretty) mmx) UDTUndef -> "Undef" UDTScalar -> "Scalar" UDTData -> "Data" UDTOptional o -> "Optional" <> brackets (pretty o) UNotUndef -> "NotUndef" UDTVariant vs -> "Variant" <> list (foldMap (pure . pretty) vs) UDTPattern vs -> "Pattern" <> list (foldMap (pure . pretty) vs) UDTEnum tx -> "Enum" <> list (foldMap (pure . pretty) tx) UDTAny -> "Any" UDTCollection -> "Collection" UDTRegexp mr -> "Regexp" <> foldMap (brackets . pretty) mr where bounded :: (Pretty a, Pretty b) => Doc -> Maybe a -> Maybe b -> Doc bounded s ma mb = s <> case (ma, mb) of (Just a, Nothing) -> list [pretty a] (Just a, Just b) -> list [pretty a, pretty b] _ -> mempty instance Pretty Expression where pretty (Equal a b) = parens (pretty a <+> "==" <+> pretty b) pretty (Different a b) = parens (pretty a <+>"!=" <+> pretty b) pretty (And a b) = parens (pretty a <+> "and" <+> pretty b) pretty (Or a b) = parens (pretty a <+> "or" <+> pretty b) pretty (LessThan a b) = parens (pretty a <+> pretty '<' <+> pretty b) pretty (MoreThan a b) = parens (pretty a <+> pretty '>' <+> pretty b) pretty (LessEqualThan a b) = parens (pretty a <+> "<=" <+> pretty b) pretty (MoreEqualThan a b) = parens (pretty a <+> ">=" <+> pretty b) pretty (RegexMatch a b) = parens (pretty a <+> "=~" <+> pretty b) pretty (NotRegexMatch a b) = parens (pretty a <+> "!~" <+> pretty b) pretty (Contains a b) = parens (pretty a <+> "in" <+> pretty b) pretty (Addition a b) = parens (pretty a <+> pretty '+' <+> pretty b) pretty (Substraction a b) = parens (pretty a <+> pretty '-' <+> pretty b) pretty (Division a b) = parens (pretty a <+> pretty '/' <+> pretty b) pretty (Multiplication a b) = parens (pretty a <+> pretty '*' <+> pretty b) pretty (Modulo a b) = parens (pretty a <+> pretty '%' <+> pretty b) pretty (RightShift a b) = parens (pretty a <+> ">>" <+> pretty b) pretty (LeftShift a b) = parens (pretty a <+> "<<" <+> pretty b) pretty (Lookup a b) = pretty a <> brackets (pretty b) pretty (ConditionalValue a b) = parens (pretty a <+> pretty '?' <+> hashComma b) pretty (Negate a) = pretty '-' <+> parens (pretty a) pretty (Not a) = pretty '!' <+> parens (pretty a) pretty (Terminal a) = pretty a pretty (FunctionApplication e1 e2) = parens (pretty e1) <> "." <> pretty e2 instance Pretty LambdaFunc where pretty (LambdaFunc nm) = bold $ red (ppline nm) instance Pretty LambdaParameters where pretty b = encloseSep (magenta (pretty '|')) (magenta (pretty '|')) comma (V.toList (fmap mkv b)) where pmspace = foldMap ((<> " ") . pretty) mkv (LambdaParam mt v) = pmspace mt <> pretty (UVariableReference v) instance Pretty SearchExpression where pretty (EqualitySearch t e) = ppline t <+> "==" <+> pretty e pretty (NonEqualitySearch t e) = ppline t <+> "!=" <+> pretty e pretty AlwaysTrue = mempty pretty (AndSearch s1 s2) = parens (pretty s1) <+> "and" <+> parens (pretty s2) pretty (OrSearch s1 s2) = parens (pretty s1) <+> "and" <+> parens (pretty s2) instance Pretty UnresolvedValue where pretty (UBoolean True) = dullmagenta "true" pretty (UBoolean False) = dullmagenta "false" pretty (UString s) = pretty '"' <> dullcyan (ppline (stringEscape s)) <> pretty '"' pretty (UNumber n) = cyan (ppline (scientific2text n)) pretty (UInterpolable v) = pretty '"' <> hcat (map specific (V.toList v)) <> pretty '"' where specific (Terminal (UString s)) = dullcyan (ppline (stringEscape s)) specific (Terminal (UVariableReference vr)) = dullblue ("${" <> ppline vr <> "}") specific (Lookup (Terminal (UVariableReference vr)) (Terminal x)) = dullblue ("${" <> ppline vr <> "[" <> pretty x <> "]}") specific x = bold (red (pretty x)) pretty UUndef = dullmagenta (ppline "undef") pretty (UResourceReference t n) = capitalizeR t <> brackets (pretty n) pretty (UArray v) = list (map pretty (V.toList v)) pretty (UHash g) = hashComma g pretty (URegexp r) = pretty r pretty (UVariableReference v) = dullblue (pretty '$' <> ppline v) pretty (UFunctionCall f args) = showFunc f args pretty (UHOLambdaCall c) = pretty c pretty (UDataType dt) = pretty dt instance Pretty HOLambdaCall where pretty (HOLambdaCall hf me bp stts mee) = pretty hf <> parensList me <+> pretty bp <+> nest 2 (pretty '{' <> line <> ppStatements stts <> mmee) <$> pretty '}' where mmee = case mee of S.Just x -> mempty pretty x S.Nothing -> mempty instance Pretty SelectorCase where pretty SelectorDefault = dullmagenta "default" pretty (SelectorType t) = pretty t pretty (SelectorValue v) = pretty v instance Pretty ArrowOp where pretty AssignArrow = "=>" pretty AppendArrow = "+>" showAss :: Vector AttributeDecl -> Doc showAss vx = folddoc (\a b -> a <> pretty ',' <$> b) prettyDecl (V.toList vx) where folddoc _ _ [] = mempty folddoc acc docGen (x:xs) = foldl acc (docGen x) (map docGen xs) maxlen = maximum (fmap (\(AttributeDecl k _ _) -> Text.length k) vx) prettyDecl (AttributeDecl k op v) = dullblue (fill maxlen (ppline k)) <+> pretty op <+> pretty v prettyDecl (AttributeWildcard v) = dullblue "*" <+> pretty AssignArrow <+> pretty v showArgs :: Vector (Pair (Pair Text (S.Maybe UDataType)) (S.Maybe Expression)) -> Doc showArgs vec = tupled (map ra lst) where lst = V.toList vec maxlen = maximum (map (Text.length . Tuple.fst . Tuple.fst) lst) ra (argname :!: mtype :!: rval) = dullblue (pretty '$' <> foldMap (\t -> pretty t <+> mempty) mtype <> fill maxlen (ppline argname)) <> foldMap (\v -> mempty <+> pretty '=' <+> pretty v) rval showFunc :: Text -> Vector Expression -> Doc showFunc funcname args = bold (red (ppline funcname)) <> parensList args braceStatements :: Vector Statement -> Doc braceStatements stts = nest 2 (pretty '{' <$> ppStatements stts) <$> pretty '}' instance Pretty NodeDesc where pretty NodeDefault = dullmagenta "default" pretty (NodeName n) = pretty (UString n) pretty (NodeMatch r) = pretty (URegexp r) instance Pretty VarAssignDecl where pretty (VarAssignDecl mt vs expr p) = foldMap (\t -> pretty t <+> mempty) mt <> dullblue (foldMap (\v -> pretty '$' <> ppline v) vs) <+> pretty '=' <+> pretty expr <+> showPPos p instance Pretty Statement where pretty (HigherOrderLambdaDeclaration (HigherOrderLambdaDecl c p)) = pretty c <+> showPPos p pretty (ConditionalDeclaration (ConditionalDecl conds p)) | V.null conds = mempty | otherwise = "if" <+> pretty firstcond <+> showPPos p <+> braceStatements firststts <$> vcat (map rendernexts xs) where ( (firstcond :!: firststts) : xs ) = V.toList conds rendernexts (Terminal (UBoolean True) :!: st) = "else" <+> braceStatements st rendernexts (c :!: st) | V.null st = mempty | otherwise = "elsif" <+> pretty c <+> braceStatements st pretty (MainFunctionDeclaration (MainFuncDecl funcname args p)) = showFunc funcname args <+> showPPos p pretty (ResourceDefaultDeclaration (ResDefaultDecl rtype defaults p)) = capitalizeR rtype <+> nest 2 (pretty '{' <+> showPPos p <$> showAss defaults) <$> pretty '}' pretty (ResourceOverrideDeclaration (ResOverrideDecl rtype rnames overs p)) = pretty (UResourceReference rtype rnames) <+> nest 2 (pretty '{' <+> showPPos p <$> showAss overs) <$> pretty '}' pretty (ResourceDeclaration (ResDecl rtype rname args virt p)) = nest 2 (red vrt <> dullgreen (ppline rtype) <+> pretty '{' <+> showPPos p <$> nest 2 (pretty rname <> pretty ':' <$> showAss args)) <$> pretty '}' where vrt = case virt of Normal -> mempty Virtual -> pretty '@' Exported -> "@@" ExportedRealized -> "!!" pretty (DefineDeclaration (DefineDecl cname args stts p)) = dullyellow "define" <+> dullgreen (ppline cname) <> showArgs args <+> showPPos p <$> braceStatements stts pretty (ClassDeclaration (ClassDecl cname args inherit stts p)) = dullyellow "class" <+> dullgreen (ppline cname) <> showArgs args <> inheritance <+> showPPos p <$> braceStatements stts where inheritance = case inherit of S.Nothing -> mempty S.Just x -> mempty <+> "inherits" <+> ppline x pretty (VarAssignmentDeclaration decl) = pretty decl pretty (NodeDeclaration (NodeDecl nodename stmts i p)) = dullyellow "node" <+> pretty nodename <> inheritance <+> showPPos p <$> braceStatements stmts where inheritance = case i of S.Nothing -> mempty S.Just n -> mempty <+> ppline "inherits" <+> pretty n pretty (DependencyDeclaration (DepDecl (st :!: sn) (dt :!: dn) lt p)) = pretty (UResourceReference st sn) <+> pretty lt <+> pretty (UResourceReference dt dn) <+> showPPos p pretty (TopContainer a b) = "TopContainer:" <+> braces ( nest 2 ("TOP" <$> braceStatements a <$> "STATEMENT" <$> pretty b)) pretty (ResourceCollectionDeclaration (ResCollDecl coltype restype search overrides p)) = capitalizeR restype <> enc (pretty search) <+> overs where overs | V.null overrides = showPPos p | otherwise = nest 2 (pretty '{' <+> showPPos p <$> showAss overrides) <$> pretty '}' enc = case coltype of Collector -> enclose "<|" "|>" ExportedCollector -> enclose "<<|" "|>>" -- | Pretty print a series of statements. ppStatements :: Vector Statement -> Doc ppStatements = vcat . map pretty . V.toList