{-# LANGUAGE OverloadedStrings #-}
-- | Bash conditional commands.
module Language.Bash.Cond
    ( CondExpr(..)
    , UnaryOp(..)
    , BinaryOp(..)
    ) where

import Text.PrettyPrint

import Language.Bash.Operator
import Language.Bash.Pretty

-- | Bash conditional expressions.
data CondExpr
    = Unary UnaryOp String
    | Binary String BinaryOp String
    | Not CondExpr
    | And CondExpr CondExpr
    | Or CondExpr CondExpr
    deriving (Eq, Read, Show)

instance Pretty CondExpr where
    pretty = go (0 :: Int)
      where
        go _ (Unary op a)    = pretty op <+> text a
        go _ (Binary a op b) = text a <+> pretty op <+> text b
        go _ (Not e)         = "!" <+> go 2 e
        go p (And e1 e2)     = paren (p > 1) $ go 1 e1 <+> "&&" <+> go 1 e2
        go p (Or e1 e2)      = paren (p > 0) $ go 0 e1 <+> "||" <+> go 0 e2

        paren False d = d
        paren True d  = "(" <+> d <+> ")"

-- | Unary conditional operators.
data UnaryOp
    = BlockFile      -- ^ @-b@
    | CharacterFile  -- ^ @-c@
    | Directory      -- ^ @-d@
    | FileExists     -- ^ @-e@, @-a@
    | RegularFile    -- ^ @-f@
    | SetGID         -- ^ @-g@
    | Sticky         -- ^ @-k@
    | NamedPipe      -- ^ @-p@
    | Readable       -- ^ @-r@
    | FileSize       -- ^ @-s@
    | Terminal       -- ^ @-t@
    | SetUID         -- ^ @-u@
    | Writable       -- ^ @-w@
    | Executable     -- ^ @-x@
    | GroupOwned     -- ^ @-G@
    | SymbolicLink   -- ^ @-L@, @-h@
    | Modified       -- ^ @-N@
    | UserOwned      -- ^ @-O@
    | Socket         -- ^ @-S@
    | Optname        -- ^ @-o@
    | Varname        -- ^ @-v@
    | ZeroString     -- ^ @-z@
    | NonzeroString  -- ^ @-n /string/@ or @/string/@
    deriving (Eq, Ord, Read, Show, Enum, Bounded)

instance Operator UnaryOp where
    operatorTable =
        zip [minBound .. maxBound]
            (map (\c -> ['-', c]) "bcdefgkprstuwxGLNOSovzn") ++
        [ (FileExists  , "-a")
        , (SymbolicLink, "-h")
        ]

instance Pretty UnaryOp where
    pretty = prettyOperator

-- | Binary conditional operators.
data BinaryOp
    = SameFile   -- ^ @-ef@
    | NewerThan  -- ^ @-nt@
    | OlderThan  -- ^ @-ot@
    | StrMatch   -- ^ @=~@
    | StrEQ      -- ^ @==@, @=@
    | StrNE      -- ^ @!=@
    | StrLT      -- ^ @<@
    | StrGT      -- ^ @>@
    | ArithEQ    -- ^ @-eq@
    | ArithNE    -- ^ @-ne@
    | ArithLT    -- ^ @-lt@
    | ArithLE    -- ^ @-le@
    | ArithGT    -- ^ @-gt@
    | ArithGE    -- ^ @-ge@
    deriving (Eq, Ord, Read, Show, Enum, Bounded)

instance Operator BinaryOp where
    operatorTable =
        zip [minBound .. maxBound]
            [ "-ef", "-nt", "-ot"
            , "=~", "==", "!=", "<", ">"
            , "-eq", "-ne", "-lt", "-le", "-gt", "-ge"
            ] ++
        [ (StrEQ, "=") ]

instance Pretty BinaryOp where
    pretty = prettyOperator