1 {-# OPTIONS_GHC -fno-warn-orphans #-}
2 -- | Symantics for terminal grammars.
3 module Language.Symantic.Grammar.Terminal where
5 import Data.Semigroup (Semigroup(..))
6 import Data.String (IsString(..))
7 import qualified Data.Bool as Bool
8 import qualified Data.Char as Char
9 import qualified Data.List as List
10 import qualified Data.Text as Text
11 import qualified Data.Text.Lazy as TL
13 import Language.Symantic.Grammar.Fixity
14 import Language.Symantic.Grammar.EBNF
17 -- | Terminal grammar.
19 = Terminal { unTerminal :: g a }
20 deriving (Functor, Gram_Char, Gram_String)
21 deriving instance Gram_Rule g => Gram_Rule (Terminal g)
23 -- ** Class 'Gram_Char'
24 -- | Symantics for terminal grammars.
25 class Gram_Rule g => Gram_Char g where
27 but :: Terminal g Char -> Terminal g Char -> Terminal g Char
31 char :: Char -> g Char
32 unicat :: Unicat -> g Char
33 range :: (Char, Char) -> g Char
34 eol = rule "NewLine" $ char '\n'
35 space = rule "Space" $ char ' '
36 deriving instance Gram_Char RuleEBNF
37 instance Gram_Char EBNF where
39 Terminal (EBNF f) `but` Terminal (EBNF g) =
40 Terminal $ EBNF $ \bo po -> parenInfix po op $
41 f bo (op, SideL) <> " - " <> g bo (op, SideR)
43 eoi = ebnf_const "eoi"
45 space = ebnf_const "␣"
46 char = ebnf_const . escape
48 escape c | Char.isPrint c && c /= '"' = Text.concat $ ["\"", Text.singleton c, "\""]
49 escape c = Text.concat ["U+", Text.pack $ show $ Char.ord c]
50 unicat = ebnf_const . Text.pack . show
51 range (l, h) = ebnf_const $ Text.concat
58 -- | Unicode category.
65 | Unicat Char.GeneralCategory
68 unicode_categories :: Unicat -> [Char.GeneralCategory]
69 unicode_categories c =
72 [ Char.UppercaseLetter
73 , Char.LowercaseLetter
74 , Char.TitlecaseLetter
80 , Char.SpacingCombiningMark
89 [ Char.ConnectorPunctuation
90 , Char.DashPunctuation
91 , Char.OpenPunctuation
92 , Char.ClosePunctuation
93 , Char.OtherPunctuation
103 -- ** Class 'Gram_String'
104 class Functor g => Gram_String g where
105 string :: String -> g String
107 string = foldr (\c -> (<*>) ((:) <$> char c)) (pure "")
109 string (c:cs) = (:) <$> char c <*> string cs
111 text :: Text.Text -> g Text.Text
112 textLazy :: TL.Text -> g TL.Text
113 text t = Text.pack <$> string (Text.unpack t)
114 textLazy t = TL.pack <$> string (TL.unpack t)
115 deriving instance Gram_String RuleEBNF
116 instance Gram_String EBNF where
118 case List.break (\c -> Bool.not (Char.isPrint c) || c == '"') s of
120 ("", [c]) -> "" <$ char c
121 (ps, [c]) -> "" <$ raw ps <* char c
122 ("", c:rs) -> "" <$ char c <* string rs
123 (ps, c:rs) -> "" <$ raw ps <* char c <* string rs
125 raw cs = ebnf_const $ Text.concat $ ["\"", Text.pack cs, "\""]
126 instance IsString (EBNF String) where