packages feed

ideas-0.6: src/Common/Strategy/Location.hs

-----------------------------------------------------------------------------
-- Copyright 2010, Open Universiteit Nederland. This file is distributed 
-- under the terms of the GNU General Public License. For more information, 
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-- Locations in a strategy
--
-----------------------------------------------------------------------------
module Common.Strategy.Location 
   ( StrategyLocation, topLocation, nextLocation, downLocation
   , locationDepth
   , subTaskLocation, nextTaskLocation, parseStrategyLocation
   , StrategyOrRule, strategyLocations, subStrategy, addLocation
   ) where

import Common.Strategy.Abstract
import Common.Strategy.Core
import Common.Transformation
import Common.Uniplate
import Common.Utils (readM)
import Data.Foldable (toList)
import Data.Sequence hiding (take)
import Control.Monad.State

-----------------------------------------------------------
--- Strategy locations

-- | A strategy location corresponds to a substrategy or a rule
newtype StrategyLocation = SL (Seq Int)
   deriving Eq

instance Show StrategyLocation where
   show (SL xs) = show (toList xs)

type StrategyOrRule a = Either (LabeledStrategy a) (Rule a)

topLocation :: StrategyLocation 
topLocation = SL empty

nextLocation :: StrategyLocation -> StrategyLocation
nextLocation (SL xs) =
   case viewr xs of
      EmptyR  -> topLocation -- invalid
      ys :> a -> SL (ys |> (a+1))

downLocation :: StrategyLocation -> StrategyLocation
downLocation (SL xs) = SL (xs |> 0)

locationDepth :: StrategyLocation -> Int
locationDepth (SL xs) = Data.Sequence.length xs

-- old (current) and actual (next major rule) location
subTaskLocation :: StrategyLocation -> StrategyLocation -> StrategyLocation
subTaskLocation (SL xs) (SL ys) = SL (rec xs ys)
 where
   rec xs ys =
      case (viewl xs, viewl ys) of
         (i :< is, j :< js) 
            | i == j    -> i <| rec is js 
            | otherwise -> empty
         (_, j :< _)    -> singleton j
         _              -> empty

-- old (current) and actual (next major rule) location
nextTaskLocation :: StrategyLocation -> StrategyLocation -> StrategyLocation
nextTaskLocation (SL xs) (SL ys) = SL (rec xs ys)
 where
   rec xs ys =
      case (viewl xs, viewl ys) of
         (i :< is, j :< js)
            | i == j    -> i <| rec is js
            | otherwise -> singleton j
         _              -> empty

parseStrategyLocation :: String -> Maybe StrategyLocation
parseStrategyLocation = fmap (SL . fromList) . readM

-- | Returns a list of all strategy locations, paired with the labeled 
-- substrategy or rule at that location

strategyLocations :: LabeledStrategy a -> [(StrategyLocation, StrategyOrRule a)]
strategyLocations = collect . addLocation . toCore . toStrategy
 where
   collect core = 
      case core of
         Label (loc, info) s -> 
            let this = makeLabeledStrategy info (mapLabel snd s)
            in (loc, Left this) : collect s
         Rule (Just (loc, _)) r -> 
            [(loc, Right r)]
         _ -> 
            concatMap collect (children core)

-- | Returns the substrategy or rule at a strategy location. Nothing 
-- indicates that the location is invalid
subStrategy :: StrategyLocation -> LabeledStrategy a -> Maybe (StrategyOrRule a)
subStrategy loc = lookup loc . strategyLocations 
            
-- local helper functions that decorates interesting places with a 
-- strategy lcations (major rules, and labels)
addLocation :: Core l a -> Core (StrategyLocation, l) a
addLocation = flip evalState topLocation . mapCoreM forLabel forRule
 where
   forLabel l ma = do
      loc <- get
      put (downLocation loc)
      rest <- ma
      put (nextLocation loc)
      return (Label (loc, l) rest)
   forRule (Just l) r = do
      loc <- get
      put (nextLocation loc)
      return (Rule (Just (loc, l)) r)
   forRule Nothing r =
      return (Rule Nothing r)