{-# LANGUAGE AllowAmbiguousTypes #-} -- For grammar
{-# LANGUAGE ConstraintKinds #-} -- For Grammarable
module Symantic.Parser.Grammar
  ( module Symantic.Parser.Grammar
  , module Symantic.Parser.Grammar.Combinators
  , module Symantic.Parser.Grammar.Fixity
  , module Symantic.Parser.Grammar.Optimize
  , module Symantic.Parser.Grammar.ObserveSharing
  , module Symantic.Parser.Grammar.Write
  , module Symantic.Parser.Grammar.View
  , Letable(..)
  , Letsable(..)
  ) where
import Symantic.Parser.Grammar.Combinators
import Symantic.Parser.Grammar.View
import Symantic.Parser.Grammar.Fixity
import Symantic.Parser.Grammar.ObserveSharing
import Symantic.Parser.Grammar.Optimize
import Symantic.Parser.Grammar.Write

import Control.DeepSeq (NFData)
import Data.Eq (Eq(..))
import Data.Function ((.))
import Data.String (String)
import Data.Typeable (Typeable)
import Text.Show (Show(..))
import qualified Language.Haskell.TH.Syntax as TH

-- * Class 'Grammarable'
type Grammarable tok repr =
  ( CombAlternable repr
  , CombApplicable repr
  , CombFoldable repr
  , Letable TH.Name repr
  , Letsable TH.Name repr
  , CombLookable repr
  , CombMatchable repr
  , CombSatisfiable tok repr
  , CombSelectable repr
  , Eq tok
  , TH.Lift tok
  , NFData tok
  , Show tok
  , Typeable tok
  )

-- | A usual pipeline to interpret 'Comb'inators:
-- 'observeSharing' then 'optimizeGrammar' then a polymorphic @(repr)@.
grammar ::
  Grammarable tok repr =>
  ObserveSharing TH.Name
    (OptimizeGrammar repr) a ->
  repr a
grammar = optimizeGrammar . observeSharing

-- | An usual pipeline to show 'Comb'inators:
-- 'observeSharing' then 'optimizeGrammar' then 'viewGrammar' then 'show'.
showGrammar :: forall showName a tok repr.
  repr ~ ObserveSharing TH.Name (OptimizeGrammar (ViewGrammar showName)) =>
  ShowLetName showName TH.Name =>
  Grammarable tok repr =>
  repr a -> String
showGrammar = show . viewGrammar . grammar @tok