module Language.Symantic.Grammar.EBNF where
import Control.Applicative (Applicative(..))
import Control.Monad
import Data.Semigroup hiding (option)
import Data.Text (Text)
import Prelude hiding (any)
import qualified Data.Text as Text
import Language.Symantic.Grammar.Meta
import Language.Symantic.Grammar.Fixity
newtype EBNF a = EBNF { unEBNF :: RuleMode -> (Infix, Side) -> Text }
instance Gram_Reader st EBNF where
askBefore (EBNF e) = EBNF e
askAfter (EBNF e) = EBNF e
instance Gram_State st EBNF where
stateBefore (EBNF e) = EBNF e
stateAfter (EBNF e) = EBNF e
instance Gram_Error err EBNF where
catch (EBNF e) = EBNF e
runEBNF :: EBNF a -> Text
runEBNF (EBNF g) = g RuleMode_Body (infixN0, SideL)
renderEBNF :: RuleEBNF a -> Text
renderEBNF = runEBNF . unRuleEBNF
ebnf_const :: Text -> EBNF a
ebnf_const t = EBNF $ \_rm _op -> t
ebnf_arg :: EBNF a -> EBNF b -> EBNF ()
ebnf_arg (EBNF a) (EBNF b) = EBNF $ \bo po -> parenInfix po op $
a bo (op, SideL) <> " " <> b bo (op, SideR)
where op = infixL 11
infixl 5 `ebnf_arg`
data RuleMode
= RuleMode_Body
| RuleMode_Ref
deriving (Eq, Show)
type Rule a = a -> a
class Gram_Rule g where
rule :: Text -> Rule (g a)
rule _n = id
rule1 :: Text -> Rule (g a -> g b)
rule1 _n g = g
rule2 :: Text -> Rule (g a -> g b -> g c)
rule2 _n g = g
rule3 :: Text -> Rule (g a -> g b -> g c -> g d)
rule3 _n g = g
rule4 :: Text -> Rule (g a -> g b -> g c -> g d -> g e)
rule4 _n g = g
newtype RuleEBNF a = RuleEBNF { unRuleEBNF :: EBNF a }
deriving (Functor, Applicative)
deriving instance Gram_RuleEBNF RuleEBNF
deriving instance Gram_Error err RuleEBNF
deriving instance Gram_Reader st RuleEBNF
deriving instance Gram_State st RuleEBNF
instance Gram_Rule RuleEBNF where
rule n = ruleEBNF (ebnf_const n)
rule1 n g a = ruleEBNF (ebnf_const n `ebnf_arg` unRuleEBNF a) (g a)
rule2 n g a b = ruleEBNF (ebnf_const n `ebnf_arg` unRuleEBNF a `ebnf_arg` unRuleEBNF b) (g a b)
rule3 n g a b c = ruleEBNF (ebnf_const n `ebnf_arg` unRuleEBNF a `ebnf_arg` unRuleEBNF b `ebnf_arg` unRuleEBNF c) (g a b c)
rule4 n g a b c d = ruleEBNF (ebnf_const n `ebnf_arg` unRuleEBNF a `ebnf_arg` unRuleEBNF b `ebnf_arg` unRuleEBNF c `ebnf_arg` unRuleEBNF d) (g a b c d)
class Gram_RuleEBNF g where
ruleEBNF :: EBNF () -> g a -> RuleEBNF a
argEBNF :: Text -> g a
instance Show (EBNF a) where
show = Text.unpack . runEBNF
instance Functor EBNF where
fmap _f (EBNF x) = EBNF x
instance Applicative EBNF where
pure _ = ebnf_const $ "\"\""
EBNF f <*> EBNF x = EBNF $ \bo po -> parenInfix po op $
f bo (op, SideL) <> ", " <> x bo (op, SideR)
where op = infixB SideL 10
instance Gram_Rule EBNF where
rule n g = EBNF $ \rm po ->
case rm of
RuleMode_Body -> unEBNF g RuleMode_Ref po
RuleMode_Ref -> n
rule1 n g a = EBNF $ \rm po ->
case rm of
RuleMode_Body -> unEBNF (g a) RuleMode_Ref po
RuleMode_Ref -> unEBNF (ebnf_const n `ebnf_arg` a) RuleMode_Ref po
rule2 n g a b = EBNF $ \rm po ->
case rm of
RuleMode_Body -> unEBNF (g a b) RuleMode_Ref po
RuleMode_Ref -> unEBNF (ebnf_const n `ebnf_arg` a `ebnf_arg` b) RuleMode_Ref po
rule3 n g a b c = EBNF $ \rm po ->
case rm of
RuleMode_Body -> unEBNF (g a b c) RuleMode_Ref po
RuleMode_Ref -> unEBNF (ebnf_const n `ebnf_arg` a `ebnf_arg` b `ebnf_arg` c) RuleMode_Ref po
rule4 n g a b c d = EBNF $ \rm po ->
case rm of
RuleMode_Body -> unEBNF (g a b c d) RuleMode_Ref po
RuleMode_Ref -> unEBNF (ebnf_const n `ebnf_arg` a `ebnf_arg` b `ebnf_arg` c `ebnf_arg` d) RuleMode_Ref po
instance Gram_RuleEBNF EBNF where
argEBNF = ebnf_const
ruleEBNF call body =
RuleEBNF $ EBNF $ \mo po ->
case mo of
RuleMode_Ref -> unEBNF call mo po
RuleMode_Body ->
Text.intercalate " "
[ unEBNF call RuleMode_Ref (infixN0, SideL)
, "="
, unEBNF body RuleMode_Ref (infixN0, SideR)
, ";"
]