{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
module Data.TypedEncoding.Instances.Restriction.Bool where
import GHC.TypeLits
import Data.Proxy
import Data.Symbol.Ascii
import Data.TypedEncoding
import Data.TypedEncoding.Instances.Support
import Data.TypedEncoding.Instances.Support.Unsafe
encBoolOrLeft :: forall f s t xs c str . (
BoolOpIs s "or" ~ 'True
, Functor f
, LeftTerm s ~ t
) => (Enc xs c str -> f (Enc (t ': xs) c str)) -> Enc xs c str -> f (Enc (s ': xs) c str)
encBoolOrLeft = implChangeAnn
encBoolOrLeft' :: forall f s t xs c str . (
BoolOpIs s "or" ~ 'True
, Functor f
, LeftTerm s ~ t
, Encode f t t c str
) => Enc xs c str -> f (Enc (s ': xs) c str)
encBoolOrLeft' = encBoolOrLeft'' @t
encBoolOrLeft'' :: forall alg f s t xs c str . (
BoolOpIs s "or" ~ 'True
, Functor f
, LeftTerm s ~ t
, Encode f t alg c str
) => Enc xs c str -> f (Enc (s ': xs) c str)
encBoolOrLeft'' = encBoolOrLeft (encodeF' @alg @t @xs @f)
encBoolOrRight :: forall f s t xs c str . (
BoolOpIs s "or" ~ 'True
, Functor f
, RightTerm s ~ t
) => (Enc xs c str -> f (Enc (t ': xs) c str)) -> Enc xs c str -> f (Enc (s ': xs) c str)
encBoolOrRight = implChangeAnn
encBoolOrRight' :: forall f s t xs c str . (
BoolOpIs s "or" ~ 'True
, Functor f
, RightTerm s ~ t
, Encode f t t c str
) => Enc xs c str -> f (Enc (s ': xs) c str)
encBoolOrRight' = encBoolOrRight'' @t
encBoolOrRight'' :: forall alg f s t xs c str . (
BoolOpIs s "or" ~ 'True
, Functor f
, RightTerm s ~ t
, Encode f t alg c str
) => Enc xs c str -> f (Enc (s ': xs) c str)
encBoolOrRight'' = encBoolOrRight (encodeF' @alg @t @xs @f)
encBoolAnd :: forall f s t1 t2 xs c str . (
BoolOpIs s "and" ~ 'True
, KnownSymbol s
, f ~ Either EncodeEx
, Eq str
, LeftTerm s ~ t1
, RightTerm s ~ t2
) =>
(Enc xs c str -> f (Enc (t1 ': xs) c str))
-> (Enc xs c str -> f (Enc (t2 : xs) c str))
-> Enc xs c str -> f (Enc (s ': xs) c str)
encBoolAnd fnl fnr en0 =
let
eent1 = fnl en0
eent2 = fnr en0
p = (Proxy :: Proxy s)
in
case (eent1, eent2) of
(Right ent1, Right ent2) ->
if getPayload ent1 == getPayload ent2
then Right . withUnsafeCoerce id $ ent1
else Left $ EncodeEx p "Left - right encoding do not match"
(_, _) -> mergeErrs (emptyEncErr p) (mergeEncodeEx p) eent1 eent2
encBoolAnd' :: forall s t1 t2 xs c str . (
BoolOpIs s "and" ~ 'True
, KnownSymbol s
, Eq str
, LeftTerm s ~ t1
, RightTerm s ~ t2
, Encode (Either EncodeEx) t1 t1 c str
, Encode (Either EncodeEx) t2 t2 c str
) => Enc xs c str -> Either EncodeEx (Enc (s ': xs) c str)
encBoolAnd' = encBoolAnd'' @t1 @t2
encBoolAnd'' :: forall al1 al2 s t1 t2 xs c str . (
BoolOpIs s "and" ~ 'True
, KnownSymbol s
, Eq str
, LeftTerm s ~ t1
, RightTerm s ~ t2
, Encode (Either EncodeEx) t1 al1 c str
, Encode (Either EncodeEx) t2 al2 c str
) => Enc xs c str -> Either EncodeEx (Enc (s ': xs) c str)
encBoolAnd'' = encBoolAnd (encodeF' @al1 @t1 @xs) (encodeF' @al2 @t2 @xs)
encBoolNot :: forall s t xs c str . (
BoolOpIs s "not" ~ 'True
, KnownSymbol s
, FirstTerm s ~ t
, Restriction t
) => (Enc xs c str -> Either EncodeEx (Enc (t ': xs) c str)) -> Enc xs c str -> Either EncodeEx (Enc (s ': xs) c str)
encBoolNot fn en0 =
let
een = fn en0
p = (Proxy :: Proxy s)
pt = (Proxy :: Proxy t)
in
case een of
Left _ -> Right . withUnsafeCoerce id $ en0
Right _ -> Left $ EncodeEx p $ "Encoding " ++ symbolVal pt ++ " succeeded"
encBoolNot' :: forall s t xs c str . (
BoolOpIs s "not" ~ 'True
, KnownSymbol s
, FirstTerm s ~ t
, KnownSymbol t
, Restriction t
, Encode (Either EncodeEx) t t c str
) => Enc xs c str -> Either EncodeEx (Enc (s ': xs) c str)
encBoolNot' = encBoolNot'' @t
encBoolNot'' :: forall alg s t xs c str . (
BoolOpIs s "not" ~ 'True
, KnownSymbol s
, FirstTerm s ~ t
, Restriction t
, Encode (Either EncodeEx) t alg c str
) => Enc xs c str -> Either EncodeEx (Enc (s ': xs) c str)
encBoolNot'' = encBoolNot (encodeF' @alg @t @xs)
decBoolR :: forall f xs t s c str . (
NestedR s ~ 'True
, Applicative f
) => Enc (s ': xs) c str -> f (Enc xs c str)
decBoolR = implTranP id
recWithEncBoolR :: forall (s :: Symbol) xs c str . (NestedR s ~ 'True)
=> (Enc xs c str -> Either EncodeEx (Enc (s ': xs) c str))
-> Enc xs c str -> Either RecreateEx (Enc (s ': xs) c str)
recWithEncBoolR = unsafeRecWithEncR
unsafeRecWithEncR :: forall (s :: Symbol) xs c str .
(Enc xs c str -> Either EncodeEx (Enc (s ': xs) c str))
-> Enc xs c str -> Either RecreateEx (Enc (s ': xs) c str)
unsafeRecWithEncR fn = either (Left . encToRecrEx) Right . fn
type family BoolOpIs (s :: Symbol) (op :: Symbol) :: Bool where
BoolOpIs s op = AcceptEq ('Text "Invalid bool encoding " ':<>: ShowType s ) (CmpSymbol (BoolOp s) op)
type family BoolOp (s :: Symbol) :: Symbol where
BoolOp s = Fst (BoolOpHelper (Dupl s))
type family BoolOpHelper (x :: (Symbol, Symbol)) :: (Symbol, Bool) where
BoolOpHelper ('(,) s1 s2) = '(,) (ToLower (TakeUntil (Drop 4 s1) ":")) ( AcceptEq ('Text "Invalid bool encoding " ':<>: ShowType s2 ) (CmpSymbol "bool" (Take 4 s2)))
type family IsBool (s :: Symbol) :: Bool where
IsBool s = AcceptEq ('Text "Not boolean encoding " ':<>: ShowType s ) (CmpSymbol "bool" (Take 4 s))
type family NestedR (s :: Symbol) :: Bool where
NestedR "" = 'True
NestedR s = Or (IsROrEmpty s)
(And (IsBool s) (And (NestedR (LeftTerm s)) (NestedR (RightTerm s))))
type family FirstTerm (s :: Symbol) :: Symbol where
FirstTerm s = LeftTerm s
type family SecondTerm (s :: Symbol) :: Symbol where
SecondTerm s = RightTerm s
type family LeftTerm (s :: Symbol) :: Symbol where
LeftTerm s = Concat (LDropLast( LTakeFstParen (LParenCnt (ToList s))))
type family RightTerm (s :: Symbol) :: Symbol where
RightTerm s = Concat (LDropLast (LTakeSndParen 0 (LParenCnt (ToList s))))
type family LDropLast (s :: [Symbol]) :: [Symbol] where
LDropLast '[] = '[]
LDropLast '[x] = '[]
LDropLast (x ': xs) = x ': LDropLast xs
type family LParenCnt (s :: [Symbol]) :: [(Symbol, Nat)] where
LParenCnt '[] = '[]
LParenCnt ("(" ': xs) = LParenCntHelper ('(,) "(" 'Decr) (LParenCnt xs)
LParenCnt (")" ': xs) = LParenCntHelper ('(,) ")" 'Incr) (LParenCnt xs)
LParenCnt (x ': xs) = LParenCntHelper ('(,) x 'NoChng) (LParenCnt xs)
data Adjust = Incr | Decr | NoChng
type family AdjHelper (a :: Adjust) (n :: Nat) :: Nat where
AdjHelper 'Incr n = n + 1
AdjHelper 'Decr 0 = 0
AdjHelper 'Decr n = n - 1
AdjHelper 'NoChng n = n
type family LParenCntHelper (s :: (Symbol, Adjust)) (sx :: [(Symbol, Nat)]) :: [(Symbol, Nat)] where
LParenCntHelper ('(,) x k) '[] = '(,) x (AdjHelper k 0) ': '[]
LParenCntHelper ('(,) x k) ('(,) c i : xs) = '(,) x (AdjHelper k i) ': '(,) c i ': xs
type family LTakeFstParen (si :: [(Symbol, Nat)]) :: [Symbol] where
LTakeFstParen '[] = '[]
LTakeFstParen ('(,) _ 0 ': xs) = LTakeFstParen xs
LTakeFstParen ('(,) ")" 1 ': _) = '[")"]
LTakeFstParen ('(,) a p ': xs) = a ': LTakeFstParen xs
type family LTakeSndParen (n :: Nat) (si :: [(Symbol, Nat)]) :: [Symbol] where
LTakeSndParen _ '[] = '[]
LTakeSndParen 0 ('(,) ")" 1 ': xs) = LTakeSndParen 1 xs
LTakeSndParen 1 ('(,) _ 0 : xs) = LTakeSndParen 1 xs
LTakeSndParen 0 ('(,) _ _ ': xs) = LTakeSndParen 0 xs
LTakeSndParen 1 ('(,) a _ ': xs) = a : LTakeSndParen 1 xs
LTakeSndParen n _ = '[]