{-|

Module      : Language.CSharp.Pretty

Description : Pretty printing of C#



This module contains the pretty printing of the abstract syntax tree defined

in "Language.CSharp.Syntax". Pretty printing results in a syntactically valid 

program.

-}



{-# LANGUAGE FlexibleInstances #-}



module Language.CSharp.Pretty(

      prettyPrint

    , Pretty(..)

) where



import Text.PrettyPrint

import Data.List

import Language.CSharp.Syntax



-- | Pretty printing type class.

class Pretty a where

    pretty :: a -> Doc



instance Pretty Doc where

    pretty = id



-- | Results in the pretty printed value of `a`.

prettyPrint :: Pretty a => a -> String

prettyPrint = render . pretty



instance Pretty CompilationUnit where

    pretty (CompilationUnit usings declarations)

        = pretty usings $+$ pretty declarations



instance Pretty [Using] where

    pretty = vsep



instance Pretty Using where

    pretty (Using name isStatic)

        = text "using" <+> pIsStatic <+> pretty name <> semi

        where

            pIsStatic = if isStatic then text "static" else empty



instance Pretty [Declaration] where

    pretty = foldr (($+$) . pretty) empty 



instance Pretty Declaration where

    pretty (NamespaceDeclaration attributes name declarations)

        = pretty attributes $+$ text "namespace" <+> pretty name 

        $+$ lbrace $+$ tab (pretty declarations) $+$ rbrace



    pretty (TypeDeclaration declaration)

        = pretty declaration



instance Pretty TypeDeclaration where

    pretty (ClassTypeDeclaration attributes modifiers name typeParameters inherits constraints body)

        = pretty attributes $+$ pretty modifiers <+> text "class" <+> pretty name <> pretty typeParameters

        <+> pInherits $+$ pConstraints $+$ lbrace $+$ tab (pretty body) $+$ rbrace

        where

            pConstraints    = (vsep . map (tab . pretty)) constraints

            pInherits       = case inherits of

                                [] -> empty

                                _  -> colon <+> hcatIntersperse comma inherits

                    

    pretty (StructTypeDeclaration attributes modifiers name typeParameters inherits constraints body)

        = pretty attributes $+$ pretty modifiers <+> text "struct" <+> pretty name <> pretty typeParameters

        <+> pInherits $+$ pConstraints $+$ lbrace $+$ tab (pretty body) $+$ rbrace

        where

            pConstraints    = (vsep . map (tab . pretty)) constraints

            pInherits  = case inherits of

                            [] -> empty

                            _  -> colon <+> hcatIntersperse comma inherits



    pretty (InterfaceTypeDeclaration attributes modifiers name typeParameters inherits constraints body)

        = pretty attributes $+$ pretty modifiers <+> text "interface" <+> pretty name <> pretty typeParameters

        <+> pInherits $+$ pConstraints $+$ lbrace $+$ tab (pretty body) $+$ rbrace

        where

            pConstraints = (vsep . map (tab . pretty)) constraints

            pInherits    = case inherits of

                                [] -> empty

                                _  -> colon <+> hcatIntersperse comma inherits



    pretty (EnumTypeDeclaration attributes modifiers name inherits body)

        = pretty attributes $+$ pretty modifiers <+> text "enum" <+> pretty name <+> pInherits

        $+$ lbrace $+$ tab (pretty body) $+$ rbrace

        where

            pInherits = maybe empty (\ i -> colon <+> pretty i) inherits



    pretty (DelegateTypeDeclaration attributes modifiers ty name typeParameters params constraints)

        = pretty attributes $+$ pretty modifiers <+> text "delegate" <+> pretty ty <+> pretty name 

        <+> pretty typeParameters <> parens (pretty params) $+$ pConstraints <> semi

        where

            pConstraints = case constraints of

                              [] -> empty

                              _  -> (vsep . map (tab . pretty)) constraints



instance Pretty ClassBody where

    pretty (ClassBody declarations) 

        = vsep declarations

                   

instance Pretty StructBody where

    pretty (StructBody declarations)

        = vsep declarations

                 

instance Pretty EnumBody where

    pretty (EnumBody body) -- TODO: find a cleaner way, e.g. `intersperse`

        = (vsep . (++ [pretty (last body)]) . init . map (\ b -> pretty b <> comma)) body



instance Pretty EnumMemberDeclaration where

    pretty (EnumMemberDeclaration name expression)

        = pretty name <+> maybe empty (\ e -> equals <+> pretty e) expression



instance Pretty InterfaceBody where

    pretty (InterfaceBody declarations)

        = vsep declarations

        

instance Pretty InterfaceMemberDeclaration where

    pretty (InterfaceMethodMemberDeclaration attributes modifiers ty name typeParameters params constraints)

        = pretty attributes $+$ pretty modifiers <+> pretty ty <+> pretty name

        <+> pretty typeParameters <> (parens (pretty params) $+$ tab pConstraints) <> semi

        where

            pConstraints = (vsep . map (tab . pretty)) constraints



    pretty (InterfacePropertyMemberDeclaration attributes modifiers ty name accessor1 accessor2)

        = pretty attributes $+$ pretty modifiers <+> pretty ty <+> pretty name

        $+$ lbrace $+$ tab pAccessor1 $+$ tab pAccessor2 $+$ rbrace

        where

            pAccessor1 = maybe empty pretty accessor1

            pAccessor2 = maybe empty pretty accessor2



    pretty (InterfaceEventMemberDeclaration attributes modifiers ty name)

        = pretty attributes $+$ pretty modifiers <+> text "event" <+> pretty ty

        <+> pretty name <+> semi



    pretty (InterfaceIndexerMemberDeclaration attributes modifiers ty params accessor1 accessor2)

        = pretty attributes $+$ pretty modifiers <+> pretty ty <+> text "this"

        <> brackets (pretty params) $+$ lbrace $+$ tab pAccessor1 $+$ tab pAccessor2 $+$ rbrace

        where

            pAccessor1 = maybe empty pretty accessor1

            pAccessor2 = maybe empty pretty accessor2



instance Pretty InterfaceAccessor where

    pretty (GetInterfaceAccessor attributes) = pretty attributes $+$ text "get;"

    pretty (SetInterfaceAccessor attributes) = pretty attributes $+$ text "set;"



instance Pretty MemberDeclaration where

    pretty (FieldMemberDeclaration attributes modifiers ty declarators)

        = pretty attributes $+$ pretty modifiers <+> pretty ty 

        <+> pretty declarators <> semi



    pretty (MethodMemberDeclaration attributes modifiers ty name typeParameters params constraints body)

        = pretty attributes $+$ pretty modifiers <+> pretty ty <+> pretty name 

        <> pretty typeParameters <> parens (pretty params) $+$ pConstraints $+$ pretty body

        where

            pConstraints = (vsep . map (tab . pretty)) constraints



    pretty (PropertyMemberDeclaration attributes modifiers ty name body)

        = pretty attributes $+$ pretty modifiers <+> pretty ty <+> pretty name 

        <+> pretty body



    pretty (EventVariableMemberDeclaration attributes modifiers ty declarators)

        = pretty attributes $+$ pretty modifiers <+> text "event" <+> pretty ty

        <+> pretty declarators <> semi



    pretty (EventAccessorMemberDeclaration attributes modifiers ty name accessor1 accessor2)

        = pretty attributes $+$ pretty modifiers <+> text "event" <+> pretty ty

        <+> pretty name $+$ lbrace $+$ tab (pretty accessor1) 

        $+$ tab (pretty accessor2) $+$ rbrace



    pretty (IndexerMemberDeclaration attributes modifiers declarator body)

        = pretty attributes $+$ pretty modifiers <+> pretty declarator 

        $+$ pretty body



    pretty (OperatorMemberDeclaration attributes modifiers declarator body)

        = pretty attributes $+$ pretty modifiers <+> pretty declarator

        $+$ pretty body



    pretty (ConstructorMemberDeclaration attributes modifiers name params initializer body)

        = pretty attributes $+$ pretty modifiers <+> pretty name 

        <> parens (pretty params) $+$ pInitializer $+$ pretty body

        where

            pInitializer = maybe empty (tab . pretty) initializer



    pretty (DestructorMemberDeclaration attributes modifiers name body)

        = pretty attributes $+$ pretty modifiers <+> char '~' <> pretty name 

        <> text "()" $+$ pretty body 



    pretty (TypeMemberDeclaration declaration)

        = pretty declaration



instance Pretty EventAccessor where

    pretty (AddEventAccessor attributes body)

        = pretty attributes $+$ text "add" <+> braces (pretty body)



    pretty (RemoveEventAccessor attributes body)

        = pretty attributes $+$ text "remove" <+> braces (pretty body)



instance Pretty OperatorDeclarator where

    pretty (UnaryOperatorDeclarator ty op paramTy paramName)

        = pretty ty <+> text "operator" <+> pretty op <> parens pParam

        where pParam = pretty paramTy <+> pretty paramName



    pretty (BinaryOperatorDeclarator ty op paramTy1 paramName1 paramTy2 paramName2)

        = pretty ty <+> text "operator" <+> pretty op <> parens pParams

        where 

            pParams = pParam1 <> comma <> pParam2

            pParam1 = pretty paramTy1 <+> pretty paramName1

            pParam2 = pretty paramTy2 <+> pretty paramName2

            

    pretty (ImplicitConversionOperatorDeclarator ty paramTy paramName)

        = text "implicit operator" <+> pretty ty <> parens pParam

        where pParam = pretty paramTy <+> pretty paramName

    

    pretty (ExplicitConversionOperatorDeclarator ty paramTy paramName)

        = text "explicit operator" <+> pretty ty <> parens pParam

        where pParam = pretty paramTy <+> pretty paramName



instance Pretty OverloadableUnaryOperator where

    pretty op = text $ 

        case op of

            OverloadableUnaryPlus       -> "+"

            OverloadableUnaryMinus      -> "-"

            OverloadableUnaryNot        -> "!"

            OverloadableUnaryBitwiseNot -> "~"

            OverloadableUnaryPlusPlus   -> "++"

            OverloadableUnaryMinusMinus -> "--"

            OverloadableUnaryTrue       -> "true"

            OverloadableUnaryFalse      -> "false"



instance Pretty OperatorBody where

    pretty (OperatorStatementBody statements)

        = lbrace $+$ tab (pretty statements) $+$ rbrace



    pretty (OperatorExpressionBody expression)

        = tab (text "=>" <+> pretty expression <> semi)



    pretty OperatorNoBody

        = semi



instance Pretty IndexerBody where

    pretty (IndexerAccessor accessor1 accessor2)

        = lbrace $+$ tab pAccessor1 $+$ tab pAccessor2 $+$ rbrace

        where

            pAccessor1 = maybe empty pretty accessor1

            pAccessor2 = maybe empty pretty accessor2



    pretty (IndexerLambda expression)

        = text "=>" <+> pretty expression <> semi



instance Pretty IndexerDeclarator where

    pretty (IndexerDeclaratorThis ty params)

        = pretty ty <+> text "this" <> brackets (pretty params)

        

    pretty (IndexerDeclaratorInterface ty interface params)

        = pretty ty <+> pretty interface <> dot <> text "this" <> brackets (pretty params)



instance Pretty PropertyBody where

    pretty (PropertyBody accessor1 accessor2 initializer)

        = braces (pAccessor1 <+> pAccessor2) <+> pInitializer 

        where

            pAccessor1   = maybe empty pretty accessor1

            pAccessor2   = maybe empty pretty accessor2

            pInitializer = maybe empty (\ i -> equals <+> pretty i <> semi) initializer



    pretty (PropertyLambda expression)

        = text "=>" <+> pretty expression <> semi



instance Pretty AccessorDeclaration where

    pretty (GetAccessorDeclaration attributes modifiers body)

        = pretty attributes $+$ pretty modifiers <+> text "get" <> pBody

        where

            pBody = maybe semi (\ b -> space <> (braces . pretty) b) body



    pretty (SetAccessorDeclaration attributes modifiers body)

        = pretty attributes $+$ pretty modifiers <+> text "set" <> pBody

        where

            pBody = maybe semi (\ b -> space <> (braces . pretty) b) body        



instance Pretty ConstructorBody where

    pretty (ConstructorStatementBody statements)

        = lbrace $+$ tab (pretty statements) $+$ rbrace



instance Pretty DestructorBody where

    pretty (DestructorStatementBody statements)

        = lbrace $+$ tab (pretty statements) $+$ rbrace



instance Pretty ConstructorInitializer where

    pretty (ConstructorBaseCall arguments)

        = colon <+> text "base" <> parens (pretty arguments)

    

    pretty (ConstructorThisCall arguments)

        = colon <+> text "this" <> parens (pretty arguments)



instance Pretty [Argument] where

    pretty = hcatIntersperse comma



instance Pretty Argument where

    pretty (Argument name expression)

        = pName <+> pretty expression

        where

            pName = maybe empty (\ n -> pretty n <> semi) name 

            

    pretty (RefArgument name expression)

        = pName <+> text "ref" <+> pretty expression

        where

            pName = maybe empty (\ n -> pretty n <> semi) name 

        

    pretty (OutArgument name expression)

        = pName <+> text "out" <+> pretty expression

        where

            pName = maybe empty (\ n -> pretty n <> semi) name 



instance Pretty MethodBody where

    pretty (MethodStatementBody statements)

        = lbrace $+$ tab (pretty statements) $+$ rbrace



    pretty (MethodExpressionBody expression)

        = tab (text "=>" <+> pretty expression <> semi)



    pretty MethodNoBody

        = semi



--------------------------------------------------------------------------------

-- Formal parameters.

--------------------------------------------------------------------------------



instance Pretty FormalParams where

    pretty (FormalParams params paramsParam)

        = (hcat . intersperse comma) pParams

        where

            pParams      = map pretty params ++ pParamsParam

            pParamsParam = maybe [] (\ p -> [pretty p]) paramsParam



instance Pretty FormalParam where

    pretty (FormalParam modifier ty name expr)

        = pModifier <+> pretty ty <+> pretty name <+> pExpr

        where

            pModifier = maybe empty pretty modifier

            pExpr     = maybe empty ((equals <>) . pretty) expr



instance Pretty ParamArray where

    pretty (ParamArray ty name) 

        = text "params" <+> pretty ty <+> pretty name



instance Pretty ParameterModifier where

    pretty modifier = text $ 

        case modifier of

            RefParam -> "ref" ; OutParam -> "out" ; ThisParam -> "this"



--------------------------------------------------------------------------------

-- Statements.

--------------------------------------------------------------------------------



instance Pretty [Statement] where

    pretty = vsep



instance Pretty Statement where

    pretty (Labeled label statement) 

        = pretty label <> colon <+> pretty statement



    pretty (Declaration declaration)

        = pretty declaration <> semi



    pretty (Block statements)

        = lbrace $+$ tab (pretty statements) $+$ rbrace



    pretty Empty

        = semi



    pretty (ExpressionStatement expression)

        = pretty expression <> semi



    pretty (IfThenElse guard trueBody falseBody)

        = text "if" <+> parens (pretty guard)

        $+$ prettyEmbedded trueBody $+$ pFalseBody

        where

            pFalseBody = maybe empty (\ b -> text "else" $+$ prettyEmbedded b) falseBody



    pretty (Switch expression blocks)

        = text "switch" <+> parens (pretty expression) 

        $+$ lbrace $+$ tab (pretty blocks) $+$ rbrace



    pretty (While guard body)

        = text "while" <+> parens (pretty guard) $+$ prettyEmbedded body



    pretty (Do body guard)

        = text "do" $+$ prettyEmbedded body $+$ text "while" <+> parens (pretty guard) <> semi



    pretty (For initializer guard iterator body)

        = text "for" <+> parens (pInitializer <> semi <+> pGuard <> semi <+> pIterator)

        $+$ prettyEmbedded body

        where

            pInitializer = maybe empty pretty initializer

            pGuard       = maybe empty pretty guard

            pIterator    = maybe empty (hcatIntersperse comma) iterator



    pretty (ForEach ty var expression body)

        = text "foreach" <+> parens pHeader $+$ prettyEmbedded body

        where

            pHeader = pretty ty <+> pretty var <+> text "in" <+> pretty expression



    pretty Break         = text "break" <> semi

    pretty Continue      = text "continue" <> semi

    pretty (Goto target) = text "goto" <+> pretty target <> semi



    pretty (Return expression)

        = text "return" <+> maybe empty pretty expression <> semi



    pretty (Throw expression)

        = text "throw" <+> maybe empty pretty expression <> semi



    pretty (Try statements catches finally)

        = text "try" $+$ lbrace $+$ tab (pretty statements) $+$ rbrace

        $+$ pretty catches $+$ pFinally

        where

            pFinally = case finally of 

                        [] -> empty

                        _  -> text "finally" $+$ lbrace $+$ tab (pretty finally) $+$ rbrace



    pretty (CheckedStatement statements)

        = text "checked" $+$ lbrace $+$ tab (pretty statements) $+$ rbrace

        

    pretty (UncheckedStatement statements)

        = text "unchecked" $+$ lbrace $+$ tab (pretty statements) $+$ rbrace



    pretty (Lock expression body)

        = text "lock" <+> parens (pretty expression) $+$ prettyEmbedded body



    pretty (UsingStatement resource body)

        = text "using" <+> parens (pretty resource) $+$ prettyEmbedded body



    pretty (Yield expression)

        = text "yield" <+> pExpression <> semi

        where

            pExpression = maybe (text "break") (\ e -> text "return" <+> pretty e) expression



instance Pretty ForInitializer where

    pretty (ForInitializerDeclaration declaration)

        = pretty declaration



    pretty (ForInitializerExpressions expression)

        = (hcat . intersperse comma . map pretty) expression



instance Pretty LocalVarDeclaration where

    pretty (LocalVarDeclaration ty declarators)

        = pretty ty <+> pretty declarators



instance Pretty [Catch] where

    pretty = vsep



instance Pretty Catch where

    pretty (Catch specifier when statements)

        = text "catch" <+> pSpecifier $+$ tab pWhen

        $+$ lbrace $+$ tab (pretty statements) $+$ rbrace

        where

            pSpecifier = maybe empty (parens . pretty) specifier

            pWhen      = maybe empty (\ e -> text "when" <+> parens (pretty e)) when



instance Pretty ExceptionSpecifier where

    pretty (ExceptionSpecifier ty name)

        = pretty ty <+> maybe empty pretty name



instance Pretty GotoTarget where

    pretty (GotoLabel label)     = pretty label

    pretty (GotoCase expression) = text "case" <+> pretty expression

    pretty GotoDefault           = text "default"



instance Pretty [SwitchBlock] where

    pretty = vsep



instance Pretty SwitchBlock where

    pretty (LabeledBlock guard statements) 

        = text "case" <+> pretty guard <> semi $+$ tab (pretty statements)

        

    pretty (DefaultBlock statements) 

        = text "default:" $+$ tab (pretty statements)



instance Pretty ResourceAcquisition where

    pretty (ResourceAcquisitionVariable declarators)

        = pretty declarators



    pretty (ResourceAcquisitionExpression expression)

        = pretty expression



instance Pretty [VariableDeclarator] where

    pretty = hcatIntersperse comma



instance Pretty VariableDeclarator where

    pretty (VariableDeclarator name initializer)

        = pretty name <+> pInitializer

        where

            pInitializer = maybe empty (\ i -> equals <+> pretty i) initializer



instance Pretty VariableInitializer where

    pretty (VariableInitializerExpression expression)

        = pretty expression



    pretty (VariableInitializerArray initializer)

        = braces (pretty initializer)



instance Pretty ArrayInitializer where

    pretty (ArrayInitializer initializers)

        = hcatIntersperse comma initializers



--------------------------------------------------------------------------------

-- Expressions

--------------------------------------------------------------------------------



instance Pretty Expression where

    pretty (Literal literal) 

        = pretty literal



    pretty (SimpleName name typeArguments)

        = pretty name <> pretty typeArguments



    pretty (Parenthesized expression)

        = parens (pretty expression)



    pretty (Assign target op expression)

        = pretty target <+> pretty op <+> pretty expression

        

    pretty (MemberAccess access)

        = pretty access



    pretty (Invocation expression arguments)

        = pretty expression <> parens (pretty arguments)



    pretty (ElementAccess expression indices)

        = pretty expression <> brackets (hcatIntersperse comma indices)



    pretty This = text "this"

    pretty Base = text "base"



    pretty (ObjectCreationExpression ty arguments initializer)

        = text "new" <+> pretty ty <> parens pArguments <+> pInitializer

        where

            pArguments   = hcatIntersperse comma arguments 

            pInitializer = maybe empty pretty initializer



    pretty (ObjectCreationTypeInitializer ty initializer)

        = text "new"<+> pretty ty <+> pretty initializer



    pretty (ArrayCreationExpression ty sizes ranks initializer)

        = text "new" <+> pretty ty <> brackets (hcatIntersperse comma sizes)

        <> (hcat . map pretty) ranks <+> maybe empty pretty initializer



    pretty (ArrayCreationTypeInitializer ty initializer)

        = text "new" <+> pretty ty <+> pretty initializer



    pretty (ArrayCreationRankInitializer rank initializer)

        = text "new" <> pretty rank <+> pretty initializer



    pretty (Sizeof ty)

        = text "sizeof" <> parens (pretty ty)



    pretty (Typeof expression)

        = text "typeof" <> parens (pretty expression)



    pretty (Checked expression)

        = text "checked" <> parens (pretty expression)



    pretty (Unchecked expression)

        = text "unchecked" <> parens (pretty expression)

        

    pretty (Default ty)

        = text "default" <> parens (pretty ty)



    pretty (BinaryOperator op exp1 exp2)

        = pretty exp1 <+> pretty op <+> pretty exp2



    pretty (Conditional guard exp1 exp2)

        = pretty guard <+> char '?' <+> pretty exp1 <+> char ':' <+> pretty exp2



    pretty (Nameof entity)

        = text "nameof" <> parens (pretty entity)



    pretty (Delegate sig body)

        = text "delegate" <+> maybe empty pretty sig <+> braces (pretty body)



    pretty (Lambda sig body)

        = pretty sig <+> text "=>" <+> pretty body



    pretty (UnaryPlus expression) 

        = text "+" <> pretty expression



    pretty (UnaryMinus expression) 

        = text "-"  <> pretty expression



    pretty (UnaryNot expression) 

        = text "!" <> pretty expression



    pretty (UnaryBitwiseNot expression) 

        = text "~" <> pretty expression



    pretty (UnaryPreIncrement expression) 

        = text "++" <> pretty expression

        

    pretty (UnaryPreDecrement  expression) 

        = text "--" <> pretty expression



    pretty (UnaryPostIncrement expression) 

        = pretty expression <> text "++"



    pretty (UnaryPostDecrement expression) 

        = pretty expression <> text "--"



    pretty (UnaryCast ty expression)

        = parens (pretty ty) <> pretty expression



    pretty (UnaryAwait expression) 

        = text "await" <+> pretty expression



instance Pretty AnonymousFunctionSignature where

    pretty (ExplicitAnonymousFunctionSignature params)

        = parens (hcatIntersperse comma params)



    pretty (ImplicitAnonymousFunctionSignature [param])

        = pretty param



    pretty (ImplicitAnonymousFunctionSignature params)

        = parens (hcatIntersperse comma params)



instance Pretty AnonymousFunctionParameter where

    pretty (ExplicitAnonymousFunctionParameter modifier ty name)

        = maybe empty pretty modifier <+> pretty ty <+> pretty name



instance Pretty AnonymousFunctionBody where

    pretty (AnonymousFunctionStatementBody body)

        = braces (pretty body)



    pretty (AnonymousFunctionExpressionBody expression)

        = pretty expression



instance Pretty NameofEntity where

    pretty (NameofIdentifier name)        = pretty name

    pretty (NameofThis name)              = text "this" <> dot <> pretty name

    pretty (NameofBase name)              = text "base" <> dot <> pretty name

    pretty (NameofEntity entity name)     = pretty entity <> dot <> pretty name

    pretty (NameofPredefinedType ty name) = pretty ty <> dot <> pretty name



instance Pretty TypeOfExpression where

    pretty (TypeofType ty)

        = pretty ty



instance Pretty ObjectCreationInitializer where

    pretty (ObjectInitializer initializers)

        = braces (hcatIntersperse comma initializers)

        

    pretty (CollectionInitializer initializer)

        = pretty initializer



instance Pretty ArrayCreationInitializer where

    pretty (ArrayCreationInitializerExpression expressions)

        = braces (hcatIntersperse comma expressions)



    pretty (ArrayCreationInitializerInitializers initializers)

        = braces (hcatIntersperse comma initializers)



instance Pretty MemberInitializer where

    pretty (MemberInitializer target value)

        = pretty target <+> equals <+> pretty value



instance Pretty InitializerTarget where

    pretty (InitializerTargetIdentifier name)

        = pretty name



    pretty (InitializerTargetList arguments)

        = brackets (pretty arguments)



instance Pretty InitializerValue where

    pretty (InitializerValueExpression expression)

        = pretty expression



    pretty (InitializerValueInitializer initializer)

        = pretty initializer



instance Pretty Literal where

    pretty (BooleanLit True)         = text "true"

    pretty (BooleanLit False)        = text "false"

    pretty (IntLit value)            = text $ show value

    pretty (UIntLit value)           = text $ show value

    pretty (LongLit value)           = text $ show value

    pretty (ULongLit value)          = text $ show value

    pretty (FloatLit value)          = text $ show value ++ "f"

    pretty (DoubleLit value)         = text $ show value ++ "d"

    pretty (DecimalLit value)        = text $ show value ++ "m"

    pretty (CharLit value)           = quotes (text value)

    pretty (StringLit value)         = doubleQuotes (text value)

    pretty (VerbatimStringLit value) = char '@' <> doubleQuotes (text value)

    pretty NullLit                   = text "null"



instance Pretty MemberAccess where

    pretty (PrimaryMemberAccess expression name typeArguments)

        = pretty expression <> dot <> pretty name <> pretty typeArguments



    pretty (PredefinedMemberAccess ty name typeArguments)

        = pretty ty <> dot <> pretty name <> pretty typeArguments



    pretty (QualifiedMemberAccess namespace member name)

        = pretty namespace <> text "::" <> pretty member <> dot <> pretty name



instance Pretty AssignmentOperator where

    pretty op = text $

        case op of

            OpAssign                  -> "="  ; OpAssignPlus             -> "+="

            OpAssignMinus             -> "-=" ; OpAssignMultiply         -> "*="

            OpAssignDivide            -> "/=" ; OpAssignModulo           -> "%="

            OpAssignBitwiseAnd        -> "&=" ; OpAssignBitwiseOr        -> "|="

            OpAssignBitwiseXor        -> "^=" ; OpAssignBitwiseLeftShift -> "<<="

            OpAssignBitwiseRightShift -> ">>="



instance Pretty BinaryOperator where

    pretty op = text $ 

        case op of 

            BinaryPlus             -> "+" ; BinaryMinus       -> "-" 

            BinaryMultiply         -> "*" ; BinaryDivide      -> "/"

            BinaryModulo           -> "%" ; BinaryShiftLeft   -> "<<"

            BinaryShiftRight       -> ">>"; BinaryEquals      -> "==" 

            BinaryNotEquals        -> "!="; BinaryLessThan    -> "<"   

            BinaryLessThanEqual    -> "<="; BinaryGreaterThan -> ">"

            BinaryGreaterThanEqual -> ">="; BinaryBitwiseAnd  -> "&"

            BinaryBitwiseXor       -> "^" ; BinaryBitwiseOr   -> "|"

            BinaryAnd              -> "&&"; BinaryOr          -> "||"

            BinaryIs               -> "is"; BinaryAs          -> "as"

            BinaryNullCoalescing   -> "??"





--------------------------------------------------------------------------------

-- Type parameters.

--------------------------------------------------------------------------------



instance Pretty [TypeParameter] where

    pretty []     = empty

    pretty params = diamonds (hcatIntersperse comma params)



instance Pretty TypeParameter where

    pretty (TypeParameter name) = pretty name



instance Pretty TypeParameterConstraintClause where

    pretty (TypeParameterConstraintClause typeParam constraints)

        = text "where" <+> pretty typeParam <+> colon <+> hcatIntersperse comma constraints



instance Pretty TypeParameterConstraint where

    pretty (TypeConstraint ty) = pretty ty

    pretty ClassConstraint     = text "class"

    pretty StructConstraint    = text "struct"

    pretty NewConstraint       = text "new()"



instance Pretty [VariantTypeParameter] where

    pretty []     = empty

    pretty params = diamonds (hcatIntersperse comma params)



instance Pretty VariantTypeParameter where

    pretty (VariantTypeParameter variance name)

        = maybe empty pretty variance <+> pretty name



instance Pretty [TypeArgument] where

    pretty []        = empty

    pretty arguments = (diamonds . hcatIntersperse comma) arguments



instance Pretty Variance where

    pretty VarianceIn  = text "in"

    pretty VarianceOut = text "out"



instance Pretty TypeArgument where

    pretty (TypeArgument ty) = pretty ty



--------------------------------------------------------------------------------

-- Types

--------------------------------------------------------------------------------



instance Pretty Type where

    pretty (TypeNamed name)  = pretty name

    pretty (TypeArray ty)    = pretty ty

    pretty (TypeSimple ty)   = pretty ty

    pretty TypeDynamic       = text "dynamic"

    pretty (TypeNullable ty) = pretty ty <> char '?'



instance Pretty (Maybe Type) where

    pretty = maybe (text "void") pretty



instance Pretty SimpleType where

    pretty ty = case ty of 

                    Char   -> text "char"  ; Bool   -> text "bool"   

                    Object -> text "object"; String -> text "string" 

                    IntegralType ty'      -> pretty ty'

                    FloatingPointType ty' -> pretty ty'



instance Pretty IntegralType where

    pretty ty = text $ 

        case ty of

            SByte  -> "sbyte" ; Byte  -> "byte"  ; Short -> "short"

            UShort -> "ushort"; Int   -> "int"   ; UInt  -> "uint"

            Long   -> "long"  ; ULong -> "ulong"         



instance Pretty FloatingPointType where

    pretty Float   = text "float"

    pretty Double  = text "double"

    pretty Decimal = text "decimal"



instance Pretty ArrayType where

    pretty (ArrayType ty ranks)

        = pretty ty <> (hcat . map pretty) ranks



instance Pretty RankSpecifier where

    pretty (RankSpecifier rank) = brackets (hcat (replicate rank comma))



instance Pretty LocalVarType where

    pretty (VarType ty) = pretty ty

    pretty Var          = text "var" 



instance Pretty TypeName where

    pretty (TypeName name args)

        = pretty name <> pretty args



    pretty (TypeAlias namespace name typeArguments)

        = pretty namespace <> text "::" <> pretty name <> pretty typeArguments



--------------------------------------------------------------------------------

-- Attribute definitions.

--------------------------------------------------------------------------------



instance Pretty [GlobalAttributeSection] where

    pretty = vsep



instance Pretty GlobalAttributeSection where

    pretty (GlobalAttributeSection target attributes)

        = brackets (pTarget <+> hcatIntersperse comma attributes)

        where

            pTarget = maybe empty (\ t -> pretty t <+> colon) target



instance Pretty GlobalAttributeTarget where

    pretty AttributeTargetAssembly = text "assembly" 

    pretty AttributeTargetModule   = text "module" 



instance Pretty [AttributeSection] where

    pretty = vsep



instance Pretty AttributeSection where

    pretty (AttributeSection target attributes)

        = brackets (pTarget <+> hcatIntersperse comma attributes)

        where

            pTarget = maybe empty (\ t -> pretty t <+> colon) target



instance Pretty AttributeTarget where

    pretty AttributeTargetField    = text "field" 

    pretty AttributeTargetEvent    = text "event" 

    pretty AttributeTargetMethod   = text "method" 

    pretty AttributeTargetParam    = text "param" 

    pretty AttributeTargetProperty = text "property" 

    pretty AttributeTargetReturn   = text "return" 

    pretty AttributeTargetType     = text "type" 



instance Pretty Attribute where

    pretty (Attribute name arguments) 

        = pretty name <> parens (hcatIntersperse comma arguments)



instance Pretty AttributeArgument where

    pretty (AttributeArgumentExpression expression) 

        = pretty expression



    pretty (AttributeArgumentNamed name expression) 

        = pretty name <+> equals <+> pretty expression



--------------------------------------------------------------------------------

-- Auxiliary definitions.

--------------------------------------------------------------------------------



instance Pretty [Modifier] where

    pretty = hsep . map pretty



instance Pretty Modifier where

    pretty modifier 

        = case modifier of

             Public   -> text "public"   ; Private   -> text "private"

             Internal -> text "internal" ; Protected -> text "protected"

             Abstract -> text "abstract" ; Async     -> text "async"

             Const    -> text "const"    ; Event     -> text "event"

             Extern   -> text "extern"   ; New       -> text "new"

             Override -> text "override" ; Readonly  -> text "readonly"

             Sealed   -> text "sealed"   ; Static    -> text "static"

             Unsafe   -> text "unsafe"   ; Virtual   -> text "virtual"

             Volatile -> text "volatile" ; Partial   -> text "partial"

             

instance Pretty Identifier where

    pretty (Identifier identifier)

        = text identifier



instance Pretty Name where

    pretty (Name name) = hcatIntersperse dot name



--------------------------------------------------------------------------------

-- Utility functions.

--------------------------------------------------------------------------------



prettyEmbedded :: Statement -> Doc

prettyEmbedded body@(Block _) = pretty body

prettyEmbedded body           = tab (pretty body)



tab :: Doc -> Doc

tab = nest 4



dot :: Doc

dot = char '.'



diamonds :: Doc -> Doc

diamonds doc = char '<' <> doc <> char '>'



hcatIntersperse :: Pretty a => Doc -> [a] -> Doc

hcatIntersperse delimiter = hcat . intersperse delimiter . map pretty



vsep :: Pretty a => [a] -> Doc

vsep = foldr (($+$) . pretty) empty