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 tok repr where
206 satisfy :: [ErrorItem tok] -> TermGrammar (tok -> Bool) -> repr tok
208 Sym.Liftable repr => Satisfiable tok (Sym.Output repr) =>
210 TermGrammar (tok -> Bool) -> repr tok
211 satisfy es = Sym.lift . satisfy es
214 item = satisfy [] (H.const H..@ H.bool True)
216 -- ** Type 'ErrorItem'
219 | ErrorItemLabel String
220 | ErrorItemHorizon Int
222 deriving instance Eq tok => Eq (ErrorItem tok)
223 deriving instance Ord tok => Ord (ErrorItem tok)
224 deriving instance Show tok => Show (ErrorItem tok)
225 deriving instance TH.Lift tok => TH.Lift (ErrorItem tok)
227 -- * Class 'Lookable'
228 class Lookable repr where
229 look :: repr a -> repr a
230 negLook :: repr a -> repr ()
231 default look :: Sym.Liftable1 repr => Lookable (Sym.Output repr) => repr a -> repr a
232 default negLook :: Sym.Liftable1 repr => Lookable (Sym.Output repr) => repr a -> repr ()
233 look = Sym.lift1 look
234 negLook = Sym.lift1 negLook
238 default eof :: Sym.Liftable repr => Lookable (Sym.Output repr) => repr ()
239 -- eof = negLook (satisfy @Char [ErrorItemAny] (H.const H..@ H.bool True))
244 (<:>) :: Applicable repr => repr a -> repr [a] -> repr [a]
245 (<:>) = liftA2 H.cons
247 sequence :: Applicable repr => [repr a] -> repr [a]
248 sequence = List.foldr (<:>) (pure H.nil)
250 traverse :: Applicable repr => (a -> repr b) -> [a] -> repr [b]
251 traverse f = sequence . List.map f
252 -- FIXME: Here hlint suggests to use Control.Monad.mapM,
253 -- but at this point there is no mapM for our own sequence
255 repeat :: Applicable repr => Int -> repr a -> repr [a]
256 repeat n p = traverse (const p) [1..n]
258 between :: Applicable repr => repr o -> repr c -> repr a -> repr a
259 between open close p = open *> p <* close
262 Applicable repr => Alternable repr =>
263 Satisfiable Char repr =>
264 [Char] -> repr [Char]
265 string = try . traverse char
268 TH.Lift tok => Eq tok =>
269 Satisfiable tok repr =>
271 oneOf ts = satisfy [ErrorItemLabel "oneOf"]
272 (Sym.trans H.ValueCode
273 { value = (`List.elem` ts)
274 , code = [||\t -> $$(ofChars ts [||t||])||] })
277 TH.Lift tok => Eq tok =>
278 Satisfiable tok repr =>
280 noneOf cs = satisfy (ErrorItemToken Functor.<$> cs) (Sym.trans H.ValueCode
281 { value = not . (`List.elem` cs)
282 , code = [||\c -> not $$(ofChars cs [||c||])||]
286 TH.Lift tok => Eq tok =>
287 {-alternatives-}[tok] ->
288 {-input-}TH.CodeQ tok ->
290 ofChars = List.foldr (\alt acc ->
291 \inp -> [|| alt == $$inp || $$(acc inp) ||])
294 more :: Applicable repr => Satisfiable Char repr => Lookable repr => repr ()
295 more = look (void (item @Char))
298 Applicable repr => Satisfiable Char repr =>
300 char c = satisfy [ErrorItemToken c] (H.eq H..@ H.char c) $> H.char c
301 -- char c = satisfy [ErrorItemToken c] (H.eq H..@ H.qual H..@ H.char c) $> H.char c
303 anyChar :: Satisfiable Char repr => repr Char
304 anyChar = satisfy [] (H.const H..@ H.bool True)
307 TH.Lift tok => Show tok => Eq tok =>
308 Applicable repr => Satisfiable tok repr =>
310 token tok = satisfy [ErrorItemToken tok] (H.eq H..@ H.char tok) $> H.char tok
311 -- token tok = satisfy [ErrorItemToken tok] (H.eq H..@ H.qual H..@ H.char tok) $> H.char tok
314 TH.Lift tok => Eq tok => Show tok =>
315 Applicable repr => Alternable repr =>
316 Satisfiable tok repr => [tok] -> repr [tok]
317 tokens = try . traverse token
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)