1 {-# LANGUAGE FlexibleContexts #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE Rank2Types #-}
4 {-# LANGUAGE TypeFamilies #-}
5 module Language.TCT.Read.Token where
7 import Control.Applicative (Applicative(..), Alternative(..))
8 import Control.Monad (Monad(..))
10 import Data.Char (Char)
11 import Data.Eq (Eq(..))
12 import Data.Foldable (Foldable(..))
13 import Data.Function (($), (.), flip)
14 import Data.Functor ((<$>), ($>), (<$))
15 import Data.Maybe (Maybe(..), fromMaybe)
16 import Data.Monoid (Monoid(..))
17 import Data.Semigroup (Semigroup(..))
18 import Data.Text (Text)
19 import Data.Text.Buildable (Buildable(..))
20 import Data.Tuple (fst,snd)
21 import Text.Show (Show(..))
22 import qualified Data.Char as Char
23 import qualified Data.Text as Text
24 import qualified Data.Text.Lazy as TL
25 import qualified Data.Text.Lazy.Builder as Builder
26 import qualified Text.Megaparsec as P
28 import Language.TCT.Token
29 import Language.TCT.Elem
30 import Language.TCT.Read.Elem
32 textOf :: Buildable a => a -> Text
33 textOf = TL.toStrict . Builder.toLazyText . build
36 type Groups = (Token,[(Group,Token)])
38 openGroup :: Group -> Groups -> Groups
39 openGroup g (t,ms) = (t,(g,mempty):ms)
41 groupToken :: Token -> Groups -> Groups
42 groupToken mrk (t,[]) = (t<>mrk,[])
43 groupToken mrk (t,(g0,m0):gs) = (t,(g0,m0<>mrk):gs)
45 closeGroup :: Group -> Groups -> Groups
46 closeGroup g (t,[]) = (t<>TokenPlain (snd $ groupBorders g mempty),[])
47 closeGroup g (t,(g1,m1):ms) =
49 (GroupElem x ax, GroupElem y ay) | x == y ->
50 groupToken (TokenGroup (GroupElem x (ax<>ay)) m1) (t,ms)
51 (x,y) | x == y -> groupToken (TokenGroup g1 m1) (t,ms)
55 (TokenPlain (fst $ groupBorders g1 mempty) <> m1)
58 closeGroups :: Groups -> Token
60 let (m0,gs) = appendLexeme (LexemeWhite "") grps in
62 acc <> TokenPlain (fst $ groupBorders g mempty) <> t) m0 gs
66 = LexemeGroupOpen Group
67 | LexemeGroupClose Group
68 | LexemeGroupPlain Char
76 appendLexeme :: Lexeme -> Groups -> Groups
78 case dbg "appendLexeme" lex of
79 _ | (tok,(GroupHash,tag):gs') <- gs
82 LexemeEscape{} -> False
83 LexemeGroupClose GroupHash -> False
86 groupToken (TokenTag (textOf tag)) (tok,gs')
87 LexemeGroupOpen g -> openGroup g gs
88 LexemeGroupClose g -> closeGroup g gs
89 LexemeGroupPlain c -> groupToken (TokenPlain (Text.singleton c)) gs
90 LexemeWhite wh -> groupToken (TokenPlain wh) gs
91 LexemeWord wo -> groupToken (TokenPlain wo) gs
92 LexemeToken tok -> groupToken tok gs
93 LexemeEscape c -> groupToken (TokenEscape c) gs
94 LexemeLink lnk -> groupToken (TokenLink lnk) gs
96 appendLexemes :: Groups -> [Lexeme] -> Groups
97 appendLexemes = foldl' (flip appendLexeme)
101 p_Token :: Parser e s Token
102 p_Token = closeGroups <$> p_Groups (mempty,[])
104 p_Groups :: Groups -> Parser e s Groups
105 p_Groups gs = pdbg "Groups" $
107 (p_Lexemes (mempty == gs) >>= p_Groups . appendLexemes gs)
110 p_Lexemes :: Bool -> Parser e s [Lexeme]
111 p_Lexemes isBOF = pdbg "Lexemes" $
113 [ P.try $ p_GroupClose
114 , P.try $ p_GroupOpen isBOF
115 , P.try $ p_GroupOpenOrClose l_GroupOpenOrClose
116 , P.try $ pure <$> p_White
117 , pure . LexemeWord <$> p_Word
120 p_White :: Parser e s Lexeme
121 p_White = pdbg "White" $
122 LexemeWhite <$> p_Spaces
124 p_PunctOrSym :: Parser e s Char
125 p_PunctOrSym = P.satisfy $ \c -> Char.isPunctuation c || Char.isSymbol c
127 p_GroupOpen :: Bool -> Parser e s [Lexeme]
128 p_GroupOpen isBOF = pdbg "GroupOpen" $ do
129 wh <- if isBOF then return [] else pure <$> p_White
130 ps <- mconcat <$> P.some (P.try $ p_GroupOpenOrClose $ l_GroupOpenAndClose LexemeGroupOpen)
133 p_GroupClose :: Parser e s [Lexeme]
134 p_GroupClose = pdbg "GroupClose" $ do
135 ps <- mconcat <$> P.some (P.try $ p_GroupOpenOrClose $ l_GroupOpenAndClose LexemeGroupClose)
136 wh <- pure <$> p_White <|> P.eof $> []
139 p_GroupOpenOrClose :: (Char -> Maybe Lexeme) -> Parser e s [Lexeme]
140 p_GroupOpenOrClose grp = pdbg "GroupOpenOrClose" $ do
143 , P.try (pure <$> p_Escape)
144 , P.try (pure <$> p_Link)
145 , (<$> p_PunctOrSym) $ \c ->
147 LexemeGroupPlain c `fromMaybe`
151 l_GroupOpenAndClose :: (Group -> Lexeme) -> Char -> Maybe Lexeme
152 l_GroupOpenAndClose lxm c = dbg "GroupOpenAndClose" $
154 '/' -> Just $ lxm GroupSlash
155 '-' -> Just $ lxm GroupDash
156 '"' -> Just $ lxm GroupDoublequote
157 '\'' -> Just $ lxm GroupSinglequote
158 '`' -> Just $ lxm GroupBackquote
159 '_' -> Just $ lxm GroupUnderscore
160 '*' -> Just $ lxm GroupStar
161 '#' -> Just $ lxm GroupHash
162 _ -> l_GroupOpenOrClose c
164 l_GroupOpenOrClose :: Char -> Maybe Lexeme
165 l_GroupOpenOrClose c = dbg "GroupOpenOrClose" $
167 '(' -> Just $ LexemeGroupOpen GroupParen
168 '[' -> Just $ LexemeGroupOpen GroupBracket
169 '{' -> Just $ LexemeGroupOpen GroupBrace
170 '«' -> Just $ LexemeGroupOpen GroupFrenchquote
171 ')' -> Just $ LexemeGroupClose GroupParen
172 ']' -> Just $ LexemeGroupClose GroupBracket
173 '}' -> Just $ LexemeGroupClose GroupBrace
174 '»' -> Just $ LexemeGroupClose GroupFrenchquote
177 p_Link :: Parser e s Lexeme
179 (\scheme ss addr -> LexemeLink $ Text.pack $ scheme <> ss <> addr)
180 <$> P.option "" (P.try p_scheme)
186 <$> P.some (P.satisfy $ \c ->
204 p_Escape :: Parser e s Lexeme
208 <*> P.satisfy Char.isPrint
210 p_Elem :: Parser e s [Lexeme]
211 p_Elem = pdbg "Elem" $ P.char '<' >> (p_close <|> p_open)
216 True -> [ LexemeGroupOpen $ GroupElem e as
217 , LexemeToken $ Tokens mempty -- same elem for open and close
218 , LexemeGroupClose $ GroupElem e [] ]
219 False -> [LexemeGroupOpen $ GroupElem e as])
222 <*> P.option False (True <$ P.char '/')
225 (\e -> [LexemeGroupClose $ GroupElem e []])