packages feed

mida-0.4.5: src/Mida/Interaction/Base.hs

-- -*- Mode: Haskell; -*-
--
-- This module describes monad for interactive REPL and some basic
-- functions.
--
-- Copyright © 2014, 2015 Mark Karpov
--
-- MIDA is free software: you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- MIDA is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-- details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program. If not, see <http://www.gnu.org/licenses/>.

{-# OPTIONS -fno-warn-orphans #-}

module Mida.Interaction.Base
  ( MidaIO
  , MidaInt
  , runMidaInt
  , MidaSt (..)
  , MidaCfg (..)
  , lift
  , liftEnv
  , getPrevLen
  , setPrevLen
  , getSrcFile
  , setSrcFile
  , getProg
  , setProg
  , getTempo
  , setTempo
  , getPrompt
  , getVerbose
  , getPrvCmd
  , getProgOp
  , getTempoOp
  , dfltSeed
  , dfltQuarter
  , dfltBeats
  , processDef )
where

import Control.Monad.Reader
import Control.Monad.State.Strict

import qualified Data.Text.Format as F
import qualified System.Console.Haskeline as L

import Mida.Language

type MidaIO = MidaInt IO

newtype MidaInt m a = MidaInt
  { unMidaInt :: StateT MidaSt (ReaderT MidaCfg (MidaEnv m)) a }
  deriving ( Functor
           , Applicative
           , Monad
           , MonadState MidaSt
           , MonadReader MidaCfg
           , MonadIO )

instance MonadTrans MidaInt where
  lift = MidaInt . lift . lift . lift

liftEnv :: (Monad m) => MidaEnv m a -> MidaInt m a
liftEnv = MidaInt . lift . lift

deriving instance L.MonadException m => L.MonadException (MidaEnv m)
deriving instance L.MonadException m => L.MonadException (MidaInt m)

data MidaSt = MidaSt
  { stPrevLen :: Int
  , stSrcFile :: String
  , stProg    :: Int
  , stTempo   :: Int }

data MidaCfg = MidaCfg
  { cfgPrompt  :: String
  , cfgVerbose :: Bool
  , cfgPrvCmd  :: String
  , cfgProgOp  :: String
  , cfgTempoOp :: String }

runMidaInt :: Monad m => MidaInt m a -> MidaSt -> MidaCfg -> m a
runMidaInt m st cfg = runMidaEnv (runReaderT (evalStateT (unMidaInt m) st) cfg)

getPrevLen :: MidaIO Int
getPrevLen = gets stPrevLen

setPrevLen :: Int -> MidaIO ()
setPrevLen x = modify $ \e -> e { stPrevLen = x }

getSrcFile :: MidaIO String
getSrcFile = gets stSrcFile

setSrcFile :: String -> MidaIO ()
setSrcFile x = modify $ \e -> e { stSrcFile = x }

getProg :: MidaIO Int
getProg = gets stProg

setProg :: Int -> MidaIO ()
setProg x = modify $ \e -> e { stProg = x }

getTempo :: MidaIO Int
getTempo = gets stTempo

setTempo :: Int -> MidaIO ()
setTempo x = modify $ \e -> e { stTempo = x }

getPrompt :: MidaIO String
getPrompt = asks cfgPrompt

getVerbose :: MidaIO Bool
getVerbose = asks cfgVerbose

getPrvCmd :: MidaIO String
getPrvCmd = asks cfgPrvCmd

getProgOp :: MidaIO String
getProgOp = asks cfgProgOp

getTempoOp :: MidaIO String
getTempoOp = asks cfgTempoOp

dfltSeed :: Int
dfltSeed = 0

dfltQuarter :: Int
dfltQuarter = 24

dfltBeats :: Int
dfltBeats = 16

processDef :: String -> SyntaxTree -> MidaIO ()
processDef n t = do
  recursive <- liftEnv $ checkRecur n t
  if recursive
  then liftIO $ F.print "Rejected recursive definition for «{}».\n" (F.Only n)
  else liftEnv (addDef n t) >> liftIO (F.print "• «{}»\n" (F.Only n))