packages feed

ottparse-pretty-0.1.2.3: src/Text/Ott/Pretty.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Text.Ott.Pretty
-- Copyright   :  (c) Brent Yorgey 2011
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  Brent Yorgey <byorgey@cis.upenn.edu>
-- Stability   :  experimental
--
-- Ott (<http://www.cl.cam.ac.uk/~pes20/ott/>) is a tool for writing
-- formal definitions of programming languages and calculi.  Often the
-- Ott grammars one defines end up being ambiguous, and Ott signals
-- its displeasure by spewing forth several massive parse trees in a
-- format requiring formidable patience to read.  Finding the slight
-- differences between two such parse trees is an exercise in
-- seizure-inducing tedium.
--
-- To the rescue comes ottparse-pretty!  Simply paste in each parse
-- and it is shown to you in a nicely formatted tree form with all the
-- extra meaningless cruft removed.
--
-- This module implements the internals of the tool: a simple parser
-- and a set of tree transformations.
-----------------------------------------------------------------------------
module Text.Ott.Pretty where

import Text.Parsec
import Control.Applicative ((<$>), (<*>), (*>), (<*), pure)

import Data.Tree
import Data.List.Split

import Data.Generics.Uniplate.Data


type Parser a = Parsec String () a

type T = Tree String

-- | Parse a string dump of an Ott parse tree.
parseTree :: Parser T
parseTree = char '(' *> parseApp <* char ')' <* spaces
        <|> Node <$> parseId <*> pure [] <* spaces

-- | Parse an application, i.e. a parent node with one or more children.
parseApp :: Parser T
parseApp = Node <$> parseId <*> many1 parseTree

-- | Parse an identifier.
parseId :: Parser String
parseId = spaces *> many1 (alphaNum <|> char '_' <|> char ':' <|> char '\'') <* spaces

-- | \"Normalize\" a parse tree by deleting meaningless cruft.
normalizeTree :: T -> T
normalizeTree = transformBis [ [ transformer stripColonNames ]
                             , [ transformer deleteSteSt ]
                             , [ transformer deleteNonterm ]
                             , [ transformer replaceStNode ]
                             ]

deleteSteSt :: T -> T
deleteSteSt (Node "Ste_st" [c]) = c
deleteSteSt t = t

deleteNonterm :: T -> T
deleteNonterm (Node "St_nonterm" [n@(Node _ [])]) = n
deleteNonterm t = t

replaceStNode :: T -> T
replaceStNode (Node "St_node" (Node name [] : cs)) = Node name cs
replaceStNode t = t

stripColonNames :: T -> T
stripColonNames (Node s cs) =
  case split (dropDelims . dropBlanks $ onSublist ":") s of
    [_,n] -> Node n cs
    _     -> Node s cs