module DepTrack.Parsing (
dependencies
) where
import Control.Applicative ((<|>))
import Data.Tree (Forest, Tree (..))
import Text.Parsec (ParsecT, (<?>))
import qualified Text.Parsec as Parsec
import Text.Parsec.Prim (tokenPrim)
import DepTrack.DepCrumb
dependencies :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (Forest a)
dependencies = forest <* Parsec.eof
forest :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (Forest a)
forest = fmap concat $ Parsec.many (simpleForest <|> spade <?> "forest")
simpleForest :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (Forest a)
simpleForest = Parsec.many1 tree <?> "simple-forest"
spade :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (Forest a)
spade = merge <$> (spadeIn *> forest <* spadeMiddle) <*> (forest <* spadeOut)
where merge :: Forest a -> Forest a -> Forest a
merge [] children = children
merge parents children = fmap (appendChildren children) parents
appendChildren :: Forest a -> Tree a -> Tree a
appendChildren zs (Node x ys) = Node x (ys ++ zs)
tree :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (Tree a)
tree = Parsec.try leaf
<|> Parsec.try parent
<?> "tree"
parent :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (Tree a)
parent = f <$> (push *> forest) <*> pop <?> "parent"
where f xs popx = Node (unsafeFromPop popx) xs
leaf :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (Tree a)
leaf = pure . unsafeFromPop <$> (push *> pop) <?> "leaf"
push :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (DepCrumb a)
push = satisfy isPush <?> "Push"
pop :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (DepCrumb a)
pop = satisfy isPop <?> "Pop"
spadeIn :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (DepCrumb a)
spadeIn = satisfy isSpadeIn <?> "SpadeIn"
spadeMiddle :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (DepCrumb a)
spadeMiddle = satisfy isSpadeMiddle <?> "SpadeMiddle"
spadeOut :: (Monad m, Show a) => ParsecT [DepCrumb a] () m (DepCrumb a)
spadeOut = satisfy isSpadeOut <?> "SpadeOut"
isPop,isPush,isSpadeIn,isSpadeMiddle,isSpadeOut :: DepCrumb a -> Bool
isPop (Pop _) = True
isPop _ = False
isPush (Push) = True
isPush _ = False
isSpadeIn SpadeIn = True
isSpadeIn _ = False
isSpadeMiddle SpadeMiddle = True
isSpadeMiddle _ = False
isSpadeOut SpadeOut = True
isSpadeOut _ = False
unsafeFromPop :: DepCrumb a -> a
unsafeFromPop (Pop x) = x
unsafeFromPop _ = error "partial function, not a Pop"
satisfy :: (Monad m, Show a) => (DepCrumb a -> Bool) -> ParsecT [DepCrumb a] () m (DepCrumb a)
satisfy f = tokenPrim showDepCrumb nextPos testDepCrumb
where showDepCrumb = show
testDepCrumb x = if f x then Just x else Nothing
nextPos pos _ _ = Parsec.incSourceColumn pos 1