module Mida.Language.Environment
( MidaEnv (..)
, runMidaEnv
, addDef
, remDef
, clearDefs
, getPrin
, getSrc
, fullSrc
, getRefs
, purgeEnv
, checkRecur
, setRandGen
, newRandGen )
where
import Control.Arrow ((***), (>>>))
import Control.Monad.State.Strict
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import System.Random (split)
import qualified Data.Map.Strict as M
import qualified Data.Text.Lazy as T
import System.Random.TF (TFGen, mkTFGen)
import Mida.Language.SyntaxTree
import Mida.Representation.Base (noteAlias, modifiers)
import Mida.Representation.Show (showDefinition)
data MidaEnvSt = MidaEnvSt
{ stDefs :: Defs
, stRandGen :: TFGen }
type Defs = M.Map String SyntaxTree
newtype MidaEnv m a = MidaEnv
{ unMidaEnv :: StateT MidaEnvSt m a }
deriving ( Functor
, Applicative
, Monad
, MonadState MidaEnvSt
, MonadTrans
, MonadIO )
runMidaEnv :: Monad m => MidaEnv m a -> m a
runMidaEnv e = evalStateT (unMidaEnv e) MidaEnvSt
{ stDefs = defaultDefs
, stRandGen = mkTFGen 0 }
defaultDefs :: Defs
defaultDefs = M.fromList $ zip noteAlias (f <$> [0..])
<> zip modifiers (f <$> [128,256..])
where f = return . Value
getDefs :: Monad m => MidaEnv m Defs
getDefs = gets stDefs
setDefs :: Monad m => Defs -> MidaEnv m ()
setDefs x = modify $ \e -> e { stDefs = x }
addDef :: Monad m => String -> SyntaxTree -> MidaEnv m ()
addDef name tree = M.insert name tree <$> getDefs >>= setDefs
remDef :: Monad m => String -> MidaEnv m ()
remDef name = M.delete name <$> getDefs >>= setDefs
clearDefs :: Monad m => MidaEnv m ()
clearDefs = setDefs defaultDefs
getPrin :: Monad m => String -> MidaEnv m SyntaxTree
getPrin name = (fromMaybe [] . M.lookup name) <$> getDefs
getSrc :: Monad m => String -> MidaEnv m T.Text
getSrc name = showDefinition name <$> getPrin name
fullSrc :: Monad m => MidaEnv m T.Text
fullSrc = (M.foldMapWithKey showDefinition . (M.\\ defaultDefs)) <$> getDefs
getRefs :: Monad m => MidaEnv m [String]
getRefs = M.keys <$> getDefs
tDefs :: String -> Defs -> [String]
tDefs name defs = maybe mzero cm $ name `M.lookup` defs
where cm = (>>= f)
f (Value _) = mempty
f (Section x) = cm x
f (Multi x) = cm x
f (CMulti x) = x >>= (cm *** cm >>> uncurry (<>))
f (Reference x) = return x <> tDefs x defs
f (Range _ _) = mempty
f (Product x y) = f x <> f y
f (Division x y) = f x <> f y
f (Sum x y) = f x <> f y
f (Diff x y) = f x <> f y
f (Loop x y) = f x <> f y
f (Rotation x y) = f x <> f y
f (Reverse x) = f x
purgeEnv :: Monad m => [String] -> MidaEnv m ()
purgeEnv tops = f <$> getDefs >>= setDefs
where f defs = M.intersection defs $ M.unions [ts, ms defs, defaultDefs]
ms = M.unions . fmap toDefs . zipWith tDefs tops . repeat
ts = toDefs tops
checkRecur :: Monad m => String -> SyntaxTree -> MidaEnv m Bool
checkRecur name tree = check <$> getDefs
where check = elem name . tDefs name . M.insert name tree
setRandGen :: Monad m => Int -> MidaEnv m ()
setRandGen x = modify $ \e -> e { stRandGen = mkTFGen x }
newRandGen :: Monad m => MidaEnv m TFGen
newRandGen = do
(g, g') <- split <$> gets stRandGen
modify $ \e -> e { stRandGen = g' }
return g
toDefs :: [String] -> Defs
toDefs = M.fromList . fmap (, [])