{-# LANGUAGE CPP #-}
module Language.Python.Common.PrettyAST () where
#if __GLASGOW_HASKELL__ >= 803
import Prelude hiding ((<>))
#endif
import Language.Python.Common.Pretty
import Language.Python.Common.AST
import Data.Maybe (isJust, fromMaybe)
dot :: Doc
dot = char '.'
indent :: Doc -> Doc
indent doc = nest 4 doc
blankLine :: Doc
blankLine = text []
prettyString :: String -> Doc
prettyString str = text str
instance Pretty (Module a) where
pretty (Module stmts) = vcat $ map pretty stmts
instance Pretty (Ident a) where
pretty name@(Ident {}) = text $ ident_string name
prettyDottedName :: DottedName a -> Doc
prettyDottedName [] = empty
prettyDottedName [name] = pretty name
prettyDottedName (name:rest@(_:_))
= pretty name <> dot <> prettyDottedName rest
instance Pretty (ImportItem a) where
pretty (ImportItem {import_item_name = name, import_as_name = asName})
= prettyDottedName name <+> (maybe empty (\n -> text "as" <+> pretty n) asName)
instance Pretty (FromItem a) where
pretty (FromItem { from_item_name = name, from_as_name = asName })
= pretty name <+> (maybe empty (\n -> text "as" <+> pretty n) asName)
instance Pretty (FromItems a) where
pretty ImportEverything {} = char '*'
pretty (FromItems { from_items_items = [item] }) = pretty item
pretty (FromItems { from_items_items = items }) = parens (commaList items)
instance Pretty (ImportRelative a) where
pretty (ImportRelative { import_relative_dots = dots, import_relative_module = mod })
= case mod of
Nothing -> dotDoc
Just name -> dotDoc <> prettyDottedName name
where
dotDoc = text (replicate dots '.')
prettySuite :: [Statement a] -> Doc
prettySuite stmts = vcat $ map pretty stmts
optionalKeywordSuite :: String -> [Statement a] -> Doc
optionalKeywordSuite _ [] = empty
optionalKeywordSuite keyword stmts = text keyword <> colon $+$ indent (prettySuite stmts)
prettyParenList :: Pretty a => [a] -> Doc
prettyParenList = parens . commaList
prettyOptionalList :: Pretty a => [a] -> Doc
prettyOptionalList [] = empty
prettyOptionalList list = parens $ commaList list
prettyGuards :: [(Expr a, Suite a)] -> Doc
prettyGuards [] = empty
prettyGuards ((cond,body):guards)
= text "elif" <+> pretty cond <> colon $+$ indent (prettySuite body) $+$
prettyGuards guards
instance Pretty (Statement a) where
pretty (Import { import_items = items}) = text "import" <+> commaList items
pretty stmt@(FromImport {})
= text "from" <+> pretty (from_module stmt) <+> text "import" <+> pretty (from_items stmt)
pretty stmt@(While {})
= text "while" <+> pretty (while_cond stmt) <> colon $+$
indent (prettySuite (while_body stmt)) $+$ optionalKeywordSuite "else" (while_else stmt)
pretty stmt@(For {})
= text "for" <+> commaList (for_targets stmt) <+> text "in" <+> pretty (for_generator stmt) <> colon $+$
indent (prettySuite (for_body stmt)) $+$ optionalKeywordSuite "else" (for_else stmt)
pretty (AsyncFor { for_stmt = fs }) = zeroWidthText "async " <> pretty fs
pretty stmt@(Fun {})
= text "def" <+> pretty (fun_name stmt) <> parens (commaList (fun_args stmt)) <+>
perhaps (fun_result_annotation stmt) (text "->") <+>
pretty (fun_result_annotation stmt) <> colon $+$ indent (prettySuite (fun_body stmt))
pretty (AsyncFun { fun_def = fd }) = zeroWidthText "async " <+> pretty fd
pretty stmt@(Class {})
= text "class" <+> pretty (class_name stmt) <> prettyOptionalList (class_args stmt) <>
colon $+$ indent (prettySuite (class_body stmt))
pretty stmt@(Conditional { cond_guards = guards, cond_else = optionalElse })
= case guards of
(cond,body):xs ->
text "if" <+> pretty cond <> colon $+$ indent (prettySuite body) $+$
prettyGuards xs $+$
optionalKeywordSuite "else" optionalElse
[] -> error "Attempt to pretty print conditional statement with empty guards"
pretty (Assign { assign_to = pattern, assign_expr = e })
= equalsList pattern <+> equals <+> pretty e
pretty (AugmentedAssign { aug_assign_to = to_expr, aug_assign_op = op, aug_assign_expr = e})
= pretty to_expr <+> pretty op <+> pretty e
pretty (AnnotatedAssign { ann_assign_annotation = ann_annotate, ann_assign_to = ann_to, ann_assign_expr = ann_expr})
= pretty ann_to <+> text ":" <+> pretty ann_annotate <+> fromMaybe empty (((text "=" <+>) . pretty) <$> ann_expr)
pretty (Decorated { decorated_decorators = decs, decorated_def = stmt})
= vcat (map pretty decs) $+$ pretty stmt
pretty (Return { return_expr = e }) = text "return" <+> pretty e
pretty (Try { try_body = body, try_excepts = handlers, try_else = optionalElse, try_finally = finally})
= text "try" <> colon $+$ indent (prettySuite body) $+$
prettyHandlers handlers $+$ optionalKeywordSuite "else" optionalElse $+$
optionalKeywordSuite "finally" finally
pretty (Raise { raise_expr = e })
= text "raise" <+> pretty e
pretty (With { with_context = context, with_body = body })
= text "with" <+> hcat (punctuate comma (map prettyWithContext context)) <+> colon $+$
indent (prettySuite body)
pretty (AsyncWith { with_stmt = ws }) = zeroWidthText "async " <+> pretty ws
pretty Pass {} = text "pass"
pretty Break {} = text "break"
pretty Continue {} = text "continue"
pretty (Delete { del_exprs = es }) = text "del" <+> commaList es
pretty (StmtExpr { stmt_expr = e }) = pretty e
pretty (Global { global_vars = idents }) = text "global" <+> commaList idents
pretty (NonLocal { nonLocal_vars = idents }) = text "nonlocal" <+> commaList idents
pretty (Assert { assert_exprs = es }) = text "assert" <+> commaList es
pretty (Print { print_chevron = have_chevron, print_exprs = es, print_trailing_comma = trail_comma }) =
text "print" <> (if have_chevron then text " >>" else empty) <+>
hcat (punctuate comma (map pretty es)) <>
if trail_comma then comma else empty
pretty (Exec { exec_expr = e, exec_globals_locals = gls }) =
text "exec" <+> pretty e <+>
maybe empty (\ (globals, next) -> text "in" <+> pretty globals <+>
maybe empty (\locals -> comma <+> pretty locals) next) gls
prettyWithContext :: (Expr a, Maybe (Expr a)) -> Doc
prettyWithContext (e, Nothing) = pretty e
prettyWithContext (e, Just as) = pretty e <+> text "as" <+> pretty as
prettyHandlers :: [Handler a] -> Doc
prettyHandlers = foldr (\next rec -> pretty next $+$ rec) empty
instance Pretty (Handler a) where
pretty (Handler { handler_clause = exceptClause, handler_suite = suite })
= pretty exceptClause <> colon $+$ indent (prettySuite suite)
instance Pretty (ExceptClause a) where
pretty (ExceptClause { except_clause = Nothing }) = text "except"
pretty (ExceptClause { except_clause = Just (e, target)})
= text "except" <+> pretty e <+> maybe empty (\t -> text "as" <+> pretty t) target
instance Pretty (RaiseExpr a) where
pretty (RaiseV3 e) =
maybe empty (\ (x, fromE) -> pretty x <+> (maybe empty (\f -> text "from" <+> pretty f) fromE)) e
pretty (RaiseV2 exp) =
maybe empty (\ (e1, next1) -> pretty e1 <>
maybe empty (\ (e2, next2) -> comma <+> pretty e2 <>
maybe empty (\ e3 -> comma <+> pretty e3) next2) next1) exp
instance Pretty (Decorator a) where
pretty (Decorator { decorator_name = name, decorator_args = args })
= char '@' <> prettyDottedName name <+> prettyOptionalList args
instance Pretty (Parameter a) where
pretty (Param { param_name = ident, param_py_annotation = annot, param_default = def })
= pretty ident <> (maybe empty (\e -> colon <> pretty e <> space) annot) <>
maybe empty (\e -> equals <> pretty e) def
pretty (VarArgsPos { param_name = ident, param_py_annotation = annot})
= char '*' <> pretty ident <> (maybe empty (\e -> colon <> pretty e) annot)
pretty (VarArgsKeyword { param_name = ident, param_py_annotation = annot })
= text "**" <> pretty ident <> (maybe empty (\e -> colon <> pretty e) annot)
pretty EndPositional {} = char '*'
pretty (UnPackTuple { param_unpack_tuple = tuple, param_default = def })
= pretty tuple <> maybe empty (\e -> equals <> pretty e) def
instance Pretty (ParamTuple a) where
pretty (ParamTupleName { param_tuple_name = name }) = pretty name
pretty (ParamTuple { param_tuple = tuple }) = prettyParenList tuple
instance Pretty (Argument a) where
pretty (ArgExpr { arg_expr = e }) = pretty e
pretty (ArgVarArgsPos { arg_expr = e}) = char '*' <> pretty e
pretty (ArgVarArgsKeyword { arg_expr = e }) = text "**" <> pretty e
pretty (ArgKeyword { arg_keyword = ident, arg_expr = e })
= pretty ident <> equals <> pretty e
instance Pretty (Comprehension a) where
pretty (Comprehension { comprehension_expr = e, comprehension_for = for })
= pretty e <+> pretty for
instance Pretty (ComprehensionExpr a) where
pretty (ComprehensionExpr e) = pretty e
pretty (ComprehensionDict d) = pretty d
instance Pretty (CompFor a) where
pretty (CompFor { comp_for_async = ca, comp_for_exprs = es, comp_in_expr = e, comp_for_iter = iter })
= (text $ if ca then "async for" else "for") <+> commaList es
<+> text "in" <+> pretty e <+> pretty iter
instance Pretty (CompIf a) where
pretty (CompIf { comp_if = e, comp_if_iter = iter })
= text "if" <+> pretty e <+> pretty iter
instance Pretty (CompIter a) where
pretty (IterFor { comp_iter_for = compFor }) = pretty compFor
pretty (IterIf { comp_iter_if = compIf }) = pretty compIf
instance Pretty (Expr a) where
pretty (Var { var_ident = i }) = pretty i
pretty (Int { expr_literal = str }) = text str
pretty (LongInt { expr_literal = str }) = text str
pretty (Float { expr_literal = str }) = text str
pretty (Imaginary { expr_literal = str }) = text str
pretty (Bool { bool_value = b}) = pretty b
pretty None {} = text "None"
pretty Ellipsis {} = text "..."
pretty (ByteStrings { byte_string_strings = bs }) = hcat (map pretty bs)
pretty (Strings { strings_strings = ss }) = hcat (map prettyString ss)
pretty (UnicodeStrings { unicodestrings_strings = ss }) = hcat (map prettyString ss)
pretty (Call { call_fun = f, call_args = args }) = pretty f <> prettyParenList args
pretty (Subscript { subscriptee = e, subscript_expr = sub })
= pretty e <> brackets (pretty sub)
pretty (SlicedExpr { slicee = e, slices = ss })
= pretty e <> brackets (commaList ss)
pretty (CondExpr { ce_true_branch = trueBranch, ce_condition = cond, ce_false_branch = falseBranch })
= pretty trueBranch <+> text "if" <+> pretty cond <+> text "else" <+> pretty falseBranch
pretty (BinaryOp { operator = op, left_op_arg = left, right_op_arg = right })
= pretty left <+> pretty op <+> pretty right
pretty (UnaryOp { operator = op, op_arg = e }) = pretty op <+> pretty e
pretty (Dot { dot_expr = e, dot_attribute = a }) =
pretty e <> dot <> pretty a
pretty (Lambda { lambda_args = args, lambda_body = body })
= text "lambda" <+> commaList args <> colon <+> pretty body
pretty (Tuple { tuple_exprs = es }) =
case es of
[] -> text "()"
[e] -> pretty e <> comma
_ -> commaList es
pretty (Yield { yield_arg = arg })
= text "yield" <+> pretty arg
pretty (Generator { gen_comprehension = gc }) = parens $ pretty gc
pretty (Await { await_expr = ae }) = text "await" <+> pretty ae
pretty (ListComp { list_comprehension = lc }) = brackets $ pretty lc
pretty (List { list_exprs = es }) = brackets (commaList es)
pretty (Dictionary { dict_mappings = mappings })
= braces (hsep (punctuate comma $ map pretty mappings))
pretty (DictComp { dict_comprehension = dc }) = braces $ pretty dc
pretty (Set { set_exprs = es }) = braces $ commaList es
pretty (SetComp { set_comprehension = sc }) = braces $ pretty sc
pretty (Paren { paren_expr = e }) = parens $ pretty e
pretty (StringConversion { backquoted_expr = e }) = char '`' <> pretty e <> char '`'
pretty (Starred { starred_expr = e }) = char '*' <> pretty e
instance Pretty (YieldArg a) where
pretty (YieldFrom e _annot) = text "from" <+> pretty e
pretty (YieldExpr e) = pretty e
instance Pretty (DictKeyDatumList a) where
pretty (DictMappingPair key val) = pretty key <> colon <+> pretty val
pretty (DictUnpacking expr) = text "**" <> pretty expr
instance Pretty (Slice a) where
pretty (SliceProper { slice_lower = lower, slice_upper = upper, slice_stride = stride })
= pretty lower <> colon <> pretty upper <> (maybe empty (\s -> colon <> pretty s) stride)
pretty (SliceExpr { slice_expr = e }) = pretty e
pretty (SliceEllipsis {}) = text "..."
instance Pretty (Op a) where
pretty (And {}) = text "and"
pretty (Or {}) = text "or"
pretty (Not {}) = text "not"
pretty (Exponent {}) = text "**"
pretty (LessThan {}) = text "<"
pretty (GreaterThan {}) = text ">"
pretty (Equality {}) = text "=="
pretty (GreaterThanEquals {}) = text ">="
pretty (LessThanEquals {}) = text "<="
pretty (NotEquals {}) = text "!="
pretty (NotEqualsV2 {}) = text "<>"
pretty (In {}) = text "in"
pretty (Is {}) = text "is"
pretty (IsNot {}) = text "is not"
pretty (NotIn {}) = text "not in"
pretty (BinaryOr {}) = text "|"
pretty (Xor {}) = text "^"
pretty (BinaryAnd {}) = text "&"
pretty (ShiftLeft {}) = text "<<"
pretty (ShiftRight {}) = text ">>"
pretty (Multiply {}) = text "*"
pretty (Plus {}) = text "+"
pretty (Minus {}) = text "-"
pretty (Divide {}) = text "/"
pretty (FloorDivide {}) = text "//"
pretty (MatrixMult {}) = text "@"
pretty (Invert {}) = text "~"
pretty (Modulo {}) = text "%"
instance Pretty (AssignOp a) where
pretty (PlusAssign {}) = text "+="
pretty (MinusAssign {}) = text "-="
pretty (MultAssign {}) = text "*="
pretty (DivAssign {}) = text "/="
pretty (ModAssign {}) = text "%="
pretty (PowAssign {}) = text "**="
pretty (BinAndAssign {}) = text "&="
pretty (BinOrAssign {}) = text "|="
pretty (BinXorAssign {}) = text "^="
pretty (LeftShiftAssign {}) = text "<<="
pretty (RightShiftAssign {}) = text ">>="
pretty (FloorDivAssign {}) = text "//="
pretty (MatrixMultAssign {}) = text "@="