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

    -- | Integral class operators applied point-wise on streams.

    {-# LANGUAGE Safe #-}

    module Copilot.Language.Operators.Integral
      ( div
      , mod
      , (^)
      ) where

    import Copilot.Core (Typed, typeOf)
    import qualified Copilot.Core as Core
    import qualified Copilot.Language.Error as Err
    import Copilot.Language.Operators.BitWise ((.<<.))
    import Copilot.Language.Stream

    import qualified Data.Bits as B
    import qualified Prelude as P
    import Data.List (foldl', replicate)

    -- | Apply the 'Prelude.div' operation to two streams, point-wise.
    div :: (Typed a, P.Integral a) => Stream a -> Stream a -> Stream a
    (Const a
    0) div :: forall a. (Typed a, Integral a) => Stream a -> Stream a -> Stream a
    `div` Stream a
    _ = a -> Stream a
    forall a. Typed a => a -> Stream a
    Const a
    0
    Stream a
    _ `div` (Const a
    0) = String -> Stream a
    forall a. String -> a
    Err.badUsage String
    "in div: division by zero."
    Stream a
    x `div` (Const a
    1) = Stream a
    x
    Stream a
    x `div` Stream a
    y = Op2 a a a -> Stream a -> Stream a -> Stream a
    forall a1 b a.
    (Typed a1, Typed b, Typed a) =>
    Op2 a1 b a -> Stream a1 -> Stream b -> Stream a
    Op2 (Type a -> Op2 a a a
    forall a. Integral a => Type a -> Op2 a a a
    Core.Div Type a
    forall a. Typed a => Type a
    typeOf) Stream a
    x Stream a
    y

    -- | Apply the 'Prelude.mod' operation to two streams, point-wise.
    mod :: (Typed a, P.Integral a) => Stream a -> Stream a -> Stream a
    Stream a
    _         mod :: forall a. (Typed a, Integral a) => Stream a -> Stream a -> Stream a
    `mod` (Const a
    0) = String -> Stream a
    forall a. String -> a
    Err.badUsage String
    "in mod: division by zero."
    (Const a
    0) `mod` Stream a
    _         = (a -> Stream a
    forall a. Typed a => a -> Stream a
    Const a
    0)
    (Const a
    x) `mod` (Const a
    y) = a -> Stream a
    forall a. Typed a => a -> Stream a
    Const (a
    x a -> a -> a
    forall a. Integral a => a -> a -> a
    `P.mod` a
    y)
    Stream a
    x `mod` Stream a
    y = Op2 a a a -> Stream a -> Stream a -> Stream a
    forall a1 b a.
    (Typed a1, Typed b, Typed a) =>
    Op2 a1 b a -> Stream a1 -> Stream b -> Stream a
    Op2 (Type a -> Op2 a a a
    forall a. Integral a => Type a -> Op2 a a a
    Core.Mod Type a
    forall a. Typed a => Type a
    typeOf) Stream a
    x Stream a
    y

    -- | Apply a limited form of exponentiation (@^@) to two streams, point-wise.
    --
    -- Either the first stream must be the constant 2, or the second must be a
    -- constant stream.
    (^) :: (Typed a, Typed b, P.Num a, B.Bits a, P.Integral b)
        => Stream a -> Stream b -> Stream a
    (Const a
    0) ^ :: forall a b.
    (Typed a, Typed b, Num a, Bits a, Integral b) =>
    Stream a -> Stream b -> Stream a
    ^ (Const b
    0)  = a -> Stream a
    forall a. Typed a => a -> Stream a
    Const a
    1
    (Const a
    0) ^ Stream b
    x          = Op3 Bool a a a -> Stream Bool -> Stream a -> Stream a -> Stream a
    forall a1 b c a.
    (Typed a1, Typed b, Typed c, Typed a) =>
    Op3 a1 b c a -> Stream a1 -> Stream b -> Stream c -> Stream a
    Op3 (Type a -> Op3 Bool a a a
    forall b. Type b -> Op3 Bool b b b
    Core.Mux Type a
    forall a. Typed a => Type a
    typeOf) (Op2 b b Bool -> Stream b -> Stream b -> Stream Bool
    forall a1 b a.
    (Typed a1, Typed b, Typed a) =>
    Op2 a1 b a -> Stream a1 -> Stream b -> Stream a
    Op2 (Type b -> Op2 b b Bool
    forall a. Eq a => Type a -> Op2 a a Bool
    Core.Eq Type b
    forall a. Typed a => Type a
    typeOf) Stream b
    x Stream b
    0) (Stream a
    1) (Stream a
    0)
    (Const a
    1) ^ Stream b
    _          = a -> Stream a
    forall a. Typed a => a -> Stream a
    Const a
    1
    (Const a
    x) ^ (Const b
    y)  = a -> Stream a
    forall a. Typed a => a -> Stream a
    Const (a
    x a -> b -> a
    forall a b. (Num a, Integral b) => a -> b -> a
    P.^ b
    y)
    (Const a
    2) ^ Stream b
    y          = (a -> Stream a
    forall a. Typed a => a -> Stream a
    Const a
    1) Stream a -> Stream b -> Stream a
    forall a b.
    (Bits a, Typed a, Typed b, Integral b) =>
    Stream a -> Stream b -> Stream a
    .<<. Stream b
    y
    Stream a
    x ^ (Const b
    y)          = (Stream a -> Stream a -> Stream a)
    -> Stream a -> [Stream a] -> Stream a
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl' (Stream a -> Stream a -> Stream a
    forall a. Num a => a -> a -> a
    (P.*)) (a -> Stream a
    forall a. Typed a => a -> Stream a
    Const a
    1) (Int -> Stream a -> [Stream a]
    forall a. Int -> a -> [a]
    replicate (b -> Int
    forall a b. (Integral a, Num b) => a -> b
    P.fromIntegral b
    y) Stream a
    x)
    Stream a
    _ ^ Stream b
    _                  = String -> Stream a
    forall a. String -> a
    Err.badUsage String
    "in ^: in x ^ y, either x must be the constant 2, or y must be a constant.  (Do not confuse ^ with bitwise XOR (.^.) or with ** for exponentation of floats/doubles.)"