{-# LANGUAGE ScopedTypeVariables, FlexibleInstances, MultiParamTypeClasses
, DeriveGeneric, DeriveAnyClass, TypeFamilies, FlexibleContexts
, StandaloneDeriving, OverloadedStrings, DeriveDataTypeable #-}
module Text.ANTLR.Grammar
(
Grammar(..)
, ProdElem(..), ProdElems
, Production(..), ProdRHS(..), StateFncn(..)
, Predicate(..), Mutator(..), Ref(..)
, getRHS, getLHS
, isSem, isAction
, sameNTs, sameTs
, isNT, isT, isEps, getNTs, getTs, getEps
, prodsFor, getProds
, validGrammar, hasAllNonTerms, hasAllTerms, startIsNonTerm
, symbols, defaultGrammar
) where
import Prelude hiding (pi)
import Data.List (nub, sort)
import System.IO.Unsafe (unsafePerformIO)
import qualified Debug.Trace as D
import Data.Data (Data(..), Typeable(..))
import Language.Haskell.TH.Lift (Lift(..))
import qualified Text.ANTLR.Set as S
import Text.ANTLR.Set
( Set(..), empty, fromList, member, union
, Hashable(..), Generic(..)
)
import Text.ANTLR.Pretty
uPIO :: IO a -> a
uPIO = unsafePerformIO
class Ref v where
type Sym v :: *
getSymbol :: v -> Sym v
compareSymbols :: (Ref ref, Eq (Sym ref)) => ref -> ref -> Bool
compareSymbols a b = getSymbol a == getSymbol b
sameNTs :: forall nt. (Ref nt, Eq (Sym nt)) => nt -> nt -> Bool
sameNTs = compareSymbols
sameTs :: forall t. (Ref t, Eq (Sym t)) => t -> t -> Bool
sameTs = compareSymbols
instance Ref String where
type Sym String = String
getSymbol = id
instance Ref (String, b) where
type Sym (String, b) = String
getSymbol = fst
data ProdElem nts ts =
NT nts
| T ts
| Eps
deriving (Eq, Ord, Generic, Hashable, Show, Data, Lift)
instance (Prettify nts, Prettify ts) => Prettify (ProdElem nts ts) where
prettify (NT nts) = prettify nts
prettify (T ts) = prettify ts
prettify Eps = pStr "ε"
isNT (NT _) = True
isNT _ = False
isT (T _) = True
isT _ = False
isEps Eps = True
isEps _ = False
getNTs = map (\(NT nt) -> nt) . filter isNT
getTs = map (\(T t) -> t) . filter isT
getEps = map (\Eps -> Eps) . filter isEps
type ProdElems nts ts = [ProdElem nts ts]
data StateFncn s =
Pass
| Sem (Predicate ())
| Action (Mutator ())
deriving (Eq, Ord, Generic, Hashable, Show, Data, Lift)
instance Prettify (StateFncn s) where
prettify Pass = return ()
prettify (Sem p) = prettify p
prettify (Action a) = prettify a
data ProdRHS s nts ts = Prod (StateFncn s) (ProdElems nts ts)
deriving (Eq, Ord, Generic, Hashable, Show, Data, Lift)
instance (Prettify s, Prettify nts, Prettify ts) => Prettify (ProdRHS s nts ts) where
prettify (Prod sf ps) = do
prettify sf
prettify ps
isSem (Prod (Sem _) _) = True
isSem _ = False
isAction (Prod (Action _) _) = True
isAction _ = False
getProds = map (\(Prod _ ss) -> ss)
data Production s nts ts = Production nts (ProdRHS s nts ts)
deriving (Eq, Ord, Generic, Hashable, Data, Lift)
instance (Prettify s, Prettify nts, Prettify ts) => Prettify (Production s nts ts) where
prettify (Production nts (Prod sf ps)) = do
len <- pCount nts
incrIndent (len + 4)
pStr " -> "
prettify sf
prettify ps
incrIndent (-4)
instance (Show s, Show nts, Show ts) => Show (Production s nts ts) where
show (Production nts rhs) = show nts ++ " -> " ++ show rhs
getRHS :: Production s nts ts -> ProdRHS s nts ts
getRHS (Production lhs rhs) = rhs
getLHS :: Production s nts ts -> nts
getLHS (Production lhs rhs) = lhs
prodsFor :: forall s nts ts. (Eq nts) => Grammar s nts ts -> nts -> [Production s nts ts]
prodsFor g nts = let
matchesNT :: Production s nts t -> Bool
matchesNT (Production nts' _) = nts' == nts
in filter matchesNT (ps g)
data Predicate p = Predicate String p
deriving (Data)
instance (Data s, Typeable s) => Lift (Predicate s)
instance (Data s, Typeable s) => Lift (Mutator s)
instance Eq (Predicate s) where
Predicate p1 _ == Predicate p2 _ = p1 == p2
instance Ord (Predicate s) where
Predicate p1 _ `compare` Predicate p2 _ = p1 `compare` p2
instance Show (Predicate s) where
show (Predicate p1 _) = "π(" ++ show p1 ++ ")"
instance Hashable (Predicate s) where
hashWithSalt salt (Predicate p1 _) = salt `hashWithSalt` p1
instance Prettify (Predicate s) where
prettify (Predicate n _) = pStr' n
instance Prettify (Mutator s) where
prettify (Mutator n _) = pStr' n
data Mutator s = Mutator String ()
deriving (Data)
instance Eq (Mutator s) where
Mutator m1 _ == Mutator m2 _ = m1 == m2
instance Ord (Mutator s) where
Mutator m1 _ `compare` Mutator m2 _ = m1 `compare` m2
instance Show (Mutator s) where
show (Mutator m1 _) = "µ(" ++ show m1 ++ ")"
instance Hashable (Mutator s) where
hashWithSalt salt (Mutator m1 _) = salt `hashWithSalt` m1
data Grammar s nts ts = G
{ ns :: Set nts
, ts :: Set ts
, ps :: [Production s nts ts]
, s0 :: nts
, _πs :: Set (Predicate s)
, _μs :: Set (Mutator s)
} deriving (Show, Lift)
instance (Eq s, Eq nts, Eq ts, Hashable nts, Hashable ts, Prettify s, Prettify nts, Prettify ts)
=> Eq (Grammar s nts ts) where
g1 == g2 = ns g1 == ns g2
&& ts g1 == ts g2
&& eqLists (nub $ ps g1) (nub $ ps g2)
&& s0 g1 == s0 g2
&& _πs g1 == _πs g2
&& _μs g1 == _μs g2
eqLists [] [] = True
eqLists [] vs = False
eqLists vs [] = False
eqLists (v1:vs) vs2 = eqLists vs (filter (/= v1) vs2)
instance (Prettify s, Prettify nts, Prettify ts, Hashable ts, Eq ts, Hashable nts, Eq nts, Ord ts, Ord nts)
=> Prettify (Grammar s nts ts) where
prettify G {ns = ns, ts = ts, ps = ps, s0 = s0, _πs = _πs, _μs = _μs} = do
pLine "Grammar:"
pStr "{ "
incrIndent 2
pStr " ns = " ; prettify ns; pLine ""
pStr ", ts = " ; prettify ts; pLine ""
pStr ", ps = " ; pListLines $ sort ps; pLine ""
pStr ", s0 = " ; prettify s0; pLine ""
pStr ", _πs = " ; prettify _πs ; pLine ""
pStr ", _μs = " ; prettify _μs ; pLine ""
incrIndent (-2)
pStr "}"
symbols
:: (Ord nts, Ord ts, Hashable s, Hashable nts, Hashable ts)
=> Grammar s nts ts -> Set (ProdElem nts ts)
symbols g = S.insert Eps $ S.map NT (ns g) `union` S.map T (ts g)
defaultGrammar
:: forall s nts ts. (Ord ts, Hashable ts, Hashable nts, Eq nts)
=> nts -> Grammar s nts ts
defaultGrammar start = G
{ ns = S.singleton start
, ts = empty
, ps = []
, _πs = empty
, _μs = empty
, s0 = start
}
validGrammar
:: forall s nts ts.
(Eq nts, Ord nts, Eq ts, Ord ts, Hashable nts, Hashable ts)
=> Grammar s nts ts -> Bool
validGrammar g =
hasAllNonTerms g
&& hasAllTerms g
&& startIsNonTerm g
hasAllNonTerms
:: (Eq nts, Ord nts, Hashable nts, Hashable ts)
=> Grammar s nts ts -> Bool
hasAllNonTerms g =
ns g == (fromList . getNTs . concat . getProds . map getRHS $ ps g)
hasAllTerms
:: (Eq ts, Ord ts, Hashable nts, Hashable ts)
=> Grammar s nts ts -> Bool
hasAllTerms g =
ts g == (fromList . getTs . concat . getProds . map getRHS $ ps g)
startIsNonTerm
:: (Ord nts, Hashable nts)
=> Grammar s nts ts -> Bool
startIsNonTerm g = s0 g `member` ns g