-- | Bash has a lot of operators.
module Language.Bash.Operator
    ( Operator(..)
    , select
    , selectOperator
    , prettyOperator
    ) where

import Control.Applicative (Alternative)
import Data.Foldable (asum)
import Prettyprinter (Doc, pretty)

-- | String operators.
class Eq a => Operator a where
    operatorTable :: [(a, String)]

-- | Select the first element that succeeds from a table.
select :: Alternative f => (b -> f c) -> [(a, b)] -> f a
select :: forall (f :: * -> *) b c a.
Alternative f =>
(b -> f c) -> [(a, b)] -> f a
select b -> f c
p = [f a] -> f a
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum ([f a] -> f a) -> ([(a, b)] -> [f a]) -> [(a, b)] -> f a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, b) -> f a) -> [(a, b)] -> [f a]
forall a b. (a -> b) -> [a] -> [b]
map (\(a
a, b
b) -> a
a a -> f c -> f a
forall a b. a -> f b -> f a
forall (f :: * -> *) a b. Functor f => a -> f b -> f a
<$ b -> f c
p b
b)

-- | Select an operator from the 'String' it represents.
selectOperator :: (Alternative f, Operator a) => (String -> f c) -> f a
selectOperator :: forall (f :: * -> *) a c.
(Alternative f, Operator a) =>
(String -> f c) -> f a
selectOperator String -> f c
p = (String -> f c) -> [(a, String)] -> f a
forall (f :: * -> *) b c a.
Alternative f =>
(b -> f c) -> [(a, b)] -> f a
select String -> f c
p [(a, String)]
forall a. Operator a => [(a, String)]
operatorTable

-- | Render an operator.
prettyOperator :: Operator a => a -> Doc ann
prettyOperator :: forall a ann. Operator a => a -> Doc ann
prettyOperator = Maybe String -> Doc ann
forall ann. Maybe String -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty (Maybe String -> Doc ann) -> (a -> Maybe String) -> a -> Doc ann
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> [(a, String)] -> Maybe String)
-> [(a, String)] -> a -> Maybe String
forall a b c. (a -> b -> c) -> b -> a -> c
flip a -> [(a, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup [(a, String)]
forall a. Operator a => [(a, String)]
operatorTable