grammar-combinators-0.2: Text/GrammarCombinators/Utils/PrintGrammar.hs
{- Copyright 2010 Dominique Devriese
This file is part of the grammar-combinators library.
The grammar-combinators library is free software: you can
redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at
your option) any later version.
Foobar is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with Foobar. If not, see
<http://www.gnu.org/licenses/>.
-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Text.GrammarCombinators.Utils.PrintGrammar (
printRule,
printGrammar,
printGrammarInf,
printReachableGrammar
) where
import Text.GrammarCombinators.Base
import Text.GrammarCombinators.Utils.IsReachable
newtype PrintProductionRule (phi :: * -> *) (r :: * -> *) t v = IPP {
printIPP :: Bool -> Bool -> Integer -> String
}
printIPPSub :: Integer -> Bool -> Bool -> PrintProductionRule phi r t v -> String
printIPPSub d pd pc pp = if d > 0 then printIPP pp pd pc (d-1) else "..."
instance ProductionRule (PrintProductionRule phi r t) where
die = IPP $ \_ _ _ -> "die"
endOfInput = IPP $ \_ _ _ -> "EOI"
a ||| b = IPP $ \pd _ d ->
let t = printIPPSub d False True a ++ " | " ++ printIPPSub d False True b
in if pd then "(" ++ t ++ ")" else t
a >>> b = IPP $ \pd pc d ->
if printIPPSub d pd pc a == "epsilon"
then printIPPSub d pd pc b
else if printIPPSub d pd pc b == "epsilon"
then printIPPSub d pd pc a
else let t = printIPPSub d True False a ++ " " ++ printIPPSub d True False b
in if pc then "(" ++ t ++ ")" else t
instance BiasedProductionRule (PrintProductionRule phi r t) where
a >||| b = IPP $ \pd _ d ->
let t = printIPPSub d False True a ++ " >| " ++ printIPPSub d False True b
in if pd then "(" ++ t ++ ")" else t
a <||| b = IPP $ \pd _ d ->
let t = printIPPSub d False True a ++ " <| " ++ printIPPSub d False True b
in if pd then "(" ++ t ++ ")" else t
instance EpsProductionRule (PrintProductionRule phi r t) where
epsilon _ = IPP $ \_ _ _ -> "epsilon"
instance PenaltyProductionRule (PrintProductionRule phi r t) where
penalty p r = IPP $ \_ _ d -> "penalty " ++ show p ++ " ( " ++ printIPPSub d False False r ++ " )"
instance LiftableProductionRule (PrintProductionRule phi r t) where
epsilonL _ _ = IPP $ \_ _ _ -> "epsilon"
instance (Token t) => TokenProductionRule (PrintProductionRule phi r t) t where
token t = IPP $ \_ _ _ -> show t
anyToken = IPP $ \_ _ _ -> "anyToken"
instance (ShowFam phi) => RecProductionRule (PrintProductionRule phi r t) phi r where
ref idx = IPP $ \_ _ _ -> "<" ++ showIdx idx ++ ">"
instance (ShowFam phi) => LoopProductionRule (PrintProductionRule phi r t) phi r where
manyRef idx = IPP $ \_ _ _ -> "<" ++ showIdx idx ++ ">" ++ "*"
many1Ref idx = IPP $ \_ _ _ -> "<" ++ showIdx idx ++ ">" ++ "+"
-- | Print out a single production rule
printRule :: (Domain phi, Token t) => GAnyExtendedContextFreeGrammar phi t r rr -> Integer -> phi ix -> String
printRule gram depth idx = "<" ++ showIdx idx ++ ">" ++ " ::= " ++ printIPP (gram idx) False False depth
printGrammar' :: forall phi t r rr. (Domain phi, Token t) =>
(forall b. (forall ix. phi ix -> b -> b) -> b -> b) ->
GAnyExtendedContextFreeGrammar phi t r rr -> Integer -> String
printGrammar' fold' gram depth =
unlines $ fold' ((:) . printRule gram depth) []
-- close enough...
infinity :: Integer
infinity = 999999999999999999999999999999
-- | Print out a full grammar.
printGrammar :: forall phi t r rr. (Domain phi, Token t) =>
GAnyExtendedContextFreeGrammar phi t r rr -> String
printGrammar g = printGrammar' foldFam g infinity
-- | Print out a grammar with a depth limit. Intended for infinite grammars.
printGrammarInf :: forall phi t r rr. (Domain phi, Token t) =>
GAnyExtendedContextFreeGrammar phi t r rr -> Integer -> String
printGrammarInf = printGrammar' foldFam
-- | Print out the part of a grammar that is reachable from a given non-terminal.
printReachableGrammar ::
forall phi t r rr ix.
(Domain phi, Token t) =>
GAnyExtendedContextFreeGrammar phi t r rr ->
phi ix -> String
printReachableGrammar gram idx = printGrammar' (foldReachable gram idx) gram infinity