-- Copyright © 2011 National Institute of Aerospace / Galois, Inc.

{-# LANGUAGE Safe #-}

-- | Boolean operators applied point-wise to streams.
module Copilot.Language.Operators.Boolean
  ( (&&)
  , (||)
  , not
  , true
  , false
  , xor
  , (==>)
  ) where

import qualified Copilot.Core as Core
import Copilot.Language.Prelude
import Copilot.Language.Operators.Constant (constant)
import Copilot.Language.Stream
import qualified Prelude as P

-- | A stream that contains the constant value 'True'.
true :: Stream Bool
true = constant True

-- | A stream that contains the constant value 'False'.
false :: Stream Bool
false = constant False

infixr 4 &&

-- | Apply the and ('&&') operator to two boolean streams, point-wise.
(&&) :: Stream Bool -> Stream Bool -> Stream Bool
(Const False) && _ = false
_ && (Const False) = false
(Const True) && y  = y
x && (Const True)  = x
x && y             = Op2 Core.And x y

infixr 4 ||

-- | Apply the or ('||') operator to two boolean streams, point-wise.
(||) :: Stream Bool -> Stream Bool -> Stream Bool
(Const True) || _  = true
_ || (Const True)  = true
(Const False) || y = y
x || (Const False) = x
x || y             = Op2 Core.Or x y

-- | Negate all the values in a boolean stream.
not :: Stream Bool -> Stream Bool
not (Const c) = (Const $ P.not c)
not x         = Op1 Core.Not x

-- | Apply the exclusive-or ('xor') operator to two boolean streams,
-- point-wise.
xor :: Stream Bool -> Stream Bool -> Stream Bool
xor x y = ( not x && y ) || ( x && not y )

-- | Apply the implication ('==>') operator to two boolean streams, point-wise.
(==>) :: Stream Bool -> Stream Bool -> Stream Bool
x ==> y = not x || y
