packages feed

pinch-gen-0.4.2.0: src/Pinch/Generate/Pretty.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}

module Pinch.Generate.Pretty where

import           Data.String
import qualified Data.Text                 as T
import           Data.Text.Prettyprint.Doc

newtype ModuleName = ModuleName T.Text
  deriving (Show)
type TypeName = T.Text
type Name = T.Text
type ClassName = T.Text

data Module = Module
  { modName    :: ModuleName
  , modPragmas :: [Pragma]
  , modImports :: [ImportDecl]
  , modDecls   :: [Decl]
  }
  deriving (Show)

data Pragma
  = PragmaLanguage T.Text
  | PragmaOptsGhc T.Text
  deriving (Show)

data ImportDecl = ImportDecl
  { iName      :: ModuleName
  , iQualified :: Bool
  , iThings    :: ImportNames
  }
  deriving (Show)

data ImportNames
  = IEverything
  | IJust [ Name ]
  deriving (Show)

data Decl
  = TypeDecl Type Type
  | DataDecl TypeName [ConDecl] [Deriving]
  | InstDecl InstHead [Decl]
  | FunBind [Match]
  | TypeSigDecl Name Type
  deriving (Show)

data Deriving
  = DeriveClass Type
  deriving (Show)

data ConDecl
  = ConDecl Name [Type]
  | RecConDecl Name [(Name, Type)]
  deriving (Show)

data Type
  = TyApp Type [Type]
  | TyCon TypeName
  | TyLam [Type] Type
  deriving (Show)


data InstHead
  = InstHead [Constraint] ClassName Type
  deriving (Show)

data Constraint
  = CClass ClassName Type
  deriving (Show)

data Match = Match Name [Pat] Exp
  deriving (Show)

data Pat
  = PVar Name
  | PLit Lit
  | PCon Name [Pat]
  deriving (Show)

data Exp
  = EVar Name
  | EApp Exp [Exp]
  | ELit Lit
  | ETyAnn Exp Type
  | ECase Exp [Alt]
  | EDo [Stm]
  | EInfix Name Exp Exp
  | EList [Exp]
  | ELam [Pat] Exp
  | ETuple [Exp]
  | ELet Name Exp Exp
  | ETyApp Exp [Type]
  deriving (Show)

data Stm
  = StmBind (Maybe Pat) Exp
  deriving (Show)

data Alt
  = Alt Pat Exp
  deriving (Show)

data Lit
  = LInt Integer
  | LFloat Double
  | LString T.Text
  deriving (Show)

instance Pretty ModuleName where
  pretty (ModuleName x) = pretty x

instance Pretty Module where
  pretty mod =
       vsep (map pretty $ modPragmas mod) <> line <> line
    <> "module" <+> pretty (modName mod) <+> "where" <> line <> line
    <> vsep (map pretty $ modImports mod) <> line <> line
    <> vsep (map pretty $ modDecls mod)

instance Pretty Pragma where
  pretty p = case p of
    PragmaLanguage p -> "{-# LANGUAGE" <+> pretty p <+> "#-}"
    PragmaOptsGhc o -> "{-# OPTIONS_GHC" <+> pretty o <+> "#-}"

instance Pretty ImportDecl where
  pretty i = "import" <+> (if (iQualified i) then "qualified" else "") <+> pretty (iName i) <> pretty (iThings i)

instance Pretty ImportNames where
  pretty i = case i of
    IEverything -> ""
    IJust xs -> " " <> (parens $ cList $ map pretty xs)

instance Pretty Decl where
  pretty decl = case decl of
    TypeDecl t1 t2 -> "type" <+> pretty t1 <+> "=" <+> pretty t2 <> line
    DataDecl t [] ds -> "data" <+> pretty t <+> prettyDerivings ds <> line
    DataDecl t (c:cs) ds -> nest 2 (vsep $
        [ "data" <+> pretty t
        , "=" <+> pretty c
        ] ++ (map (\c -> "|" <+> pretty c) cs) ++ [ prettyDerivings ds ]
      ) <> line
    InstDecl h decls -> (nest 2 $ vsep $ [ pretty h ] ++ map pretty decls) <> line
    FunBind ms -> vsep (map pretty ms) <> line
    TypeSigDecl n ty -> pretty n <+> "::" <+> pretty ty

prettyDerivings :: [Deriving] -> Doc a
prettyDerivings [] = ""
prettyDerivings ds = "deriving" <+> (parens $ cList $ map pretty ds)

instance Pretty Deriving where
  pretty (DeriveClass c) = pretty c

instance Pretty ConDecl where
  pretty (ConDecl n args) = hsep $ [ pretty n ] ++ map pretty args
  pretty (RecConDecl n args) = hsep $ [ pretty n, "{", fields, "}" ]
    where fields = cList $ map (\(n, v) -> pretty n <+> "::" <+> pretty v) args

instance Pretty InstHead where
  pretty (InstHead cs n ty) = "instance" <> context <+> pretty n <+> pretty ty <+> "where"
    where context = if null cs then "" else space <> parens (cList $ map pretty cs) <+> "=>" <+> pretty n <+> pretty ty <+> "where"

instance Pretty Constraint where
  pretty (CClass cl n) = pretty cl <+> pretty n

instance Pretty Type where
  pretty ty = case ty of
    TyApp t1 ts -> parens $ pretty t1 <+> hsep (map pretty ts)
    TyCon t -> pretty t
    TyLam ts t -> concatWith (surround (space <> "->" <> space)) (map (parens . pretty) ts ++ [pretty t])

instance Pretty Match where
  pretty (Match n ps e) = pretty n <+> hsep (map pretty ps) <+> "=" <+> pretty e

instance Pretty Pat where
  pretty p = case p of
    (PVar x) -> pretty x
    (PLit i) -> pretty i
    (PCon n []) -> pretty n
    (PCon n xs) -> parens $ pretty n <+> hsep (map pretty xs)

instance Pretty Exp where
  pretty e = case e of
    EVar n -> pretty n
    EApp e es -> pretty e <+> hsep (map (parens . pretty) es)
    ELit l -> pretty l
    ETyAnn e ty -> parens $ pretty e <+> "::" <+> pretty ty
    ECase e as -> nest 2 $ vsep $ ["case" <+> pretty e <+> "of"] ++ map pretty as
    EDo s -> nest 2 $ vsep $ ["do"] ++ map pretty s
    EInfix op e1 e2 -> parens $ hsep [ pretty e1, pretty op, pretty e2]
    EList es -> "[" <+> cList (map pretty es) <+> "]"
    ELam ps e -> parens $ "\\" <> hsep (map pretty ps) <+> "->" <+> pretty e
    ETuple es -> nest 2 $ tupled $ map pretty es
    ELet nm e1 e2 -> "let" <+> pretty nm <+> "=" <+> indent 2 (pretty e1) <+> "in" <+> pretty e2
    ETyApp e tys -> pretty e <+>  hsep (map (("@"<>) . parens . pretty) tys)

instance Pretty Alt where
  pretty (Alt p e) = pretty p <+> "->" <+> pretty e

instance Pretty Stm where
  pretty s = case s of
    StmBind Nothing e -> pretty e
    StmBind (Just p) e -> pretty p <+> "<-" <+> pretty e

instance Pretty Lit where
  pretty l = case l of
    LInt i -> pretty i
    LFloat f -> pretty f
    LString t -> "\"" <> pretty t <> "\""

cList = concatWith (surround (comma <> space))


instance IsString Exp where
  fromString = EVar . T.pack

instance IsString Pat where
  fromString = PVar . T.pack