-- 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 0) `div` _ = Const 0 _ `div` (Const 0) = Err.badUsage "in div: division by zero." x `div` (Const 1) = x x `div` y = Op2 (Core.Div typeOf) x y -- | Apply the 'Prelude.mod' operation to two streams, point-wise. mod :: (Typed a, P.Integral a) => Stream a -> Stream a -> Stream a _ `mod` (Const 0) = Err.badUsage "in mod: division by zero." (Const 0) `mod` _ = (Const 0) (Const x) `mod` (Const y) = Const (x `P.mod` y) x `mod` y = Op2 (Core.Mod typeOf) x 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 0) ^ (Const 0) = Const 1 (Const 0) ^ x = Op3 (Core.Mux typeOf) (Op2 (Core.Eq typeOf) x 0) (1) (0) (Const 1) ^ _ = Const 1 (Const x) ^ (Const y) = Const (x P.^ y) (Const 2) ^ y = (Const 1) .<<. y x ^ (Const y) = foldl' ((P.*)) (Const 1) (replicate (P.fromIntegral y) x) _ ^ _ = Err.badUsage "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.)"