module Ideas.Common.Strategy.Parsing
(
runCore
, Prefix, noPrefix, makePrefix, replayCore
, isEmptyPrefix, majorPrefix, searchModePrefix, prefixPaths
, Step(..), stepRule, stepEnvironment
, Path, emptyPath, readPath, readPaths
) where
import Control.Monad
import Data.Function
import Data.List
import Ideas.Common.Classes
import Ideas.Common.Environment
import Ideas.Common.Id
import Ideas.Common.Rule
import Ideas.Common.Strategy.Choice
import Ideas.Common.Strategy.Core
import Ideas.Common.Strategy.Derived
import Ideas.Common.Strategy.Process
import Ideas.Common.Strategy.Sequence
import Ideas.Common.Utils (fst3, splitsWithElem, readM)
import Ideas.Common.Utils.Uniplate
runCore :: Core a -> a -> [a]
runCore core a = bests $ accum applyAll a $ coreToProcess False core
coreToProcess :: Bool -> Core a -> Process (Step a)
coreToProcess useLabels = fromAtoms . toProcess . rec . coreSubstAll
where
rec :: Core a -> Builder (Sym (Step a))
rec core =
case core of
a :*: b -> rec a <*> rec b
a :|: b -> rec a <|> rec b
a :>|> b -> rec a >|> rec b
a :|>: b -> rec a |> rec b
Rule r -> single (Single (RuleStep mempty r))
Fail -> empty
Succeed -> done
Label l a
| useLabels -> Single (Enter l) ~> rec a
<*> single (Single (Exit l))
| otherwise -> rec a
a :%: b -> concurrent switch (rec a) (rec b)
a :@: b -> rec a <@> rec b
Atomic a -> atomic (rec a)
Not a -> notCore a
Remove _ -> empty
Collapse a -> rec (collapse a)
Hide a -> rec (fmap minor a)
Let _ _ -> error "not substituted: let"
Var _ -> error "not substituted: var"
switch (Single (Enter _)) = False
switch _ = True
collapse :: Core a -> Core a
collapse (Label l s) = Rule $ makeRule l (runCore s)
collapse core = descend collapse core
notCore :: Core a -> Builder (Sym (Step a))
notCore core = single $ Single $ RuleStep mempty $
checkRule "core.not" $ null . runCore core
data Prefix a = Prefix
{ getPaths :: [Path]
, remainder :: Process (Step a, a, Path)
}
instance Show (Prefix a) where
show = intercalate ";" . map show . prefixPaths
instance Monoid (Prefix a) where
mempty = noPrefix
mappend (Prefix xs p) (Prefix ys q) = Prefix (xs ++ ys) (p <|> q)
instance Firsts (Prefix a) where
type Elem (Prefix a) = (Step a, a)
menu = fmap f . menu . remainder
where
f Done = Done
f ((st, a, path) :~> p) = (st, a) :~> Prefix [path] p
noPrefix :: Prefix a
noPrefix = Prefix [] empty
makePrefix :: Core a -> a -> Prefix a
makePrefix = snd . replayCore emptyPath
replayCore :: Path -> Core a -> ([Step a], a -> Prefix a)
replayCore path core =
let (acc, p) = runPath path (withPath (coreToProcess True core))
in (map fst acc, Prefix [path] . applySteps p)
runPath :: Path -> Process a -> ([a], Process a)
runPath (Path is) = rec [] is
where
rec acc [] p = (reverse acc, p)
rec acc (n:ns) p =
case getByIndex n (menu p) of
Just (a :~> r) -> rec (a:acc) ns r
_ -> ([], empty)
applySteps :: Process (Step a, Path) -> a -> Process (Step a, a, Path)
applySteps p a0 = prune (isMajor . fst3) (scan f a0 p)
where
f a (RuleStep _ r, path) =
[ (b, (RuleStep env r, b, path))
| (b, env) <- transApply (transformation r) a
]
f a (st, path) = [(a, (st, a, path))]
withPath :: Process a -> Process (a, Path)
withPath = rec []
where
rec ns = mapWithIndex (menuItem done . f ns) . menu
f ns n a p =
let ms = n:ns
in (a, Path (reverse ms)) ~> rec ms p
isEmptyPrefix :: Prefix a -> Bool
isEmptyPrefix = all (== emptyPath) . getPaths
majorPrefix :: Prefix a -> Prefix a
majorPrefix prfx = prfx { remainder = hide (isMajor . fst3) (remainder prfx) }
searchModePrefix :: (Step a -> Step a -> Bool) -> Prefix a -> Prefix a
searchModePrefix eq prfx =
prfx { remainder = rec (remainder (majorPrefix prfx)) }
where
eq3 = eq `on` fst3
rec p | ready p = done
| otherwise = process (firsts p)
process [] = empty
process ((a, p):xs) =
let ys = map fst $ firsts (a ~> p)
in (a ~> rec p) <|> process (concatMap (change ys) xs)
change ys (a, q) =
let f x = all (not . eq3 x) ys
in firsts $ filterP f (a ~> q)
prefixPaths :: Prefix a -> [Path]
prefixPaths = getPaths
data Step a = Enter Id
| Exit Id
| RuleStep Environment (Rule a)
deriving Eq
instance Show (Step a) where
show (Enter l) = "enter " ++ showId l
show (Exit l) = "exit " ++ showId l
show (RuleStep _ r) = show r
instance Apply Step where
applyAll (RuleStep _ r) = applyAll r
applyAll _ = return
instance HasId (Step a) where
getId (Enter l) = getId l
getId (Exit l) = getId l
getId (RuleStep _ r) = getId r
changeId f (Enter l) = Enter (changeId f l)
changeId f (Exit l) = Exit (changeId f l)
changeId f (RuleStep env r) = RuleStep env (changeId f r)
instance Minor (Step a) where
setMinor b (RuleStep env r) = RuleStep env (setMinor b r)
setMinor _ st = st
isMinor (RuleStep _ r) = isMinor r
isMinor _ = True
stepRule :: Step a -> Rule a
stepRule (RuleStep _ r) = r
stepRule (Enter l) = idRule (l # "enter")
stepRule (Exit l) = idRule (l # "exit")
stepEnvironment :: Step a -> Environment
stepEnvironment (RuleStep env _) = env
stepEnvironment _ = mempty
newtype Path = Path [Int]
deriving Eq
instance Show Path where
show (Path is) = show is
emptyPath :: Path
emptyPath = Path []
readPath :: Monad m => String -> m Path
readPath = liftM Path . readM
readPaths :: Monad m => String -> m [Path]
readPaths = mapM readPath . splitsWithElem ';'