module Language.Symantic.Grammar.ContextFree where
import Control.Applicative (Applicative(..))
import Control.Monad
import Data.Semigroup (Semigroup(..))
import Data.String (IsString(..))
import Prelude hiding (any)
import qualified Data.List as L
import Language.Symantic.Grammar.Meta
import Language.Symantic.Grammar.Fixity
import Language.Symantic.Grammar.EBNF
import Language.Symantic.Grammar.Terminal
import Language.Symantic.Grammar.Regular
newtype CF g a = CF { unCF :: g a }
deriving (IsString, Functor, Gram_Terminal, Applicative, Gram_App)
deriving instance Gram_Error err g => Gram_Error err (CF g)
deriving instance Gram_Reader st g => Gram_Reader st (CF g)
deriving instance Gram_State st g => Gram_State st (CF g)
deriving instance Gram_Alt g => Gram_Alt (CF g)
deriving instance Gram_Try g => Gram_Try (CF g)
deriving instance Gram_AltApp g => Gram_AltApp (CF g)
deriving instance Gram_Rule g => Gram_Rule (CF g)
deriving instance Gram_RegL g => Gram_RegL (CF g)
deriving instance Gram_RegR g => Gram_RegR (CF g)
deriving instance Gram_CF g => Gram_CF (CF g)
deriving instance Gram_CF RuleEBNF
deriving instance Gram_RuleEBNF g => Gram_RuleEBNF (CF g)
instance Gram_CF EBNF where
CF (EBNF f) <& Reg (EBNF g) =
CF $ EBNF $ \bo po -> parenInfix po op $
f bo (op, SideL) <> " & " <> g bo (op, SideR)
where op = infixB SideL 4
Reg (EBNF f) &> CF (EBNF g) =
CF $ EBNF $ \bo po -> parenInfix po op $
f bo (op, SideL) <> " & " <> g bo (op, SideR)
where op = infixB SideL 4
CF (EBNF f) `minus` Reg (EBNF g) =
CF $ EBNF $ \bo po -> parenInfix po op $
f bo (op, SideL) <> " - " <> g bo (op, SideR)
where op = infixL 6
class ContextFreeOf gram where
cfOf :: gram g a -> CF g a
instance ContextFreeOf Terminal where
cfOf (Terminal g) = CF g
instance ContextFreeOf (Reg lr) where
cfOf (Reg g) = CF g
class Gram_CF g where
(<&) :: CF g (a -> b) -> Reg lr g a -> CF g b
infixl 4 <&
(&>) :: Reg lr g (a -> b) -> CF g a -> CF g b
infixl 4 &>
minus :: CF g a -> Reg lr g b -> CF g a
class Applicative g => Gram_App g where
between :: g open -> g close -> g a -> g a
between open close g = open *> g <* close
deriving instance Gram_App RuleEBNF
instance Gram_App EBNF
class (Gram_Alt g, Gram_App g) => Gram_AltApp g where
option :: a -> g a -> g a
option x g = g <+> pure x
optional :: g a -> g (Maybe a)
optional v = Just <$> v <+> pure Nothing
manyFoldL :: b -> (a -> b -> b) -> g a -> g b
manyFoldL e f a = someFoldL e f a <+> pure e
someFoldL :: b -> (a -> b -> b) -> g a -> g b
someFoldL e f a = f <$> a <*> manyFoldL e f a
many :: g a -> g [a]
many = fmap L.reverse . manyFoldL [] (:)
some :: g a -> g [a]
some = fmap L.reverse . someFoldL [] (:)
manySkip :: g a -> g ()
manySkip = void . many
someSkip :: g a -> g ()
someSkip = void . some
inside
:: (in_ -> next)
-> CF g begin
-> CF g in_
-> CF g end
-> CF g next
-> CF g next
inside f begin in_ end next =
(f <$ begin <*> in_ <* end) <+> next
deriving instance Gram_AltApp RuleEBNF
instance Gram_AltApp EBNF where
manyFoldL _ _ (EBNF g) = EBNF $ \rm _po -> "{" <> g rm (op, SideL) <> "}" where op = infixN0
someFoldL _ _ (EBNF g) = EBNF $ \rm _po -> "{" <> g rm (op, SideL) <> "}-" where op = infixN0
option _x (EBNF g) = EBNF $ \rm _po ->
"[" <> g rm (op, SideL) <> "]" where op = infixN0
class
( Gram_Terminal g
, Gram_Rule g
, Gram_Alt g
, Gram_App g
, Gram_AltApp g
, Gram_CF g
) => Gram_Comment g where
commentable :: g () -> g () -> g () -> g ()
commentable = rule3 "commentable" $ \space line block ->
manySkip $ choice [space, line, block]
comment_line :: CF g String -> CF g String
comment_line prefix = rule "comment_line" $
prefix *> many (any `minus` (void (char '\n') <+> eoi))
comment_block :: CF g String -> Reg lr g String -> CF g String
comment_block begin end = rule "comment_block" $
begin *> many (any `minus` end) <* cfOf end
lexeme :: CF g a -> CF g a
lexeme = rule1 "lexeme" $ \g ->
g <* commentable
(void $ string " " <+> string "\n ")
(void $ comment_line (string "--"))
(void $ comment_block (string "{-") (string "-}"))
parens :: CF g a -> CF g a
parens = rule1 "parens" $
between
(lexeme $ char '(')
(lexeme $ char ')')
symbol :: String -> CF g String
symbol = lexeme . string
deriving instance Gram_Comment g => Gram_Comment (CF g)
instance Gram_Comment RuleEBNF
instance Gram_Comment EBNF
gram_comment :: forall g. (Gram_Comment g, Gram_RuleEBNF g) => [CF g ()]
gram_comment =
[ void $ commentable (void $ argEBNF "space") (void $ argEBNF "line") (void $ argEBNF "block")
, void $ comment_line (argEBNF "prefix")
, void $ comment_block (argEBNF "begin") (argEBNF "end" :: RegL g String)
, void $ lexeme (argEBNF "g")
, void $ parens (argEBNF "g")
, void $ inside id (argEBNF "begin") (argEBNF "in") (argEBNF "end") (argEBNF "next")
]