{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}

{- |
    /DEPRECATED/: Use "Data.Generics.Uniplate.Typeable" instead.

    This module supplies a method for writing 'Biplate' instances more easily.

    To take an example:

    > data Expr = Var Int | Neg Expr | Add Expr Expr
    >
    > instance Typeable Expr where ...
    >
    > instance (Typeable a, Uniplate a) => PlateAll Expr a where
    >   plateAll (Var x  ) = plate Var |- x
    >   plateAll (Neg x  ) = plate Neg |+ x
    >   plateAll (Add x y) = plate Add |+ x |+ y
    >
    > instance Uniplate Expr where
    >   uniplate = uniplateAll
-}

module Data.Generics.PlateTypeable
    {-# DEPRECATED "Use Data.Generics.Uniplate.Typeable instead" #-}
    (
    module Data.Generics.Biplate,
    module Data.Typeable,
    -- * The Class
    PlateAll(..), uniplateAll,
    -- * The Combinators
    plate, (|+), (|-)
    ) where

import Data.Generics.Biplate
import Data.Generics.Uniplate.Internal.Utils
import Data.Typeable


instance (Typeable a, Typeable b, Uniplate b, PlateAll a b) => Biplate a b where
    biplate :: BiplateType a b
biplate = forall from to.
(Typeable from, Typeable to, PlateAll from to) =>
from -> Type from to
plateMore


-- | This function is used to write a 'Uniplate' instance from a 'PlateAll' one
uniplateAll :: PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll :: forall a b. PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll = forall a b. PlateAll a b => a -> (Str b, Str b -> a)
plateAll


type Type from to = (Str to, Str to -> from)


plateMore :: (Typeable from, Typeable to, PlateAll from to) => from -> Type from to
plateMore :: forall from to.
(Typeable from, Typeable to, PlateAll from to) =>
from -> Type from to
plateMore from
x = (Str to, Str to -> from)
res
    where
        res :: (Str to, Str to -> from)
res = case forall a. a -> a -> a
asTypeOf (forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast from
x) (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. Str a -> a
strType forall a b. (a -> b) -> a -> b
$ forall a b. (a, b) -> a
fst (Str to, Str to -> from)
res) of
                  Maybe to
Nothing -> forall a b. PlateAll a b => a -> (Str b, Str b -> a)
plateAll from
x
                  Just to
y -> (forall a. a -> Str a
One to
y, \(One to
y) -> forall a b. a -> b
unsafeCoerce to
y)


-- | This class represents going from the container type to the target.
--
-- This class should only be constructed with 'plate', '|+' and '|-'
class PlateAll from to where
    plateAll :: from -> Type from to


-- | The main combinator used to start the chain.
--
-- The following rule can be used for optimisation:
--
-- > plate Ctor |- x == plate (Ctor x)
plate :: from -> Type from to
plate :: forall from to. from -> Type from to
plate from
x = (forall a. Str a
Zero, \Str to
_ -> from
x)


-- | the field to the right may contain the target.
(|+) :: (Typeable item, Typeable to, PlateAll item to) => Type (item -> from) to -> item -> Type from to
|+ :: forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
(|+) (Str to
xs,Str to -> item -> from
x_) item
y = case forall from to.
(Typeable from, Typeable to, PlateAll from to) =>
from -> Type from to
plateMore item
y of
                      (Str to
ys,Str to -> item
y_) -> (forall a. Str a -> Str a -> Str a
Two Str to
xs Str to
ys,\(Two Str to
xs Str to
ys) -> Str to -> item -> from
x_ Str to
xs (Str to -> item
y_ Str to
ys))

-- | The field to the right /does not/ contain the target.
-- This can be used as either an optimisation, or more commonly for excluding
-- primitives such as Int.
(|-) :: Type (item -> from) to -> item -> Type from to
|- :: forall item from to. Type (item -> from) to -> item -> Type from to
(|-) (Str to
xs,Str to -> item -> from
x_) item
y = (Str to
xs,\Str to
xs -> Str to -> item -> from
x_ Str to
xs item
y)


-- * Instances

-- ** Primitive Types

instance PlateAll Int to where plateAll :: Int -> Type Int to
plateAll Int
x = forall from to. from -> Type from to
plate Int
x
instance Uniplate Int where uniplate :: UniplateType Int
uniplate = forall a b. PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll

instance PlateAll Bool to where plateAll :: Bool -> Type Bool to
plateAll Bool
x = forall from to. from -> Type from to
plate Bool
x
instance Uniplate Bool where uniplate :: UniplateType Bool
uniplate = forall a b. PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll

instance PlateAll Char to where plateAll :: Char -> Type Char to
plateAll Char
x = forall from to. from -> Type from to
plate Char
x
instance Uniplate Char where uniplate :: UniplateType Char
uniplate = forall a b. PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll

instance PlateAll Integer to where plateAll :: Integer -> Type Integer to
plateAll Integer
x = forall from to. from -> Type from to
plate Integer
x
instance Uniplate Integer where uniplate :: UniplateType Integer
uniplate = forall a b. PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll

instance PlateAll Double to where plateAll :: Double -> Type Double to
plateAll Double
x = forall from to. from -> Type from to
plate Double
x
instance Uniplate Double where uniplate :: UniplateType Double
uniplate = forall a b. PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll

instance PlateAll Float to where plateAll :: Float -> Type Float to
plateAll Float
x = forall from to. from -> Type from to
plate Float
x
instance Uniplate Float where uniplate :: UniplateType Float
uniplate = forall a b. PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll

instance PlateAll () to where plateAll :: () -> Type () to
plateAll ()
x = forall from to. from -> Type from to
plate ()
x
instance Uniplate () where uniplate :: UniplateType ()
uniplate = forall a b. PlateAll a b => a -> (Str b, Str b -> a)
uniplateAll

-- ** Container Types

instance (PlateAll from to, Typeable from, Typeable to, Uniplate to) => PlateAll [from] to where
    plateAll :: [from] -> Type [from] to
plateAll []     = forall from to. from -> Type from to
plate []
    plateAll (from
x:[from]
xs) = forall from to. from -> Type from to
plate (:) forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ from
x forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ [from]
xs

instance (PlateAll from to, Typeable from, Typeable to, Uniplate to) => PlateAll (Maybe from) to where
    plateAll :: Maybe from -> Type (Maybe from) to
plateAll Maybe from
Nothing  = forall from to. from -> Type from to
plate forall a. Maybe a
Nothing
    plateAll (Just from
x) = forall from to. from -> Type from to
plate forall a. a -> Maybe a
Just forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ from
x

instance (PlateAll a to, Typeable a, PlateAll b to, Typeable b, Typeable to, Uniplate to) =>
         PlateAll (Either a b) to where
    plateAll :: Either a b -> Type (Either a b) to
plateAll (Left  a
x) = forall from to. from -> Type from to
plate forall a b. a -> Either a b
Left  forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ a
x
    plateAll (Right b
x) = forall from to. from -> Type from to
plate forall a b. b -> Either a b
Right forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ b
x

instance (PlateAll a to, Typeable a
         ,PlateAll b to, Typeable b
         ,Typeable to, Uniplate to) =>
         PlateAll (a,b) to where
    plateAll :: (a, b) -> Type (a, b) to
plateAll (a
a,b
b) = forall from to. from -> Type from to
plate (,) forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ a
a forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ b
b

instance (PlateAll a to, Typeable a
         ,PlateAll b to, Typeable b
         ,PlateAll c to, Typeable c
         ,Typeable to, Uniplate to) =>
         PlateAll (a,b,c) to where
    plateAll :: (a, b, c) -> Type (a, b, c) to
plateAll (a
a,b
b,c
c) = forall from to. from -> Type from to
plate (,,) forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ a
a forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ b
b forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ c
c

instance (PlateAll a to, Typeable a
         ,PlateAll b to, Typeable b
         ,PlateAll c to, Typeable c
         ,PlateAll d to, Typeable d
         ,Typeable to, Uniplate to) =>
         PlateAll (a,b,c,d) to where
    plateAll :: (a, b, c, d) -> Type (a, b, c, d) to
plateAll (a
a,b
b,c
c,d
d) = forall from to. from -> Type from to
plate (,,,) forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ a
a forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ b
b forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ c
c forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ d
d

instance (PlateAll a to, Typeable a
         ,PlateAll b to, Typeable b
         ,PlateAll c to, Typeable c
         ,PlateAll d to, Typeable d
         ,PlateAll e to, Typeable e
         ,Typeable to, Uniplate to) =>
         PlateAll (a,b,c,d,e) to where
    plateAll :: (a, b, c, d, e) -> Type (a, b, c, d, e) to
plateAll (a
a,b
b,c
c,d
d,e
e) = forall from to. from -> Type from to
plate (,,,,) forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ a
a forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ b
b forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ c
c forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ d
d forall item to from.
(Typeable item, Typeable to, PlateAll item to) =>
Type (item -> from) to -> item -> Type from to
|+ e
e