GrammarProducts-0.0.0.2: FormalLanguage/GrammarProduct/Op/Add.hs
{-# LANGUAGE FlexibleInstances #-}
module FormalLanguage.GrammarProduct.Op.Add where
import Control.Lens
import Control.Lens.Fold
import Control.Newtype
import Data.List (genericReplicate)
import Data.Monoid hiding ((<>))
import Data.Semigroup
import qualified Data.Set as S
import Text.Printf
import FormalLanguage.CFG.Grammar
-- | Add two grammars. Implemented as the union of production rules without any
-- renaming.
newtype Add a = Add {runAdd :: a}
-- | Note that the semigroup on Add will create a new rule S_gh -> S_g | S_h in
-- case two start symbols with different rhs exist (If S_g, S_h are the same,
-- there is no problem).
instance Semigroup (Add Grammar) where
(Add l) <> (Add r)
| gDim l /= gDim r
= error $ printf "ERROR: grammars \n%s\n and \n%s\n have different dimensions, cannot unify. (add %d %d)"
(show l)
(show r)
(gDim l)
(gDim r)
| otherwise = Add $ Grammar (l^.tsyms <> r^.tsyms)
(l^.nsyms <> r^.nsyms) -- TODO add the newly created symbol to the non-terminals (or maybe just run ``fix T+N 's from the rules?'')
(l^.epsis <> r^.epsis)
(l^.rules <> r^.rules <> t)
s
(l^.name <> r^.name)
where s = case (l^.start,r^.start) of
(Nothing, Nothing) -> Nothing
(Nothing, Just k ) -> Just k
(Just k , Nothing) -> Just k
(Just k , Just l ) -> if k==l then Just k else error "need to create new symbol, see note on Semigroup (Add Grammar)"
t = case (l^.start,r^.start) of
(Just k , Just l ) -> if k==l then S.empty else error "this will create the new rule"
_ -> S.empty
--(if l^.start == r^.start
-- then l^.start
-- else error "maybe add another rule and a unique start symbol?")
instance Monoid (Add Grammar) where
mempty = Add $ Grammar S.empty S.empty S.empty S.empty Nothing ""
mappend = (<>)
-- idempotency is not made explicit here