1 -- The default type signature of type class methods are changed
2 -- to introduce a Liftable constraint and the same type class but on the 'Output' repr,
3 -- this setup avoids to define the method with boilerplate code when its default
4 -- definition with lift* and 'trans' does what is expected by an instance
5 -- of the type class. This is almost as explained in:
6 -- https://ro-che.info/articles/2016-02-03-finally-tagless-boilerplate
7 {-# LANGUAGE DefaultSignatures #-}
8 {-# LANGUAGE DeriveLift #-} -- For TH.Lift (ErrorItem tok)
9 {-# LANGUAGE StandaloneDeriving #-} -- For Show (ErrorItem (InputToken inp))
10 {-# LANGUAGE TemplateHaskell #-}
11 module Symantic.Parser.Grammar.Combinators where
13 import Data.Bool (Bool(..), not, (||))
14 import Data.Char (Char)
15 import Data.Either (Either(..))
16 import Data.Eq (Eq(..))
17 import Data.Function ((.), flip, const)
19 import Data.Maybe (Maybe(..))
21 import Data.String (String)
22 import Text.Show (Show(..))
23 import qualified Data.Functor as Functor
24 import qualified Data.List as List
25 import qualified Language.Haskell.TH as TH
26 import qualified Language.Haskell.TH.Syntax as TH
28 import qualified Symantic.Univariant.Trans as Sym
29 import qualified Symantic.Parser.Haskell as H
31 -- * Type 'TermGrammar'
32 type TermGrammar = H.Term H.ValueCode
34 -- * Class 'Applicable'
35 -- | This is like the usual 'Functor' and 'Applicative' type classes
36 -- from the @base@ package, but using @('TermGrammar' a)@ instead of just @(a)@
37 -- to be able to use and pattern match on some usual terms of type @(a)@ (like 'H.id')
38 -- and thus apply some optimizations.
39 -- @(repr)@, for "representation", is the usual tagless-final abstraction
40 -- over the many semantics that this syntax (formed by the methods
41 -- of type class like this one) will be interpreted.
42 class Applicable repr where
43 -- | @(a2b '<$>' ra)@ parses like @(ra)@ but maps its returned value with @(a2b)@.
44 (<$>) :: TermGrammar (a -> b) -> repr a -> repr b
45 (<$>) f = (pure f <*>)
47 -- | Like '<$>' but with its arguments 'flip'-ped.
48 (<&>) :: repr a -> TermGrammar (a -> b) -> repr b
51 -- | @(a '<$' rb)@ parses like @(rb)@ but discards its returned value by replacing it with @(a)@.
52 (<$) :: TermGrammar a -> repr b -> repr a
55 -- | @(ra '$>' b)@ parses like @(ra)@ but discards its returned value by replacing it with @(b)@.
56 ($>) :: repr a -> TermGrammar b -> repr b
59 -- | @('pure' a)@ parses the empty string, always succeeding in returning @(a)@.
60 pure :: TermGrammar a -> repr a
62 Sym.Liftable repr => Applicable (Sym.Output repr) =>
63 TermGrammar a -> repr a
64 pure = Sym.lift . pure
66 -- | @(ra2b '<*>' ra)@ parses sequentially @(ra2b)@ and then @(ra)@,
67 -- and returns the application of the function returned by @(ra2b)@
68 -- to the value returned by @(ra)@.
69 (<*>) :: repr (a -> b) -> repr a -> repr b
71 Sym.Liftable2 repr => Applicable (Sym.Output repr) =>
72 repr (a -> b) -> repr a -> repr b
73 (<*>) = Sym.lift2 (<*>)
75 -- | @('liftA2' a2b2c ra rb)@ parses sequentially @(ra)@ and then @(rb)@,
76 -- and returns the application of @(a2b2c)@ to the values returned by those parsers.
77 liftA2 :: TermGrammar (a -> b -> c) -> repr a -> repr b -> repr c
78 liftA2 f x = (<*>) (f <$> x)
80 -- | @(ra '<*' rb)@ parses sequentially @(ra)@ and then @(rb)@,
81 -- and returns like @(ra)@, discarding the return value of @(rb)@.
82 (<*) :: repr a -> repr b -> repr a
85 -- | @(ra '*>' rb)@ parses sequentially @(ra)@ and then @(rb)@,
86 -- and returns like @(rb)@, discarding the return value of @(ra)@.
87 (*>) :: repr a -> repr b -> repr b
88 x *> y = (H.id <$ x) <*> y
90 -- | Like '<*>' but with its arguments 'flip'-ped.
91 (<**>) :: repr a -> repr (a -> b) -> repr b
92 (<**>) = liftA2 (H.flip H..@ (H.$))
94 (<**>) :: repr a -> repr (a -> b) -> repr b
95 (<**>) = liftA2 (\a f -> f a)
97 infixl 4 <$>, <&>, <$, $>, <*>, <*, *>, <**>
99 -- * Class 'Alternable'
100 class Alternable repr where
101 -- | @(rl '<|>' rr)@ parses @(rl)@ and return its return value or,
102 -- if it fails, parses @(rr)@ from where @(rl)@ has left the input stream,
103 -- and returns its return value.
104 (<|>) :: repr a -> repr a -> repr a
105 -- | @(empty)@ parses nothing, always failing to return a value.
107 -- | @('try' ra)@ records the input stream position,
108 -- then parses like @(ra)@ and either returns its value it it succeeds or fails
109 -- if it fails but with a reset of the input stream to the recorded position.
110 -- Generally used on the first alternative: @('try' rl '<|>' rr)@.
111 try :: repr a -> repr a
113 Sym.Liftable2 repr => Alternable (Sym.Output repr) =>
114 repr a -> repr a -> repr a
116 Sym.Liftable repr => Alternable (Sym.Output repr) =>
119 Sym.Liftable1 repr => Alternable (Sym.Output repr) =>
121 (<|>) = Sym.lift2 (<|>)
122 empty = Sym.lift empty
124 -- | Like @('<|>')@ but with different returning types for the alternatives,
125 -- and a return value wrapped in an 'Either' accordingly.
126 (<+>) :: Applicable repr => Alternable repr => repr a -> repr b -> repr (Either a b)
127 p <+> q = H.left <$> p <|> H.right <$> q
130 optionally :: Applicable repr => Alternable repr => repr a -> TermGrammar b -> repr b
131 optionally p x = p $> x <|> pure x
133 optional :: Applicable repr => Alternable repr => repr a -> repr ()
134 optional = flip optionally H.unit
136 option :: Applicable repr => Alternable repr => TermGrammar a -> repr a -> repr a
137 option x p = p <|> pure x
139 choice :: Alternable repr => [repr a] -> repr a
140 choice = List.foldr (<|>) empty
141 -- FIXME: Here hlint suggests to use Data.Foldable.asum,
142 -- but at this point there is no asum for our own (<|>)
144 maybeP :: Applicable repr => Alternable repr => repr a -> repr (Maybe a)
145 maybeP p = option H.nothing (H.just <$> p)
147 manyTill :: Applicable repr => Alternable repr => repr a -> repr b -> repr [a]
148 manyTill p end = let go = end $> H.nil <|> p <:> go in go
150 -- * Class 'Selectable'
151 class Selectable repr where
152 branch :: repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
154 Sym.Liftable3 repr => Selectable (Sym.Output repr) =>
155 repr (Either a b) -> repr (a -> c) -> repr (b -> c) -> repr c
156 branch = Sym.lift3 branch
158 -- * Class 'Matchable'
159 class Matchable repr where
161 Eq a => repr a -> [TermGrammar (a -> Bool)] -> [repr b] -> repr b -> repr b
162 default conditional ::
163 Sym.Unliftable repr => Sym.Liftable1 repr => Matchable (Sym.Output repr) =>
164 Eq a => repr a -> [TermGrammar (a -> Bool)] -> [repr b] -> repr b -> repr b
165 conditional a ps bs = Sym.lift1 (conditional (Sym.trans a) ps (Sym.trans Functor.<$> bs))
167 match :: Eq a => repr a -> [TermGrammar a] -> (TermGrammar a -> repr b) -> repr b -> repr b
168 match a as a2b = conditional a ((H.eq H..@) Functor.<$> as) (a2b Functor.<$> as)
169 -- match a as a2b = conditional a (((H.eq H..@ H.qual) H..@) Functor.<$> as) (a2b Functor.<$> as)
171 -- * Class 'Foldable'
172 class Foldable repr where
173 chainPre :: repr (a -> a) -> repr a -> repr a
174 chainPost :: repr a -> repr (a -> a) -> repr a
177 Sym.Liftable2 repr => Foldable (Sym.Output repr) =>
178 repr (a -> a) -> repr a -> repr a
180 Sym.Liftable2 repr => Foldable (Sym.Output repr) =>
181 repr a -> repr (a -> a) -> repr a
182 chainPre = Sym.lift2 chainPre
183 chainPost = Sym.lift2 chainPost
188 repr (a -> a) -> repr a -> repr a
192 repr a -> repr (a -> a) -> repr a
193 chainPre op p = go <*> p
194 where go = (H..) <$> op <*> go <|> pure H.id
195 chainPost p op = p <**> go
196 where go = (H..) <$> op <*> go <|> pure H.id
199 conditional :: Selectable repr => [(TermGrammar (a -> Bool), repr b)] -> repr a -> repr b -> repr b
200 conditional cs p def = match p fs qs def
201 where (fs, qs) = List.unzip cs
204 -- * Class 'Satisfiable'
205 class Satisfiable repr tok where
206 satisfy :: [ErrorItem tok] -> TermGrammar (tok -> Bool) -> repr tok
208 Sym.Liftable repr => Satisfiable (Sym.Output repr) tok =>
210 TermGrammar (tok -> Bool) -> repr tok
211 satisfy es = Sym.lift . satisfy es
213 -- ** Type 'ErrorItem'
216 | ErrorItemLabel String
217 | ErrorItemHorizon Int
219 deriving instance Eq tok => Eq (ErrorItem tok)
220 deriving instance Ord tok => Ord (ErrorItem tok)
221 deriving instance Show tok => Show (ErrorItem tok)
222 deriving instance TH.Lift tok => TH.Lift (ErrorItem tok)
224 -- * Class 'Lookable'
225 class Lookable repr where
226 look :: repr a -> repr a
227 negLook :: repr a -> repr ()
228 default look :: Sym.Liftable1 repr => Lookable (Sym.Output repr) => repr a -> repr a
229 default negLook :: Sym.Liftable1 repr => Lookable (Sym.Output repr) => repr a -> repr ()
230 look = Sym.lift1 look
231 negLook = Sym.lift1 negLook
235 default eof :: Sym.Liftable repr => Lookable (Sym.Output repr) => repr ()
236 -- eof = negLook (satisfy @_ @Char [ErrorItemAny] (H.const H..@ H.bool True))
241 (<:>) :: Applicable repr => repr a -> repr [a] -> repr [a]
242 (<:>) = liftA2 H.cons
244 sequence :: Applicable repr => [repr a] -> repr [a]
245 sequence = List.foldr (<:>) (pure H.nil)
247 traverse :: Applicable repr => (a -> repr b) -> [a] -> repr [b]
248 traverse f = sequence . List.map f
249 -- FIXME: Here hlint suggests to use Control.Monad.mapM,
250 -- but at this point there is no mapM for our own sequence
252 repeat :: Applicable repr => Int -> repr a -> repr [a]
253 repeat n p = traverse (const p) [1..n]
255 between :: Applicable repr => repr o -> repr c -> repr a -> repr a
256 between open close p = open *> p <* close
259 Applicable repr => Alternable repr =>
260 Satisfiable repr Char =>
261 [Char] -> repr [Char]
262 string = try . traverse char
265 TH.Lift tok => Eq tok =>
266 Satisfiable repr tok =>
268 oneOf ts = satisfy [ErrorItemLabel "oneOf"]
269 (Sym.trans H.ValueCode
270 { value = (`List.elem` ts)
271 , code = [||\t -> $$(ofChars ts [||t||])||] })
274 TH.Lift tok => Eq tok =>
275 Satisfiable repr tok =>
277 noneOf cs = satisfy (ErrorItemToken Functor.<$> cs) (Sym.trans H.ValueCode
278 { value = not . (`List.elem` cs)
279 , code = [||\c -> not $$(ofChars cs [||c||])||]
283 TH.Lift tok => Eq tok =>
284 {-alternatives-}[tok] ->
285 {-input-}TH.CodeQ tok ->
287 ofChars = List.foldr (\alt acc ->
288 \inp -> [|| alt == $$inp || $$(acc inp) ||])
291 more :: Applicable repr => Satisfiable repr Char => Lookable repr => repr ()
292 more = look (void (item @_ @Char))
295 Applicable repr => Satisfiable repr Char =>
297 char c = satisfy [ErrorItemToken c] (H.eq H..@ H.char c) $> H.char c
298 -- char c = satisfy [ErrorItemToken c] (H.eq H..@ H.qual H..@ H.char c) $> H.char c
300 anyChar :: Satisfiable repr Char => repr Char
301 anyChar = satisfy [] (H.const H..@ H.bool True)
304 TH.Lift tok => Show tok => Eq tok =>
305 Applicable repr => Satisfiable repr tok =>
307 token tok = satisfy [ErrorItemToken tok] (H.eq H..@ H.char tok) $> H.char tok
308 -- token tok = satisfy [ErrorItemToken tok] (H.eq H..@ H.qual H..@ H.char tok) $> H.char tok
311 TH.Lift tok => Eq tok => Show tok =>
312 Applicable repr => Alternable repr =>
313 Satisfiable repr tok => [tok] -> repr [tok]
314 tokens = try . traverse token
316 item :: Satisfiable repr tok => repr tok
317 item = satisfy [] (H.const H..@ H.bool True)
319 -- Composite Combinators
320 -- someTill :: repr a -> repr b -> repr [a]
321 -- someTill p end = negLook end *> (p <:> manyTill p end)
323 void :: Applicable repr => repr a -> repr ()
326 unit :: Applicable repr => repr ()
330 constp :: Applicable repr => repr a -> repr (b -> a)
331 constp = (H.const <$>)
336 (>>) :: Applicable repr => repr a -> repr b -> repr b
339 -- Monoidal Operations
342 (<~>) :: Applicable repr => repr a -> repr b -> repr (a, b)
343 (<~>) = liftA2 (H.runtime (,))
346 (<~) :: Applicable repr => repr a -> repr b -> repr a
350 (~>) :: Applicable repr => repr a -> repr b -> repr b
356 TermGrammar (a -> b -> c) -> repr a -> repr b -> repr c
357 liftA2 f x = (<*>) (fmap f x)
361 TermGrammar (a -> b -> c -> d) -> repr a -> repr b -> repr c -> repr d
362 liftA3 f a b c = liftA2 f a b <*> c
368 Applicable repr => Foldable repr =>
369 TermGrammar (a -> b -> b) -> TermGrammar b -> repr a -> repr b
370 pfoldr f k p = chainPre (f <$> p) (pure k)
373 Applicable repr => Foldable repr =>
374 TermGrammar (a -> b -> b) -> TermGrammar b -> repr a -> repr b
375 pfoldr1 f k p = f <$> p <*> pfoldr f k p
378 Applicable repr => Foldable repr =>
379 TermGrammar (b -> a -> b) -> TermGrammar b -> repr a -> repr b
380 pfoldl f k p = chainPost (pure k) ((H.flip <$> pure f) <*> p)
383 Applicable repr => Foldable repr =>
384 TermGrammar (b -> a -> b) -> TermGrammar b -> repr a -> repr b
385 pfoldl1 f k p = chainPost (f <$> pure k <*> p) ((H.flip <$> pure f) <*> p)
389 Applicable repr => Foldable repr =>
390 TermGrammar (a -> b) -> repr a -> repr (b -> a -> b) -> repr b
391 chainl1' f p op = chainPost (f <$> p) (H.flip <$> op <*> p)
394 Applicable repr => Foldable repr =>
395 repr a -> repr (a -> a -> a) -> repr a
396 chainl1 = chainl1' H.id
399 chainr1' :: ParserOps rep => rep (a -> b) -> repr a -> repr (a -> b -> b) -> repr b
400 chainr1' f p op = newRegister_ H.id $ \acc ->
401 let go = bind p $ \x ->
402 modify acc (H.flip (H..@) <$> (op <*> x)) *> go
406 chainr1 :: repr a -> repr (a -> a -> a) -> repr a
407 chainr1 = chainr1' H.id
409 chainr :: repr a -> repr (a -> a -> a) -> TermGrammar a -> repr a
410 chainr p op x = option x (chainr1 p op)
414 Applicable repr => Alternable repr => Foldable repr =>
415 repr a -> repr (a -> a -> a) -> TermGrammar a -> repr a
416 chainl p op x = option x (chainl1 p op)
418 -- Derived Combinators
420 Applicable repr => Foldable repr =>
422 many = pfoldr H.cons H.nil
425 Applicable repr => Foldable repr =>
426 Int -> repr a -> repr [a]
427 manyN n p = List.foldr (const (p <:>)) (many p) [1..n]
430 Applicable repr => Foldable repr =>
435 Applicable repr => Foldable repr =>
437 --skipMany p = let skipManyp = p *> skipManyp <|> unit in skipManyp
438 skipMany = void . pfoldl H.const H.unit -- the void here will encourage the optimiser to recognise that the register is unused
441 Applicable repr => Foldable repr =>
442 Int -> repr a -> repr ()
443 skipManyN n p = List.foldr (const (p *>)) (skipMany p) [1..n]
446 Applicable repr => Foldable repr =>
448 skipSome = skipManyN 1
451 Applicable repr => Alternable repr => Foldable repr =>
452 repr a -> repr b -> repr [a]
453 sepBy p sep = option H.nil (sepBy1 p sep)
456 Applicable repr => Alternable repr => Foldable repr =>
457 repr a -> repr b -> repr [a]
458 sepBy1 p sep = p <:> many (sep *> p)
461 Applicable repr => Alternable repr => Foldable repr =>
462 repr a -> repr b -> repr [a]
463 endBy p sep = many (p <* sep)
466 Applicable repr => Alternable repr => Foldable repr =>
467 repr a -> repr b -> repr [a]
468 endBy1 p sep = some (p <* sep)
471 Applicable repr => Alternable repr => Foldable repr =>
472 repr a -> repr b -> repr [a]
473 sepEndBy p sep = option H.nil (sepEndBy1 p sep)
476 Applicable repr => Alternable repr => Foldable repr =>
477 repr a -> repr b -> repr [a]
479 let seb1 = p <**> (sep *> (H.flip H..@ H.cons <$> option H.nil seb1)
480 <|> pure (H.flip H..@ H.cons H..@ H.nil))
484 sepEndBy1 :: repr a -> repr b -> repr [a]
485 sepEndBy1 p sep = newRegister_ H.id $ \acc ->
486 let go = modify acc ((H.flip (H..)) H..@ H.cons <$> p)
487 *> (sep *> (go <|> get acc) <|> get acc)
492 -- Combinators interpreters for 'Sym.Any'.
493 instance Applicable repr => Applicable (Sym.Any repr)
494 instance Satisfiable repr => Satisfiable (Sym.Any repr)
495 instance Alternable repr => Alternable (Sym.Any repr)
496 instance Selectable repr => Selectable (Sym.Any repr)
497 instance Matchable repr => Matchable (Sym.Any repr)
498 instance Lookable repr => Lookable (Sym.Any repr)
499 instance Foldable repr => Foldable (Sym.Any repr)