1 {-# OPTIONS_GHC -fno-warn-orphans #-}
2 -- | Symantics for terminal grammars.
3 module Language.Symantic.Grammar.Terminal where
5 import Control.Applicative (Applicative(..))
7 import Data.Char (Char)
8 import Data.Eq (Eq(..))
9 import Data.Function (($), (.))
10 import Data.Functor (Functor(..), (<$>))
11 import Data.Semigroup (Semigroup(..))
12 import Data.String (IsString(..), String)
13 import Text.Show (Show(..))
14 import qualified Data.Bool as Bool
15 import qualified Data.Char as Char
16 import qualified Data.List as List
17 import qualified Data.Text as Text
18 import qualified Data.Text.Lazy as TL
20 import Language.Symantic.Grammar.Fixity
21 import Language.Symantic.Grammar.EBNF
24 -- | Terminal grammar.
26 = Terminal { unTerminal :: g a }
27 deriving (Functor, Gram_Char, Gram_String)
28 deriving instance Gram_Rule g => Gram_Rule (Terminal g)
30 -- ** Class 'Gram_Char'
31 -- | Symantics for terminal grammars.
32 class Gram_Rule g => Gram_Char g where
34 but :: Terminal g Char -> Terminal g Char -> Terminal g Char
38 char :: Char -> g Char
39 unicat :: Unicat -> g Char
40 range :: (Char, Char) -> g Char
41 eol = rule "NewLine" $ char '\n'
42 space = rule "Space" $ char ' '
43 deriving instance Gram_Char RuleEBNF
44 instance Gram_Char EBNF where
46 Terminal (EBNF f) `but` Terminal (EBNF g) =
47 Terminal $ EBNF $ \bo po -> pairIfNeeded pairParen po op $
48 f bo (op, SideL) <> " - " <> g bo (op, SideR)
50 eoi = ebnf_const "eoi"
52 space = ebnf_const "␣"
53 char = ebnf_const . escape
55 escape c | Char.isPrint c && c /= '"' = Text.concat $ ["\"", Text.singleton c, "\""]
56 escape c = Text.concat ["U+", Text.pack $ show $ Char.ord c]
57 unicat = ebnf_const . Text.pack . show
58 range (l, h) = ebnf_const $ Text.concat
65 -- | Unicode category.
72 | Unicat Char.GeneralCategory
75 unicode_categories :: Unicat -> [Char.GeneralCategory]
76 unicode_categories c =
79 [ Char.UppercaseLetter
80 , Char.LowercaseLetter
81 , Char.TitlecaseLetter
87 , Char.SpacingCombiningMark
96 [ Char.ConnectorPunctuation
97 , Char.DashPunctuation
98 , Char.OpenPunctuation
99 , Char.ClosePunctuation
100 , Char.OtherPunctuation
104 , Char.CurrencySymbol
105 , Char.ModifierSymbol
110 -- ** Class 'Gram_String'
111 class Functor g => Gram_String g where
112 string :: String -> g String
114 string = foldr (\c -> (<*>) ((:) <$> char c)) (pure "")
116 string (c:cs) = (:) <$> char c <*> string cs
118 text :: Text.Text -> g Text.Text
119 textLazy :: TL.Text -> g TL.Text
120 text t = Text.pack <$> string (Text.unpack t)
121 textLazy t = TL.pack <$> string (TL.unpack t)
122 deriving instance Gram_String RuleEBNF
123 instance Gram_String EBNF where
125 case List.break (\c -> Bool.not (Char.isPrint c) || c == '"') s of
127 ("", [c]) -> "" <$ char c
128 (ps, [c]) -> "" <$ raw ps <* char c
129 ("", c:rs) -> "" <$ char c <* string rs
130 (ps, c:rs) -> "" <$ raw ps <* char c <* string rs
132 raw cs = ebnf_const $ Text.concat $ ["\"", Text.pack cs, "\""]
133 instance IsString (EBNF String) where