module MemDerive (
derive, Mem, newMem, validate
) where
import qualified Data.Map.Strict as M
import Control.Monad.State (State, runState, lift, state)
import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
import qualified Derive
import Smart (Grammar, Pattern, lookupRef, nullable, lookupMain)
import IfExprs
import Expr
import Zip
import Parsers
mem :: Ord k => (k -> v) -> k -> M.Map k v -> (v, M.Map k v)
mem f k m
| M.member k m = (m M.! k, m)
| otherwise = let res = f k
in (res, M.insert k res m)
type Calls = M.Map [Pattern] IfExprs
type Returns = M.Map ([Pattern], [Bool]) [Pattern]
newtype Mem = Mem (Calls, Returns)
newMem :: Mem
newMem = Mem (M.empty, M.empty)
calls :: Grammar -> [Pattern] -> State Mem IfExprs
calls g k = state $ \(Mem (c, r)) -> let (v', c') = mem (Derive.calls g) k c;
in (v', Mem (c', r))
returns :: Grammar -> ([Pattern], [Bool]) -> State Mem [Pattern]
returns g k = state $ \(Mem (c, r)) -> let (v', r') = mem (Derive.returns g) k r;
in (v', Mem (c, r'))
mderive :: Tree t => Grammar -> [Pattern] -> [t] -> ExceptT String (State Mem) [Pattern]
mderive _ ps [] = return ps
mderive g ps (tree:ts) = do {
ifs <- lift $ calls g ps;
childps <- hoistExcept $ evalIfExprs ifs (getLabel tree);
(zchildps, zipper) <- return $ zippy childps;
childres <- mderive g zchildps (getChildren tree);
let
nulls = map nullable childres
unzipns = unzipby zipper nulls
;
rs <- lift $ returns g (ps, unzipns);
mderive g rs ts
}
hoistExcept :: (Monad m) => Either e a -> ExceptT e m a
hoistExcept = ExceptT . return
derive :: Tree t => Grammar -> [t] -> Either String Pattern
derive g ts =
let start = [lookupMain g]
(res, _) = runState (runExceptT $ mderive g start ts) newMem
in case res of
(Left l) -> Left l
(Right [r]) -> return r
(Right rs) -> Left $ "not a single pattern: " ++ show rs
validate :: Tree t => Grammar -> Pattern -> [t] -> (State Mem) Bool
validate g start tree = do {
rs <- runExceptT (mderive g [start] tree);
return $ case rs of
(Right [r]) -> nullable r
_ -> False
}