{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}

{-# HLINT ignore "Eta reduce" #-}

-- |
-- Module      :   Grisette.Internal.SymPrim.Prim.Internal.Instances.PEvalBitwiseTerm
-- Copyright   :   (c) Sirui Lu 2024
-- License     :   BSD-3-Clause (see the LICENSE file)
--
-- Maintainer  :   siruilu@cs.washington.edu
-- Stability   :   Experimental
-- Portability :   GHC only
module Grisette.Internal.SymPrim.Prim.Internal.Instances.PEvalBitwiseTerm () where

import Data.Bits (Bits (complement, xor, zeroBits, (.&.), (.|.)))
import GHC.TypeLits (KnownNat, type (<=))
import Grisette.Internal.SymPrim.BV (IntN, WordN)
import Grisette.Internal.SymPrim.Prim.Internal.Instances.SupportedPrim ()
import Grisette.Internal.SymPrim.Prim.Internal.Term
  ( PEvalBitwiseTerm
      ( pevalAndBitsTerm,
        pevalComplementBitsTerm,
        pevalOrBitsTerm,
        pevalXorBitsTerm,
        withSbvBitwiseTermConstraint
      ),
    SupportedPrim (withPrim),
    Term (ComplementBitsTerm, ConTerm),
    andBitsTerm,
    complementBitsTerm,
    conTerm,
    orBitsTerm,
    xorBitsTerm,
  )
import Grisette.Internal.SymPrim.Prim.Internal.Unfold
  ( binaryUnfoldOnce,
    unaryUnfoldOnce,
  )

pevalDefaultAndBitsTerm ::
  (Bits a, SupportedPrim a, PEvalBitwiseTerm a) => Term a -> Term a -> Term a
pevalDefaultAndBitsTerm :: forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a -> Term a
pevalDefaultAndBitsTerm = PartialRuleBinary a a a
-> TotalRuleBinary a a a -> TotalRuleBinary a a a
forall a b c.
(Typeable a, Typeable b, SupportedPrim c) =>
PartialRuleBinary a b c
-> TotalRuleBinary a b c -> TotalRuleBinary a b c
binaryUnfoldOnce PartialRuleBinary a a a
forall {t}.
(SupportedPrim t, Bits t) =>
Term t -> Term t -> Maybe (Term t)
doPevalAndBitsTerm TotalRuleBinary a a a
forall a. PEvalBitwiseTerm a => Term a -> Term a -> Term a
andBitsTerm
  where
    doPevalAndBitsTerm :: Term t -> Term t -> Maybe (Term t)
doPevalAndBitsTerm (ConTerm Id
_ t
a) (ConTerm Id
_ t
b) = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm (t
a t -> t -> t
forall a. Bits a => a -> a -> a
.&. t
b)
    doPevalAndBitsTerm (ConTerm Id
_ t
a) Term t
b
      | t
a t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm t
forall a. Bits a => a
zeroBits
      | t
a t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t -> t
forall a. Bits a => a -> a
complement t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
b
    doPevalAndBitsTerm Term t
a (ConTerm Id
_ t
b)
      | t
b t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm t
forall a. Bits a => a
zeroBits
      | t
b t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t -> t
forall a. Bits a => a -> a
complement t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
a
    doPevalAndBitsTerm Term t
a Term t
b | Term t
a Term t -> Term t -> Bool
forall a. Eq a => a -> a -> Bool
== Term t
b = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
a
    doPevalAndBitsTerm Term t
_ Term t
_ = Maybe (Term t)
forall a. Maybe a
Nothing

pevalDefaultOrBitsTerm ::
  (Bits a, SupportedPrim a, PEvalBitwiseTerm a) => Term a -> Term a -> Term a
pevalDefaultOrBitsTerm :: forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a -> Term a
pevalDefaultOrBitsTerm = PartialRuleBinary a a a
-> TotalRuleBinary a a a -> TotalRuleBinary a a a
forall a b c.
(Typeable a, Typeable b, SupportedPrim c) =>
PartialRuleBinary a b c
-> TotalRuleBinary a b c -> TotalRuleBinary a b c
binaryUnfoldOnce PartialRuleBinary a a a
forall {t}.
(SupportedPrim t, Bits t) =>
Term t -> Term t -> Maybe (Term t)
doPevalOrBitsTerm TotalRuleBinary a a a
forall a. PEvalBitwiseTerm a => Term a -> Term a -> Term a
orBitsTerm
  where
    doPevalOrBitsTerm :: Term t -> Term t -> Maybe (Term t)
doPevalOrBitsTerm (ConTerm Id
_ t
a) (ConTerm Id
_ t
b) = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm (t
a t -> t -> t
forall a. Bits a => a -> a -> a
.|. t
b)
    doPevalOrBitsTerm (ConTerm Id
_ t
a) Term t
b
      | t
a t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
b
      | t
a t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t -> t
forall a. Bits a => a -> a
complement t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm (t -> Term t) -> t -> Term t
forall a b. (a -> b) -> a -> b
$ t -> t
forall a. Bits a => a -> a
complement t
forall a. Bits a => a
zeroBits
    doPevalOrBitsTerm Term t
a (ConTerm Id
_ t
b)
      | t
b t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
a
      | t
b t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t -> t
forall a. Bits a => a -> a
complement t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm (t -> Term t) -> t -> Term t
forall a b. (a -> b) -> a -> b
$ t -> t
forall a. Bits a => a -> a
complement t
forall a. Bits a => a
zeroBits
    doPevalOrBitsTerm Term t
a Term t
b | Term t
a Term t -> Term t -> Bool
forall a. Eq a => a -> a -> Bool
== Term t
b = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
a
    doPevalOrBitsTerm Term t
_ Term t
_ = Maybe (Term t)
forall a. Maybe a
Nothing

pevalDefaultXorBitsTerm ::
  (PEvalBitwiseTerm a, SupportedPrim a) => Term a -> Term a -> Term a
pevalDefaultXorBitsTerm :: forall a.
(PEvalBitwiseTerm a, SupportedPrim a) =>
Term a -> Term a -> Term a
pevalDefaultXorBitsTerm = PartialRuleBinary a a a
-> TotalRuleBinary a a a -> TotalRuleBinary a a a
forall a b c.
(Typeable a, Typeable b, SupportedPrim c) =>
PartialRuleBinary a b c
-> TotalRuleBinary a b c -> TotalRuleBinary a b c
binaryUnfoldOnce PartialRuleBinary a a a
forall {t}.
PEvalBitwiseTerm t =>
Term t -> Term t -> Maybe (Term t)
doPevalXorBitsTerm TotalRuleBinary a a a
forall a. PEvalBitwiseTerm a => Term a -> Term a -> Term a
xorBitsTerm
  where
    doPevalXorBitsTerm :: Term t -> Term t -> Maybe (Term t)
doPevalXorBitsTerm (ConTerm Id
_ t
a) (ConTerm Id
_ t
b) =
      Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm (t
a t -> t -> t
forall a. Bits a => a -> a -> a
`xor` t
b)
    doPevalXorBitsTerm (ConTerm Id
_ t
a) Term t
b
      | t
a t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
b
      | t
a t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t -> t
forall a. Bits a => a -> a
complement t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ Term t -> Term t
forall t. PEvalBitwiseTerm t => Term t -> Term t
pevalComplementBitsTerm Term t
b
    doPevalXorBitsTerm Term t
a (ConTerm Id
_ t
b)
      | t
b t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
a
      | t
b t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t -> t
forall a. Bits a => a -> a
complement t
forall a. Bits a => a
zeroBits = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ Term t -> Term t
forall t. PEvalBitwiseTerm t => Term t -> Term t
pevalComplementBitsTerm Term t
a
    doPevalXorBitsTerm Term t
a Term t
b | Term t
a Term t -> Term t -> Bool
forall a. Eq a => a -> a -> Bool
== Term t
b = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm t
forall a. Bits a => a
zeroBits
    doPevalXorBitsTerm (ComplementBitsTerm Id
_ Term t
i) (ComplementBitsTerm Id
_ Term t
j) =
      Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ Term t -> Term t -> Term t
forall a. PEvalBitwiseTerm a => Term a -> Term a -> Term a
pevalXorBitsTerm Term t
i Term t
j
    doPevalXorBitsTerm (ComplementBitsTerm Id
_ Term t
i) Term t
j =
      Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ Term t -> Term t
forall t. PEvalBitwiseTerm t => Term t -> Term t
pevalComplementBitsTerm (Term t -> Term t) -> Term t -> Term t
forall a b. (a -> b) -> a -> b
$ Term t -> Term t -> Term t
forall a. PEvalBitwiseTerm a => Term a -> Term a -> Term a
pevalXorBitsTerm Term t
i Term t
j
    doPevalXorBitsTerm Term t
i (ComplementBitsTerm Id
_ Term t
j) =
      Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ Term t -> Term t
forall t. PEvalBitwiseTerm t => Term t -> Term t
pevalComplementBitsTerm (Term t -> Term t) -> Term t -> Term t
forall a b. (a -> b) -> a -> b
$ Term t -> Term t -> Term t
forall a. PEvalBitwiseTerm a => Term a -> Term a -> Term a
pevalXorBitsTerm Term t
i Term t
j
    doPevalXorBitsTerm Term t
_ Term t
_ = Maybe (Term t)
forall a. Maybe a
Nothing

pevalDefaultComplementBitsTerm ::
  (Bits a, SupportedPrim a, PEvalBitwiseTerm a) => Term a -> Term a
pevalDefaultComplementBitsTerm :: forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a
pevalDefaultComplementBitsTerm =
  PartialRuleUnary a a -> TotalRuleUnary a a -> TotalRuleUnary a a
forall a b.
SupportedPrim b =>
PartialRuleUnary a b -> TotalRuleUnary a b -> TotalRuleUnary a b
unaryUnfoldOnce PartialRuleUnary a a
forall {t}. Bits t => Term t -> Maybe (Term t)
doPevalComplementBitsTerm TotalRuleUnary a a
forall t. PEvalBitwiseTerm t => Term t -> Term t
complementBitsTerm
  where
    doPevalComplementBitsTerm :: Term t -> Maybe (Term t)
doPevalComplementBitsTerm (ConTerm Id
_ t
a) = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just (Term t -> Maybe (Term t)) -> Term t -> Maybe (Term t)
forall a b. (a -> b) -> a -> b
$ t -> Term t
forall t.
(SupportedPrim t, Typeable t, Hashable t, Eq t, Show t) =>
t -> Term t
conTerm (t -> Term t) -> t -> Term t
forall a b. (a -> b) -> a -> b
$ t -> t
forall a. Bits a => a -> a
complement t
a
    doPevalComplementBitsTerm (ComplementBitsTerm Id
_ Term t
a) = Term t -> Maybe (Term t)
forall a. a -> Maybe a
Just Term t
a
    doPevalComplementBitsTerm Term t
_ = Maybe (Term t)
forall a. Maybe a
Nothing

instance (KnownNat n, 1 <= n) => PEvalBitwiseTerm (WordN n) where
  pevalAndBitsTerm :: Term (WordN n) -> Term (WordN n) -> Term (WordN n)
pevalAndBitsTerm = Term (WordN n) -> Term (WordN n) -> Term (WordN n)
forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a -> Term a
pevalDefaultAndBitsTerm
  pevalOrBitsTerm :: Term (WordN n) -> Term (WordN n) -> Term (WordN n)
pevalOrBitsTerm = Term (WordN n) -> Term (WordN n) -> Term (WordN n)
forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a -> Term a
pevalDefaultOrBitsTerm
  pevalXorBitsTerm :: Term (WordN n) -> Term (WordN n) -> Term (WordN n)
pevalXorBitsTerm = Term (WordN n) -> Term (WordN n) -> Term (WordN n)
forall a.
(PEvalBitwiseTerm a, SupportedPrim a) =>
Term a -> Term a -> Term a
pevalDefaultXorBitsTerm
  pevalComplementBitsTerm :: Term (WordN n) -> Term (WordN n)
pevalComplementBitsTerm = Term (WordN n) -> Term (WordN n)
forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a
pevalDefaultComplementBitsTerm
  withSbvBitwiseTermConstraint :: forall (n :: Nat) (proxy :: Nat -> *) r.
KnownIsZero n =>
proxy n -> (Bits (SBVType n (WordN n)) => r) -> r
withSbvBitwiseTermConstraint proxy n
p Bits (SBVType n (WordN n)) => r
r = forall t (n :: Nat) (p :: Nat -> *) a.
(SupportedPrim t, KnownIsZero n) =>
p n
-> ((PrimConstraint n t, SMTDefinable (SBVType n t),
     Mergeable (SBVType n t), Typeable (SBVType n t)) =>
    a)
-> a
withPrim @(WordN n) proxy n
p r
Bits (SBVType n (WordN n)) => r
(PrimConstraint n (WordN n), SMTDefinable (SBVType n (WordN n)),
 Mergeable (SBVType n (WordN n)), Typeable (SBVType n (WordN n))) =>
r
r

instance (KnownNat n, 1 <= n) => PEvalBitwiseTerm (IntN n) where
  pevalAndBitsTerm :: Term (IntN n) -> Term (IntN n) -> Term (IntN n)
pevalAndBitsTerm = Term (IntN n) -> Term (IntN n) -> Term (IntN n)
forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a -> Term a
pevalDefaultAndBitsTerm
  pevalOrBitsTerm :: Term (IntN n) -> Term (IntN n) -> Term (IntN n)
pevalOrBitsTerm = Term (IntN n) -> Term (IntN n) -> Term (IntN n)
forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a -> Term a
pevalDefaultOrBitsTerm
  pevalXorBitsTerm :: Term (IntN n) -> Term (IntN n) -> Term (IntN n)
pevalXorBitsTerm = Term (IntN n) -> Term (IntN n) -> Term (IntN n)
forall a.
(PEvalBitwiseTerm a, SupportedPrim a) =>
Term a -> Term a -> Term a
pevalDefaultXorBitsTerm
  pevalComplementBitsTerm :: Term (IntN n) -> Term (IntN n)
pevalComplementBitsTerm = Term (IntN n) -> Term (IntN n)
forall a.
(Bits a, SupportedPrim a, PEvalBitwiseTerm a) =>
Term a -> Term a
pevalDefaultComplementBitsTerm
  withSbvBitwiseTermConstraint :: forall (n :: Nat) (proxy :: Nat -> *) r.
KnownIsZero n =>
proxy n -> (Bits (SBVType n (IntN n)) => r) -> r
withSbvBitwiseTermConstraint proxy n
p Bits (SBVType n (IntN n)) => r
r = forall t (n :: Nat) (p :: Nat -> *) a.
(SupportedPrim t, KnownIsZero n) =>
p n
-> ((PrimConstraint n t, SMTDefinable (SBVType n t),
     Mergeable (SBVType n t), Typeable (SBVType n t)) =>
    a)
-> a
withPrim @(IntN n) proxy n
p r
Bits (SBVType n (IntN n)) => r
(PrimConstraint n (IntN n), SMTDefinable (SBVType n (IntN n)),
 Mergeable (SBVType n (IntN n)), Typeable (SBVType n (IntN n))) =>
r
r