{-# LANGUAGE AllowAmbiguousTypes #-} -- For grammar
{-# LANGUAGE ConstraintKinds #-} -- For Grammar
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(..)
  ) 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 Symantic.Univariant.Letable (Letable(..))

import Data.Function ((.))
import Data.String (String)
import Text.Show (Show(..))
import qualified Language.Haskell.TH.Syntax as TH

-- Class 'Grammar'
type Grammar tok repr =
  ( Applicable repr
  , Alternable repr
  , Satisfiable tok repr
  , Letable TH.Name repr
  , Selectable repr
  , Matchable repr
  , Foldable repr
  , Lookable repr
  )

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

-- | A usual pipeline to show 'Comb'inators:
-- 'observeSharing' then 'optimizeGrammar' then 'viewGrammar' then 'show'.
showGrammar :: ObserveSharing TH.Name (OptimizeGrammar TH.Name ViewGrammar) a -> String
showGrammar = show . viewGrammar . optimizeGrammar . observeSharing