{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses,
  TypeSynonymInstances, FlexibleContexts #-} 
                                                                                                    
-- | Functions to write imperative style csound code 
                                                     
module CsoundExpr.Base.Imperative (
    outList,
    ar,
    kr,
    ir,
    gar,
    gkr,
    gir,
    Assign(..))
where 
      
import CsoundExpr.Translator.Types
import CsoundExpr.Translator.Cs.IM
import CsoundExpr.Translator.Cs.CsTree
import CsoundExpr.Translator.ExprTree.ExprTree 
                                               
 
ar :: Name -> Arate
ar = argIn A 
             
 
kr :: Name -> Krate
kr = argIn K 
             
 
ir :: Name -> Irate
ir = argIn I 
             
 
gar :: Name -> Arate
gar = argIn GA 
               
 
gkr :: Name -> Krate
gkr = argIn GK 
               
 
gir :: Name -> Irate
gir = argIn GI 
               


fromArgIn :: (IM CsTree a) => a -> (Rate, Name)
fromArgIn a
  | isArg e = (argRate e, argName e)
  | otherwise =
    error "left hand side of <=> should be named expression"
  where e = exprOp $ exprTreeTag t
        t = to a :: CsTree 
 
-- Assign Class 
                
 
infixr 0 <=> 
               
 
class Assign a where

         
        (<=>) :: a -> a -> SignalOut 
                                                                      
 
instance Assign Arate where
        sig <=> expr
          = let (rate, name) = fromArgIn sig in
              SignalOut $ return $ argOut rate name expr 
                                                                                                                                                            
 
instance Assign Krate where
        sig <=> expr
          = let (rate, name) = fromArgIn sig in
              SignalOut $ return $ argOut rate name expr 
                                                                                                                                                            
 
instance Assign Irate where
        sig <=> expr
          = let (rate, name) = fromArgIn sig in
              SignalOut $ return $ argOut rate name expr 
                                                                                                                                                            
 
instance (Assign a) => Assign [a] where
        sigs <=> exprs = outList $ zipWith (<=>) sigs exprs 
                                                                                                      
 
instance (Assign a0, Assign a1) => Assign (a0, a1) where
        (sig0, sig1) <=> (exprs0, exprs1)
          = outList [sig0 <=> exprs0, sig1 <=> exprs1] 
                                                                                                                                                            
 
instance (Assign a0, Assign a1, Assign a2) => Assign (a0, a1, a2)
         where
        (sig0, sig1, sig2) <=> (exprs0, exprs1, exprs2)
          = outList [sig0 <=> exprs0, sig1 <=> exprs1, sig2 <=> exprs2] 
                                                                                                                                                                                                                   
 
instance (Assign a0, Assign a1, Assign a2, Assign a3) => Assign
         (a0, a1, a2, a3) where
        (sig0, sig1, sig2, sig3) <=> (exprs0, exprs1, exprs2, exprs3)
          = outList
              [sig0 <=> exprs0, sig1 <=> exprs1, sig2 <=> exprs2,
               sig3 <=> exprs3] 
                                                                                                                                                                                                                                                                                              
 
instance (Assign a0, Assign a1, Assign a2, Assign a3, Assign a4) =>
         Assign (a0, a1, a2, a3, a4) where
        (sig0, sig1, sig2, sig3, sig4) <=>
          (exprs0, exprs1, exprs2, exprs3, exprs4)
          = outList
              [sig0 <=> exprs0, sig1 <=> exprs1, sig2 <=> exprs2,
               sig3 <=> exprs3, sig4 <=> exprs4] 
                                                                                                                                                                                                                                                                                                                                                      
 
instance (Assign a0, Assign a1, Assign a2, Assign a3, Assign a4,
          Assign a5) =>
         Assign (a0, a1, a2, a3, a4, a5) where
        (sig0, sig1, sig2, sig3, sig4, sig5) <=>
          (exprs0, exprs1, exprs2, exprs3, exprs4, exprs5)
          = outList
              [sig0 <=> exprs0, sig1 <=> exprs1, sig2 <=> exprs2,
               sig3 <=> exprs3, sig4 <=> exprs4, sig5 <=> exprs5] 
                                                                                                                                                                                                                                                                                                                                                                                                              
 
instance (Assign a0, Assign a1, Assign a2, Assign a3, Assign a4,
          Assign a5, Assign a6) =>
         Assign (a0, a1, a2, a3, a4, a5, a6) where
        (sig0, sig1, sig2, sig3, sig4, sig5, sig6) <=>
          (exprs0, exprs1, exprs2, exprs3, exprs4, exprs5, exprs6)
          = outList
              [sig0 <=> exprs0, sig1 <=> exprs1, sig2 <=> exprs2,
               sig3 <=> exprs3, sig4 <=> exprs4, sig5 <=> exprs5, sig6 <=> exprs6] 
                                                                                                                                                                                                                                                                                                                                                                                                                                                            
 
instance (Assign a0, Assign a1, Assign a2, Assign a3, Assign a4,
          Assign a5, Assign a6, Assign a7) =>
         Assign (a0, a1, a2, a3, a4, a5, a6, a7) where
        (sig0, sig1, sig2, sig3, sig4, sig5, sig6, sig7) <=>
          (exprs0, exprs1, exprs2, exprs3, exprs4, exprs5, exprs6, exprs7)
          = outList
              [sig0 <=> exprs0, sig1 <=> exprs1, sig2 <=> exprs2,
               sig3 <=> exprs3, sig4 <=> exprs4, sig5 <=> exprs5, sig6 <=> exprs6,
               sig7 <=> exprs7]