module Data.Katydid.Relapse.VpaDerive
( derive
)
where
import qualified Data.Map.Strict as M
import Control.Monad.State ( State
, runState
, state
, lift
)
import Data.Foldable ( foldlM )
import Control.Monad.Trans.Except ( ExceptT(..)
, runExceptT
)
import Data.Katydid.Parser.Parser
import qualified Data.Katydid.Relapse.Derive as Derive
import Data.Katydid.Relapse.Smart ( Grammar
, Pattern
)
import qualified Data.Katydid.Relapse.Smart as Smart
import Data.Katydid.Relapse.IfExprs
import Data.Katydid.Relapse.Expr
import Data.Katydid.Relapse.Zip
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 VpaState = [Pattern]
type StackElm = ([Pattern], Zipper)
type Calls = M.Map VpaState ZippedIfExprs
type Nullable = M.Map [Pattern] [Bool]
type Returns = M.Map ([Pattern], Zipper, [Bool]) [Pattern]
newtype Vpa = Vpa (Nullable, Calls, Returns, Grammar)
newVpa :: Grammar -> Vpa
newVpa g = Vpa (M.empty, M.empty, M.empty, g)
nullable :: [Pattern] -> State Vpa [Bool]
nullable key = state $ \(Vpa (n, c, r, g)) ->
let (v', n') = mem (map Smart.nullable) key n in (v', Vpa (n', c, r, g))
calls :: [Pattern] -> State Vpa ZippedIfExprs
calls key = state $ \(Vpa (n, c, r, g)) ->
let (v', c') = mem (zipIfExprs . Derive.calls g) key c
in (v', Vpa (n, c', r, g))
vpacall :: VpaState -> Label -> ExceptT String (State Vpa) (StackElm, VpaState)
vpacall vpastate label = do
zifexprs <- lift $ calls vpastate
(nextstate, zipper) <- hoistExcept $ evalZippedIfExprs zifexprs label
let stackelm = (vpastate, zipper)
return (stackelm, nextstate)
hoistExcept :: (Monad m) => Either e a -> ExceptT e m a
hoistExcept = ExceptT . return
returns :: ([Pattern], Zipper, [Bool]) -> State Vpa [Pattern]
returns key = state $ \(Vpa (n, c, r, g)) ->
let (v', r') = mem
(\(ps, zipper, znulls) -> Derive.returns g (ps, unzipby zipper znulls))
key
r
in (v', Vpa (n, c, r', g))
vpareturn :: StackElm -> VpaState -> State Vpa VpaState
vpareturn (vpastate, zipper) current = do
zipnulls <- nullable current
returns (vpastate, zipper, zipnulls)
deriv :: Tree t => VpaState -> t -> ExceptT String (State Vpa) VpaState
deriv current tree = do
(stackelm, nextstate) <- vpacall current (getLabel tree)
resstate <- foldlM deriv nextstate (getChildren tree)
lift $ vpareturn stackelm resstate
foldLT :: Tree t => Vpa -> VpaState -> [t] -> Either String [Pattern]
foldLT _ current [] = return current
foldLT m current (t : ts) =
let (newstate, newm) = runState (runExceptT $ deriv current t) m
in case newstate of
(Left l) -> Left l
(Right r) -> foldLT newm r ts
derive :: Tree t => Grammar -> [t] -> Either String Pattern
derive g ts =
let start = [Smart.lookupMain g]
in case foldLT (newVpa g) start ts of
(Left l ) -> Left $ show l
(Right [r]) -> return r
(Right rs ) -> Left $ "Number of patterns is not one, but " ++ show rs