module Csound.Exp.Logic() where
import Control.Monad.Trans.State
import Data.Fix
import qualified Data.IntMap as IM
import Control.Applicative
import Data.Boolean
import Csound.Exp.Wrapper
import Csound.Exp
instance Boolean BoolSig where
true = boolOp0 TrueOp
false = boolOp0 FalseOp
notB = BoolSig . notE . unBoolSig
(&&*) = boolOp2 And
(||*) = boolOp2 Or
type instance BooleanOf Sig = BoolSig
instance IfB Sig where
ifB = cond'
instance EqB Sig where
(==*) = boolOp2 Equals
(/=*) = boolOp2 NotEquals
instance OrdB Sig where
(<*) = boolOp2 Less
(>*) = boolOp2 Greater
(<=*) = boolOp2 LessEquals
(>=*) = boolOp2 GreaterEquals
instance Boolean BoolD where
true = boolOp0 TrueOp
false = boolOp0 FalseOp
notB = BoolD . notE . unBoolD
(&&*) = boolOp2 And
(||*) = boolOp2 Or
type instance BooleanOf D = BoolD
instance IfB D where
ifB = cond'
instance EqB D where
(==*) = boolOp2 Equals
(/=*) = boolOp2 NotEquals
instance OrdB D where
(<*) = boolOp2 Less
(>*) = boolOp2 Greater
(<=*) = boolOp2 LessEquals
(>=*) = boolOp2 GreaterEquals
type instance BooleanOf Tab = BoolD
instance IfB Tab where
ifB = cond'
type instance BooleanOf Str = BoolD
instance IfB Str where
ifB = cond'
boolExp = PreInline
cond' :: (Val bool, Val a) => bool -> a -> a -> a
cond' p t e = wrap $ mkCond (condInfo $ toPrimOr $ Fix $ unwrap p) (unwrap t) (unwrap e)
where mkCond :: CondInfo (PrimOr E) -> RatedExp E -> RatedExp E -> RatedExp E
mkCond p t e
| isTrue p = t
| isFalse p = e
| otherwise = noRate $ If p (toPrimOr $ Fix t) (toPrimOr $ Fix e)
condInfo :: PrimOr E -> CondInfo (PrimOr E)
condInfo exp = (\(a, b) -> Inline a (IM.fromList b)) $ evalState (condInfo' exp) 0
where condInfo' :: PrimOr E -> State Int (InlineExp CondOp, [(Int, PrimOr E)])
condInfo' e = maybe (onLeaf e) (onExp e) $ parseNode e
onLeaf e = state $ \n -> ((InlinePrim n, [(n, e)]), n+1)
onExp e (op, args) = mkNode <$> mapM condInfo' args
where mkNode as = (InlineExp op (map fst as), concat $ map snd as)
parseNode :: PrimOr E -> Maybe (CondOp, [PrimOr E])
parseNode x = case unPrimOr $ fmap (ratedExpExp . unFix) x of
Right (ExpBool (PreInline op args)) -> Just (op, args)
_ -> Nothing
boolOps :: (Val a) => CondOp -> [E] -> a
boolOps op as = noRate $ ExpBool $ boolExp op $ fmap toPrimOr as
boolOp0 :: Val a => CondOp -> a
boolOp0 op = boolOps op []
boolOp1 :: Val a => CondOp -> a -> a
boolOp1 op a = boolOps op [setRate Kr $ Fix $ unwrap a]
boolOp2 :: (Val a1, Val a2, Val b) => CondOp -> a1 -> a2 -> b
boolOp2 op a b = boolOps op $ map (Fix . setRate Kr) [unwrap a, unwrap b]
notE :: E -> E
notE x = Fix $ onExp phi $ unFix x
where phi (ExpBool (PreInline op args)) = ExpBool $ case op of
TrueOp -> boolExp FalseOp []
FalseOp -> boolExp TrueOp []
And -> boolExp Or $ fmap (fmap notE) args
Or -> boolExp And $ fmap (fmap notE) args
Equals -> boolExp NotEquals args
NotEquals -> boolExp Equals args
Less -> boolExp GreaterEquals args
Greater -> boolExp LessEquals args
LessEquals -> boolExp Greater args
GreaterEquals -> boolExp Less args