--------------------------------------------------------------------------------
-- 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 :: Stream Bool
true = Bool -> Stream Bool
forall a. Typed a => a -> Stream a
constant Bool
True

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

infixr 4 &&

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

infixr 4 ||

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

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

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

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

--------------------------------------------------------------------------------