{-# LANGUAGE FlexibleInstances #-} module GLL.Combinators.Visit.Join where import GLL.Types.Derivations import GLL.Types.Grammar import GLL.Combinators.Visit.Sem import GLL.Combinators.Visit.Grammar import GLL.Combinators.Options import Control.Compose (OO(..),unOO) import Data.List (intercalate) import Data.Text (pack) -- | A combinator expression representing a symbol. -- A 'SymbExpr' either represents a terminal or a nonterminal. -- In the latter case it is constructed with (a variant of) '<:=>' and -- adds a rule to the grammar of which the represented symbol is the -- left-hand side. data SymbExpr t a = SymbExpr (Symbol t, Grammar_Expr t, Sem_Symb t a) -- | A combinator expression representing a BNF-grammar. The terminals of -- the grammar are of type 't'. When used to parse, the expression yields -- semantic results of type 'a'. type BNF t a = SymbExpr t a -- | -- A combinator expression representing an alternative: -- the right-hand side of a production. data AltExpr t a = AltExpr ([Symbol t], Grammar_Expr t, Sem_Alt t a) -- | A list of alternatives represents the right-hand side of a rule. type AltExprs = OO [] AltExpr mkNtRule :: (Show t, Ord t, HasAlts b) => Bool -> Bool -> String -> b t a -> SymbExpr t a mkNtRule use_ctx left_biased x' altPs' = let vas1 = map (\(AltExpr (f,_,_)) -> f) altPs vas2 = map (\(AltExpr (_,s,_)) -> s) altPs vas3 = map (\(AltExpr (_,_,t)) -> t) altPs alts = map (Prod x) vas1 altPs = altsOf altPs' x = pack x' in SymbExpr (Nt x, grammar_nterm x alts vas2, sem_nterm use_ctx left_biased x alts vas3) join_apply :: (Show t, Ord t, IsSymbExpr s) => (a -> b) -> s t a -> AltExpr t b join_apply f p' = let SymbExpr (vpa1,vpa2,vpa3) = mkRule p' in AltExpr ([vpa1],grammar_apply vpa2, sem_apply f vpa3) join_seq :: (Show t, Ord t, IsAltExpr i, IsSymbExpr s) => CombinatorOptions -> i t (a -> b) -> s t a -> AltExpr t b join_seq local_opts pl' pr' = let AltExpr (vimp1,vimp2,vimp3) = toAlt pl' SymbExpr (vpa1,vpa2,vpa3) = mkRule pr' in AltExpr (vimp1++[vpa1], grammar_seq vimp2 vpa2, sem_seq local_opts vimp3 vpa3) -- | -- Class for lifting to 'SymbExpr'. class IsSymbExpr a where toSymb :: (Show t, Ord t) => a t b -> SymbExpr t b -- | Synonym of 'toSymb' for creating /derived combinators/. mkRule :: (Show t, Ord t) => a t b -> BNF t b mkRule = toSymb instance IsSymbExpr AltExpr where toSymb = toSymb . OO . (:[]) instance IsSymbExpr SymbExpr where toSymb = id instance IsSymbExpr AltExprs where toSymb a = mkNtRule False False mkName a where mkName = "_" ++ "(" ++ intercalate "|" (map op (unOO a)) ++ ")" where op (AltExpr (rhs,_,_)) = "(" ++ intercalate "*" (map show rhs) ++ ")" -- | -- Class for lifting to 'AltExprs'. class HasAlts a where altsOf :: (Show t, Ord t) => a t b -> [AltExpr t b] instance HasAlts AltExpr where altsOf = (:[]) instance HasAlts SymbExpr where altsOf = altsOf . toAlt instance HasAlts AltExprs where altsOf = unOO -- | -- Class for lifting to 'AltExpr'. class IsAltExpr a where toAlt :: (Show t, Ord t) => a t b -> AltExpr t b instance IsAltExpr AltExpr where toAlt = id instance IsAltExpr SymbExpr where toAlt p = join_apply id p instance IsAltExpr AltExprs where toAlt = toAlt . mkRule