-
Notifications
You must be signed in to change notification settings - Fork 15
/
Parsley.scala
1283 lines (1267 loc) · 62.8 KB
/
Parsley.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* SPDX-FileCopyrightText: © 2018 Parsley Contributors <https://github.com/j-mie6/Parsley/graphs/contributors>
* SPDX-License-Identifier: BSD-3-Clause
*/
package parsley
import parsley.combinator.{option, some}
import parsley.errors.ErrorBuilder
import parsley.expr.{chain, infix}
import parsley.internal.deepembedding.{frontend, singletons}
import parsley.internal.machine.Context
import Parsley.pure
import XCompat._ // substituteCo
/**
* This is the class that encapsulates the act of parsing and running an object of this class with `parse` will
* parse the string given as input to `parse`.
*
* @note In order to construct an object of this class you must use the combinators; the class itself is opaque.
*
* @author Jamie Willis
* @version 4.0.0
*
* @groupprio run 0
* @groupname run Running Parsers
* @groupdesc run These methods allow for a parser to be executed.
*
* @groupprio map 20
* @groupname map Result Changing Combinators
* @groupdesc map
* These combinators change the result of the parser they are called on into a value
* of a different type. This new result value may or may not be derived from the previous
* result.
*
* @groupprio alt 25
* @groupname alt Branching Combinators
* @groupdesc alt
* These combinators allow for parsing one alternative or another. All of these combinators
* are ''left-biased'', which means that the left-hand side of the combinator is tried first:
* the right-hand side of the combinator will only be tried when the left-hand one failed
* (and did not consume input in the process).
*
* @groupprio seq 25
* @groupname seq Sequencing Combinators
* @groupdesc seq
* These combinators all combine two parsers in sequence. The receiver of the combinator
* will be executed first, then the argument second. The results of both parsers are combined
* in some way (depending on the individual combinator). If one of the parsers fails, the
* combinator as a whole fails.
*
* @groupprio filter 50
* @groupname filter Filtering Combinators
* @groupdesc filter
* These combinators perform filtering on the results of a parser. This means that, given
* the result of a parser, they will perform some function on that result, and the success
* of that function effects whether or not the parser fails.
*
* @groupprio fold 50
* @groupname fold Folding Combinators
* @groupdesc fold
* These combinators repeatedly execute a parser (at least zero or one times depending on
* the specific combinator) until it fails. The results of the successes are then combined
* together using a folding function. An initial value for the accumulation may be given
* (for the `fold`s), or the first successful result is the initial accumulator (for the
* `reduce`s). These are implemented efficiently and do not need to construct any intermediate
* list with which to store the results.
*
* @groupprio monad 75
* @groupname monad Expensive Sequencing Combinators
* @groupdesc monad
* These combinators can sequence two parsers, where the first parser's result influences
* the structure of the second one. This may be because the second parser is generated
* from the result of the first, or that the first parser ''returns'' the second parser.
* Either way, the second parser cannot be known until runtime, when the first parser
* has been executed: this means that Parsley is forced to compile the second parser during
* parse-time, which is '''very''' expensive to do repeatedly. These combinators are only
* needed in exceptional circumstances, and should be avoided otherwise.
*
* @groupprio special 100
* @groupname special Special Methods
* @groupdesc special These are methods that should be rarely needed.
*
* @define attemptreason
* The reason for this behaviour is that it prevents space leaks and improves error messages. If this behaviour
* is not desired, use `attempt(this)` to rollback any input consumed on failure.
*
* @define or
* parses `q` if this parser fails '''without''' consuming input.
*
* If this parser is successful, then this combinator is successful and no further action is taken. Otherwise, if this parser
* fails '''without''' consuming input, then `q` is parsed instead. If this parser fails having consumed
* input, this combinator fails.
*
* @define orconst
* returns `x` if this parser fails '''without''' consuming input.
*
* If this parser is successful, then this combinator is successful and no further action is taken. Otherwise, if this parser
* fails '''without''' consuming input, then `x` is unconditionally returned. If this parser fails having consumed
* input, this combinator fails. Functionally the same as `this <|> pure(x)`.
*
* @define bind
* first performs this parser, then uses its result to generate and execute a new parser.
*
* First, this combinator runs this parser. If it succeeded, the result `x` is given to the function `f`
* to produce a new parser `f(x)`. This new parser is then executed and its result returned. If either
* of this parser or the new parser fails, then the entire combinator fails.
*
* This is a very powerful combinator (Turing-powerful, in fact): it is only necessary (and not ''all''
* the time) to use this for context-sensitive parsing. The idea is that it can make any form of
* decision based on the result of a parser, allowing it to perform a different parser for each
* possible output of another without exhaustively enumerating them all.
*
* @define autoAmend
* when this combinator fails (and not this parser itself), it will generate errors rooted at the start of the
* parse (as if [[parsley.errors.combinator$.amend `amend`]] had been used) and the caret will span the entire
* successful parse of this parser.
*/
final class Parsley[+A] private [parsley] (private [parsley] val internal: frontend.LazyParsley[A]) extends AnyVal {
/** This method is responsible for actually executing parsers. Given an input
* array, will parse the string with the parser. The result is either a `Success` or a `Failure`.
* @param input The input to run against
* @return Either a success with a value of type `A` or a failure with error message
* @since 3.0.0
* @group run
*/
def parse[Err: ErrorBuilder](input: String): Result[Err, A] = new Context(internal.instrs, input, internal.numRegs, None).run()
// RESULT CHANGING COMBINATORS
/** This combinator allows the result of this parser to be changed using a given function.
*
* When this parser succeeds, `map(f)` will adjust its result using the function `f`, which can
* potentially change its type. This can be used to build more complex results from parsers, instead
* of just characters or strings.
*
* ''In Haskell, this combinator is known as `fmap` or `(<$>)`''.
*
* @example {{{
* scala> import parsley.character.digit
* scala> digit.map(_.asDigit).parse("7")
* val res0 = Success(7)
* }}}
*
* @note This is subject to aggressive optimisations assuming purity; the compiler is permitted to optimise such
* that the application of `f` actually only happens once at compile time. In order to preserve the behaviour of
* impure functions, consider using the `unsafe` method before map; `p.unsafe.map(f)`.
* @param f the function to apply to the result of the parse
* @return a new parser that behaves the same as this parser, but with the given function `f` applied to its result.
* @group map
*/
def map[B](f: A => B): Parsley[B] = pure(f) <*> this
/** This combinator, pronounced "as", replaces the result of this parser, ignoring the old result.
*
* Similar to `map`, except the old result of this parser is not required to
* compute the new result. This is useful when the result is a constant value (or function!).
* Functionally the same as `this *> pure(x)` or `this.map(_ => x)`.
*
* ''In Haskell, this combinator is known as `($>)`''.
*
* @example {{{
* scala> import parsley.character.string
* scala> (string("true") #> true).parse("true")
* val res0 = Success(true)
* }}}
*
* @param x the new result of this parser.
* @return a new parser that behaves the same as this parser, but always succeeds with `x` as the result.
* @group map
*/
def #>[B](x: B): Parsley[B] = this *> pure(x)
/** Replaces the result of this parser with `()`.
*
* This combinator is useful when the result of this parser is not required, and the
* type must be `Parsley[Unit]`. Functionally the same as `this #> ()`.
*
* @return a new parser that behaves the same as this parser, but always returns `()` on success.
* @group map
*/
def void: Parsley[Unit] = this #> (())
// BRANCHING COMBINATORS
/** This combinator, pronounced "or", $or
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("a") <|> string("b")
* scala> p.parse("a")
* val res0 = Success("a")
* scala> p.parse("b")
* val res1 = Success("b")
* scala> val q = string("ab") <|> string("ac")
* scala> q.parse("ac")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @param q the parser to run if this parser fails having not consumed input.
* @tparam Aʹ the type returned by `q`, which must be a supertype of the result type of this parser: this allows for weakening of the result type.
* @return a parser which either parses this parser or parses `q`.
* @group alt
*/
def <|>[Aʹ >: A](q: Parsley[Aʹ]): Parsley[Aʹ] = new Parsley(new frontend.<|>(this.internal, q.internal))
/** This combinator, pronounced "or", $or
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("a") | string("b")
* scala> p.parse("a")
* val res0 = Success("a")
* scala> p.parse("b")
* val res1 = Success("b")
* scala> val q = string("ab") | string("ac")
* scala> q.parse("ac")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @since 4.0.0
* @param q the parser to run if this parser fails having not consumed input.
* @tparam Aʹ the type returned by `q`, which must be a supertype of the result type of this parser: this allows for weakening of the result type.
* @return a parser which either parses this parser or parses `q`.
* @note just an alias for `<|>`.
* @group alt
*/
def |[Aʹ >: A](q: Parsley[Aʹ]): Parsley[Aʹ] = this <|> q
/** This combinator $or
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("a").orElse(string("b"))
* scala> p.parse("a")
* val res0 = Success("a")
* scala> p.parse("b")
* val res1 = Success("b")
* scala> val q = string("ab").orElse(string("ac"))
* scala> q.parse("ac")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @since 4.0.0
* @param q the parser to run if this parser fails having not consumed input.
* @tparam Aʹ the type returned by `q`, which must be a supertype of the result type of this parser: this allows for weakening of the result type.
* @return a parser which either parses this parser or parses `q`.
* @note just an alias for `<|>`.
* @group alt
*/
def orElse[Aʹ >: A](q: Parsley[Aʹ]): Parsley[Aʹ] = this <|> q
/** This combinator, pronounced "or constant", $orconst
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("aa") </> "b"
* scala> p.parse("aa")
* val res0 = Success("a")
* scala> p.parse("xyz")
* val res1 = Success("b")
* scala> p.parse("ab")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @param x the value to return if this parser fails having not consumed input.
* @tparam Aʹ the type of `x`, which must be a supertype of the result type of this parser: this allows for weakening of the result type.
* @return a parser which either parses this parser or returns `x`.
* @group alt
*/
def </>[Aʹ >: A](x: Aʹ): Parsley[Aʹ] = this <|> pure(x)
/** This combinator $orconst
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.string
* scala> val p = string("aa").getOrElse("b")
* scala> p.parse("aa")
* val res0 = Success("a")
* scala> p.parse("xyz")
* val res1 = Success("b")
* scala> p.parse("ab")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @group alt
* @note just an alias for `</>`
*/
def getOrElse[Aʹ >: A](x: Aʹ): Parsley[Aʹ] = this </> x
/** This combinator, pronounced "sum", wraps this parser's result in `Left` if it succeeds, and parses `q` if it failed '''without''' consuming input,
* wrapping the result in `Right`.
*
* If this parser is successful, then its result is wrapped up using `Left(_)` and no further action is taken.
* Otherwise, if this parser fails '''without''' consuming input, then `q` is parsed instead and its result is
* wrapped up using `Right(_)`. If this parser fails having consumed input, this combinator fails.
* This is functionally equivalent to `this.map(Left(_)) <|> q.map(Right(_))`.
*
* $attemptreason
*
* @example {{{
* scala> import parsley.character.char
* scala> val p = string("abc") <+> char("xyz")
* scala> p.parse("abc")
* val res0 = Success(Left("abc"))
* scala> p.parse("xyz")
* val res1 = Success(Right("xyz"))
* scala> p.parse("ab")
* val res2 = Failure(..) // first parser consumed an 'a'!
* }}}
*
* @param q the parser to run if this parser fails having not consumed input.
* @return a parser which either parses this parser or parses `q` projecting their results into an `Either[A, B]`.
* @group alt
*/
def <+>[B](q: Parsley[B]): Parsley[Either[A, B]] = this.map(Left(_)) <|> q.map(Right(_))
// SEQUENCING COMBINATORS
/** This combinator, pronounced "ap", first parses this parser then parses `px`: if both succeed then the function
* returned by this parser is applied to the value returned by `px`.
*
* The implicit (compiler-provided) evidence proves that this parser really has type `Parsley[B => C]`.
* First, this parser is ran, yielding a function `f` on success, then `px` is ran, yielding a value `x`
* on success. If both are successful, then `f(x)` is returned. If either fail then the entire combinator
* fails.
*
* @example {{{
* scala> import parsley.Parsley, parsley.character.char
* scala> val sign: Parsley[Int => Int] = char('+') #> (identity[Int] _) <|> char('-') #> (x => -x)
* scala> val nat: Parsley[Int] = ..
* scala> val int = sign <*> nat
* scala> int.parse("-7")
* val res0 = Success(-7)
* scala> int.parse("+42")
* val res1 = Success(42)
* scala> int.parse("2")
* val res2 = Failure(..) // `sign` failed: no + or -
* scala> int.parse("-a")
* val res3 = Failure(..) // `nat` failed
* }}}
*
* @param px the parser to run second, which returns a value applicable to this parser's result.
* @param ev witnesses that the type of this parser, `A`, is actually `B => C`.
* @return a parser that sequences this parser with `px` and combines their results with function application.
* @note equivalent to `lift2((f, x) => f(x), this, px)`.
* @group seq
*/
def <*>[B, C](px: =>Parsley[B])
(implicit ev: A <:< (B=>C)): Parsley[C] = new Parsley(new frontend.<*>[B, C](ev.substituteParsley(this).internal, px.internal))
/** This combinator, pronounced "reverse ap", first parses this parser then parses `pf`: if both succeed then the value
* returned by this parser is applied to the function returned by `pf`.
*
* First, this parser is ran, yielding a value `x` on success, then `pf` is ran, yielding a function `f`
* on success. If both are successful, then `f(x)` is returned. If either fail then the entire combinator
* fails.
*
* Compared with `<*>`, this combinator is useful for left-factoring: when two branches of a parser share
* a common prefix, this can often be factored out; but the result of that factored prefix may be required
* to help generate the results of each branch. In this case, the branches can return functions that, when
* given the factored result, can produce the original results from before the factoring.
*
* @example {{{
* // this has a common prefix "term" and requires backtracking
* val expr1 = attempt(lift2(Add, term <* char('+'), expr2)) <|> term
* // common prefix factored out, and branches return a function to recombine
* val expr2 = term <**> (char('+') *> expr2.map(y => Add(_, y)) </> (identity[Expr] _))
* }}}
*
* @param pf the parser to run second, which returns a function this parser's result can be applied to.
* @return a parser that sequences this parser with `pf` and combines their results with function application.
* @note equivalent to {{{lift2((x, f) => f(x), this, pf)}}}
* @group seq
*/
def <**>[B](pf: =>Parsley[A => B]): Parsley[B] = lift.lift2[A, A=>B, B]((x, f) => f(x), this, pf)
/** This combinator, pronounced "then", first parses this parser then parses `q`: if both succeed then the result
* of `q` is returned.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `y` is returned and `x` is ignored. If either fail then the entire combinator fails.
*
* ''Identical to `~>`: `*>` is more common in Haskell, whereas `~>` is more common in Scala.''
*
* @example {{{
* scala> import parsley.character.char
* scala> ('a' *> 'b').parse("ab")
* val res0 = Success('b')
* }}}
*
* @param q the parser to run second, which returns the result of this combinator.
* @return a parser that sequences this parser with `q` and returns `q`'s result.
* @group seq
*/
def *>[B](q: =>Parsley[B]): Parsley[B] = new Parsley(new frontend.*>(this.internal, q.internal))
/** This combinator, pronounced "then discard", first parses this parser then parses `q`: if both succeed then the result
* of this parser is returned.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `x` is returned and `y` is ignored. If either fail then the entire combinator fails.
*
* ''Identical to `<~`: `<*` is more common in Haskell, whereas `<~` is more common in Scala.''
*
* @example {{{
* scala> import parsley.character.char
* scala> ('a' <* 'b').parse("ab")
* val res0 = Success('a')
* }}}
*
* @param q the parser to run second, which returns the result of this combinator.
* @return a parser that sequences this parser with `q` and returns this parser's result.
* @group seq
*/
def <*[B](q: =>Parsley[B]): Parsley[A] = new Parsley(new frontend.<*(this.internal, q.internal))
/** This combinator, pronounced "then", first parses this parser then parses `q`: if both succeed then the result
* of `q` is returned.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `y` is returned and `x` is ignored. If either fail then the entire combinator fails.
*
* ''Identical to `*>`: `*>` is more common in Haskell, whereas `~>` is more common in Scala.''
*
* @example {{{
* scala> import parsley.character.char
* scala> ('a' ~> 'b').parse("ab")
* val res0 = Success('b')
* }}}
*
* @param q the parser to run second, which returns the result of this combinator.
* @return a parser that sequences this parser with `q` and returns `q`'s result.
* @since 2.4.0
* @group seq
*/
def ~>[B](q: =>Parsley[B]): Parsley[B] = this *> q
/** This combinator, pronounced "then discard", first parses this parser then parses `q`: if both succeed then the result
* of this parser is returned.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `x` is returned and `y` is ignored. If either fail then the entire combinator fails.
*
* ''Identical to `<*`: `<*` is more common in Haskell, whereas `<~` is more common in Scala.''
*
* @example {{{
* scala> import parsley.character.char
* scala> ('a' <~ 'b').parse("ab")
* val res0 = Success('a')
* }}}
*
* @param q the parser to run second, which returns the result of this combinator.
* @return a parser that sequences this parser with `q` and returns this parser's result.
* @since 2.4.0
* @group seq
*/
def <~[B](q: =>Parsley[B]): Parsley[A] = this <* q
/** This combinator, pronounced "prepend", first parses this parser then parses `ps`: if both succeed the result of this
* parser is prepended onto the result of `ps`.
*
* First, this parser is ran, yielding `x` on success, then `ps` is ran, yielding `xs` on success. If both
* are successful then `x +: xs` is returned. If either fail then the entire combinator fails.
*
* @example {{{
* def some[A](p: Parsley[A]): Parsley[List[A]] = {
* p <+:> many(p) // since List[A] <: Seq[A]
* }
* }}}
*
* @param ps the parser to run second, which returns a sequence.
* @tparam Aʹ the type of the elements in the result sequence, which must be a supertype of
* the result type of this parser: this allows for weakening of the result type.
* @return a parser that sequences this parser with `ps` and prepends its result onto `ps` result.
* @note equivalent to {{{lift2(_ +: _, this, ps)}}}
* @group seq
*/
def <+:>[Aʹ >: A](ps: =>Parsley[Seq[Aʹ]]): Parsley[Seq[Aʹ]] = lift.lift2[A, Seq[Aʹ], Seq[Aʹ]](_ +: _, this, ps)
/** This combinator, pronounced "cons", first parses this parser then parses `ps`: if both succeed the result of this
* parser is prepended onto the result of `ps`.
*
* First, this parser is ran, yielding `x` on success, then `ps` is ran, yielding `xs` on success. If both
* are successful then `x :: xs` is returned. If either fail then the entire combinator fails.
*
* @example {{{
* def some[A](p: Parsley[A]): Parsley[List[A]] = {
* p <::> many(p)
* }
* }}}
*
* @param ps the parser to run second, which returns a list.
* @tparam Aʹ the type of the elements in the result list, which must be a supertype of
* the result type of this parser: this allows for weakening of the result type.
* @return a parser that sequences this parser with `ps` and prepends its result onto `ps` result.
* @note equivalent to {{{lift2(_ :: _, this, ps)}}}
* @group seq
*/
def <::>[Aʹ >: A](ps: =>Parsley[List[Aʹ]]): Parsley[List[Aʹ]] = lift.lift2[A, List[Aʹ], List[Aʹ]](_ :: _, this, ps)
/** This combinator, pronounced "zip", first parses this parser then parses `q`: if both succeed the result of this
* parser is paired with the result of `q`.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `(x, y)` is returned. If either fail then the entire combinator fails.
*
* @example {{{
* scala> import parsley.character.char
* scala> val p = char('a') <~> char('b')
* scala> p.parse("ab")
* val res0 = Success(('a', 'b'))
* scala> p.parse("b")
* val res1 = Failure(..)
* scala> p.parse("a")
* val res2 = Failure(..)
* }}}
*
* @param q the parser to run second.
* @return a parser that sequences this parser with `q` and pairs their results together.
* @note equivalent to {{{lift2((_, _), this, q)}}}
* @group seq
*/
def <~>[B](q: =>Parsley[B]): Parsley[(A, B)] = lift.lift2[A, B, (A, B)]((_, _), this, q)
/** This combinator first parses this parser then parses `q`: if both succeed the result of this
* parser is paired with the result of `q`.
*
* First, this parser is ran, yielding `x` on success, then `q` is ran, yielding `y` on success. If both
* are successful then `(x, y)` is returned. If either fail then the entire combinator fails.
*
* @example {{{
* scala> import parsley.character.char
* scala> val p = char('a').zip(char('b'))
* scala> p.parse("ab")
* val res0 = Success(('a', 'b'))
* scala> p.parse("b")
* val res1 = Failure(..)
* scala> p.parse("a")
* val res2 = Failure(..)
* }}}
*
* @param q the parser to run second.
* @return a parser that sequences this parser with `q` and pairs their results together.
* @note alias for `<~>`.
* @since 2.3.0
* @group seq
*/
def zip[B](q: =>Parsley[B]): Parsley[(A, B)] = this <~> q
// FILTERING COMBINATORS
/** This combinator filters the result of this parser using a given predicate, succeeding only if the predicate returns `true`.
*
* First, parse this parser. If it succeeds then take its result `x` and apply it to the predicate `pred`. If `pred(x)` is
* true, then return `x`. Otherwise, the combinator fails.
*
* @example {{{
* scala> import parsley.character.letter
* scala> val keywords = Set("if", "then", "else")
* scala> val identifier = some(letter).map(_.mkString)
* .filter(!keywords.contains(_))
* scala> identifier.parse("hello")
* val res0 = Success("hello")
* scala> idenfitier.parse("if")
* val res1 = Failure(..)
* }}}
*
* @param pred the predicate that is tested against the parser result.
* @return a parser that returns the result of this parser if it passes the predicate.
* @see [[parsley.errors.combinator.ErrorMethods.filterOut `filterOut`]] for a version which can produce custom ''reasons'' on failure.
* @see [[parsley.errors.combinator.ErrorMethods.guardAgainst `guardAgainst`]] for a version which can produce custom error messages on failure.
* @note $autoAmend
* @group filter
*/
def filter(pred: A => Boolean): Parsley[A] = new Parsley(new frontend.Filter(this.internal, pred))
/** This combinator filters the result of this parser using a given predicate, succeeding only if the predicate returns `false`.
*
* First, parse this parser. If it succeeds then take its result `x` and apply it to the predicate `pred`. If `pred(x) is
* false, then return `x`. Otherwise, the combinator fails.
*
* @example {{{
* scala> import parsley.character.letter
* scala> val keywords = Set("if", "then", "else")
* scala> val identifier = some(letter).map(_.mkString)
* .filterNot(keywords.contains(_))
* scala> identifier.parse("hello")
* val res0 = Success("hello")
* scala> idenfitier.parse("if")
* val res1 = Failure(..)
* }}}
*
* @param pred the predicate that is tested against the parser result.
* @return a parser that returns the result of this parser if it fails the predicate.
* @see [[parsley.errors.combinator.ErrorMethods.filterOut `filterOut`]] for a version that can produce custom ''reasons'' on failure.
* @see [[parsley.errors.combinator.ErrorMethods.guardAgainst `guardAgainst`]] for a version that can produce custom error messages on failure.
* @note $autoAmend
* @group filter
*/
def filterNot(pred: A => Boolean): Parsley[A] = this.filter(!pred(_))
/** This combinator applies a partial function `pf` to the result of this parser if its result
* is defined for `pf`, failing if it is not.
*
* First, parse this parser. If it succeeds, test whether its result `x` is in the
* domain of the partial function `pf`. If it is defined for `pf`, return `pf(x)`.
* If it is undefined, or this parser failed, then this combinator fails. Equivalent
* to a `filter` followed by a `map`.
*
* @example {{{
* scala> val int: Parsley[Int] = ..
* scala> val safeDiv: Parsley[Int] = (int <~> char(' ') *> int).collect {
* case (x, y) if y != 0 => x / y
* }
* scala> safeDiv.parse("7 0")
* val res0 = Failure(..) // y cannot be 0!
* scala> safeDiv.parse("10 2")
* val res1 = Success(5)
* }}}
*
* @param pf the partial function used to both filter the result of this parser and transform it.
* @return a parser that returns the result of this parser applied to `pf`, if possible.
* @see [[parsley.errors.combinator.ErrorMethods.collectMsg[B](msg0:String,msgs:String*)* `collectMsg(String, String*)`]]
* and [[parsley.errors.combinator.ErrorMethods.collectMsg[B](msggen:A=>Seq[String])* `collectMsg(A => Seq[String])`]]
* for versions that can produce custom error messages on failure.
* @since 2.0.0
* @note $autoAmend
* @group filter
*/
def collect[B](pf: PartialFunction[A, B]): Parsley[B] = this.mapFilter(pf.lift)
/** This combinator applies a function `f` to the result of this parser: if it returns a
* `Some(y)`, `y` is returned, otherwise the parser fails.
*
* First, parse this parser. If it succeeds, apply the function `f` to the result `x`. If
* `f(x)` returns `Some(y)`, return `y`. If `f(x)` returns `None`, or this parser failed
* then this combinator fails. Is a more efficient way of performing a `filter` and `map`
* at the same time.
*
* @example {{{
* scala> val int: Parsley[Int] = ..
* scala> val safeDiv: Parsley[Int] = (int <~> char(' ') *> int).collect {
* case (x, y) if y != 0 => Some(x / y)
* case _ => None
* }
* scala> safeDiv.parse("7 0")
* val res0 = Failure(..) // y cannot be 0!
* scala> safeDiv.parse("10 2")
* val res1 = Success(5)
* }}}
*
* @param f the function used to both filter the result of this parser and transform it.
* @return a parser that returns the result of this parser applied to `f`, if it yields a value.
* @since 4.0.0
* @note $autoAmend
* @group filter
*/
def mapFilter[B](f: A => Option[B]): Parsley[B] = new Parsley(new frontend.MapFilter(this.internal, f))
// FOLDING COMBINATORS
/** This combinator will parse this parser '''zero''' or more times combining the results with the function `f` and base value `k` from the right.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a right-to-left
* fashion using the function `f`: the right-most value provided to `f` is the value `k`.
* If this parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* // in reality, many is implemented more efficiently
* def many[A](p: Parsley[A]) = {
* p.foldRight(List.empty[A])(_ :: _)
* }
* }}}
*
* @param k value to use when this parser no longer succeeds.
* @param f function to apply to each value produced by this parser, starting at the right.
* @return a parser which parses this parser many times and folds the results together with `f` and `k` right-associatively.
* @group fold
*/
def foldRight[B](k: B)(f: (A, B) => B): Parsley[B] = chain.prefix(this.map(f.curried), pure(k))
/** This combinator will parse this parser '''zero''' or more times combining the results with the function `f` and base value `k` from the left.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a left-to-right
* fashion using the function `f`: the accumulation is initialised with the value `k`.
* If this parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* // this is not an efficient implementation of stringOfMany
* def stringOfMany(pc: Parsley[Char]): Parsley[String] = {
* pc.foldLeft("")(_ + _)
* }
* }}}
*
* @param k initial accumulation value.
* @param f function to apply to each iteration's accumulator.
* @return a parser which parses this parser many times and folds the results together with `f` and `k` left-associatively.
* @group fold
*/
def foldLeft[B](k: B)(f: (B, A) => B): Parsley[B] = expr.infix.secretLeft1(pure(k), this, pure(f))
/** This combinator will parse this parser '''one''' or more times combining the results with the function `f` and base value `k` from the right.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a right-to-left
* fashion using the function `f`: the right-most value provided to `f` is the value `k`.
* If this parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* // in reality, some is implemented more efficiently
* def some[A](p: Parsley[A]) = {
* p.foldRight1(List.empty[A])(_ :: _)
* }
* }}}
*
* @param k value to use when this parser no longer succeeds.
* @param f function to apply to each value produced by this parser, starting at the right.
* @return a parser which parses this parser some times and folds the results together with `f` and `k` right-associatively.
* @since 2.1.0
* @group fold
*/
def foldRight1[B](k: B)(f: (A, B) => B): Parsley[B] = {
lift.lift2(f, this, this.foldRight(k)(f))
}
/** This combinator will parse this parser '''one''' or more times combining the results with the function `f` and base value `k` from the left.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a left-to-right
* fashion using the function `f`: the accumulation is initialised with the value `k`.
* If this parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* val natural: Parsley[Int] = digit.foldLeft1(0)((x, d) => x * 10 + d.toInt)
* }}}
*
* @param k initial accumulation value.
* @param f function to apply to each iteration's accumulator.
* @return a parser which parses this parser some times and folds the results together with `f` and `k` left-associatively.
* @since 2.1.0
* @group fold
*/
def foldLeft1[B](k: B)(f: (B, A) => B): Parsley[B] = expr.infix.secretLeft1(this.map(f(k, _)), this, pure(f))
/** This combinator will parse this parser '''one''' or more times combining the results right-associatively with the function `op`.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a right-to-left
* fashion using the function `op`. If this parser does fail at any point having consumed input,
* this combinator will fail.
*
* @example {{{
* stmt.reduceRight(Seq(_, _))
* }}}
*
* @param op function to apply to each value produced by this parser, starting from the right.
* @return a parser which parses this parser some times and folds the results together with `op` right-associatively.
* @since 2.3.0
* @group fold
*/
def reduceRight[B >: A](op: (A, B) => B): Parsley[B] = some(this).map(_.reduceRight(op))
/** This combinator will parse this parser '''zero''' or more times combining the results right-associatively with the function `op`.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* If this parser succeeded at least once, all of the results generated by the successful
* parses are then combined in a right-to-left fashion using the function `op` and returned
* in a `Some`. If no successful parses occurred, then `None` is returned. If this
* parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* arg.reduceRightOption(Sep(_, _))
* }}}
*
* @param op function to apply to each value produced by this parser, starting from the right.
* @return a parser which parses this parser many times and folds the results together with `op` right-associatively or returns None if no parses occured.
* @since 2.3.0
* @group fold
*/
def reduceRightOption[B >: A](op: (A, B) => B): Parsley[Option[B]] = option(this.reduceRight(op))
/** This combinator will parse this parser '''one''' or more times combining the results left-associatively with the function `op`.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* All of the results generated by the successful parses are then combined in a left-to-right
* fashion using the function `op`. If this parser does fail at any point having consumed input,
* this combinator will fail.
*
* @example {{{
* stmt.reduceLeft(Seq(_, _))
* }}}
*
* @param op function to apply to each value produced by this parser, starting from the left.
* @return a parser which parses this parser some times and folds the results together with `op` left-associatively.
* @since 2.3.0
* @group fold
*/
def reduceLeft[B >: A](op: (B, A) => B): Parsley[B] = infix.left1(this, pure(op))
/** This combinator will parse this parser '''zero''' or more times combining the results left-associatively with the function `op`.
*
* This parser will continue to be parsed until it fails having '''not consumed''' input.
* If this parser succeeded at least once, all of the results generated by the successful
* parses are then combined in a left-to-right fashion using the function `op` and returned
* in a `Some`. If no successful parses occurred, then `None` is returned. If this
* parser does fail at any point having consumed input, this combinator will fail.
*
* @example {{{
* arg.reduceLeftOption(Sep(_, _))
* }}}
*
* @param op function to apply to each value produced by this parser, starting from the left.
* @return a parser which parses this parser many times and folds the results together with `op` left-associatively or returns None if no parses occured.
* @since 2.3.0
* @group fold
*/
def reduceLeftOption[B >: A](op: (B, A) => B): Parsley[Option[B]] = option(this.reduceLeft(op))
// EXPENSIVE SEQUENCING COMBINATORS
/** This combinator $bind
*
* ''In Haskell, this combinator is known as `(>>=)` (pronounced "bind")''.
*
* @example {{{
* // this is an inefficient implementation, but does work
* def filter(pred: A => Boolean): Parsley[A] = {
* this.flatMap { x =>
* if (pred(x)) pure(x)
* else empty
* }
* }
* }}}
*
* @note there is '''significant''' overhead for using `flatMap`: if possible try to avoid using it! This
* is because Parsley will need to generate, process, and compile each parser produced by the combinator
* during parse-time.
* @param f the function that produces the next parser.
* @return a new parser, which sequences this parser with the parser generated from its result.
* @group monad
*/
def flatMap[B](f: A => Parsley[B]): Parsley[B] = new Parsley(new frontend.>>=(this.internal, f.andThen(_.internal)))
/** This combinator, pronounced "bind", $bind
*
* @example {{{
* // this is an inefficient implementation, but does work
* def filter(pred: A => Boolean): Parsley[A] = {
* this >>= { x =>
* if (pred(x)) pure(x)
* else empty
* }
* }
* }}}
*
* @note there is '''significant''' overhead for using `>>=`: if possible try to avoid using it! This
* is because Parsley will need to generate, process, and compile each parser produced by the combinator
* during parse-time.
* @param f the function that produces the next parser.
* @return a new parser, which sequences this parser with the parser generated from its result.
* @group monad
*/
def >>=[B](f: A => Parsley[B]): Parsley[B] = this.flatMap(f)
/** This combinator collapses two layers of parsing structure into one.
*
* The implicit (compiler-provided) evidence proves that this parser really has type `Parsley[Parsley[B]]`.
* First, this parser is executed, which, if successful, will produce a new parser `p`. The parser `p` is
* then executed, and its result is returned. If either this parser or `p` fail, then the entire combinator
* fails.
*
* This is a very powerful combinator (Turing-powerful, in fact): it is only necessary (and not ''all''
* the time) to use this for context-sensitive parsing. The idea is that it can allow a parser to return
* any other parser as its result: this allows for an implementation of a later parser to be picked
* by an earlier one.
*
* ''In Haskell, this combinator is known as `join`''.
*
* @example imagine a parser for RegEx that first reads the description of the regular expression, then runs
* that against the remaining input string. It is possible to implement the parser for the regular
* expression itself as a `Parsley[Parsley[Unit]]`, which returns a parser that matches the regular
* expression. This can then be used to parse the remaining input by using `flatten` to incorporate
* it into the parser again:
* {{{
* scala> val regexDesc: Parsley[Parsley[Unit]] = ..
* // let's suppose "#" is the delimeter between expression and input
* scala> val regex: Parsley[Unit] = (regexDesc <* char('#')).flatten
* scala> regex.parse("a.(c*)#abccc")
* val res0 = Success(())
* scala> regex.parse("a.(c*)#a")
* val res1 = Failure(..)
* }}}
*
* @param ev witnesses that the result type of this parser, `A`, is really `Parsley[B]`.
* @return a new parser, which sequences this parser with its result parser.
* @note there is '''significant''' overhead for using `flatten`: if possible try to avoid using it! This
* is because Parsley will need to generate, process, and compile each parser produced by the combinator
* during parse-time.
* @group monad
*/
def flatten[B](implicit ev: A <:< Parsley[B]): Parsley[B] = this.flatMap[B](ev)
// SPECIAL METHODS
// $COVERAGE-OFF$
/** Forces the compilation of a parser as opposed to the regular lazy evaluation.
*
* @group special
*/
def force(): Unit = internal.force()
/** Provides an indicator that this parser will likely stack-overflow and so a stack-safe
* construction should be used when "compiling" this parser.
*
* @group special
*/
def overflows(): Unit = internal.overflows()
/** Using this method signifies that the parser it is invoked on is impure and any optimisations which assume purity
* are disabled.
*
* @group special
*/
def unsafe(): Parsley[A] = {
internal.unsafe()
this
}
// $COVERAGE-ON$
// $COVERAGE-OFF$
/** This is an alias for `p.filter(pred)`. It is needed to support for-comprehension syntax with `if`s.
*
* @since 4.0.0
* @see [[parsley.Parsley.filter `filter`]] for more information.
*/
def withFilter(pred: A => Boolean): Parsley[A] = this.filter(pred)
// $COVERAGE-ON$
}
/** This object contains the core "function-style" combinators: all parsers will likely require something from within!
*
* In particular, it contains combinators for: controlling how input is consumed; injecting values into
* the parser, or failing; extracting position information from the parser; conditional execution of
* parsers; and more.
*
* @groupprio cond 25
* @groupname cond Conditional Combinators
* @groupdesc cond
* These combinators will decide which branch to take next based on the result of another parser.
* This differs from combinators like `<|>` which make decisions based on the success/failure of
* a parser: here the result of a ''successful'' parse will direct which option is done. These
* are sometimes known as "selective" combinators.
*
* @groupprio prim 0
* @groupname prim Primitive Combinators
* @groupdesc prim
* These combinators are specific to parser combinators. In one way or another, they influence how a
* parser consumes input, or under what conditions a parser does or does not fail. These are really
* important for most practical parsing considerations, although `lookAhead` is much less well used.
*
* @groupprio basic 5
* @groupname basic Consumptionless Parsers
* @groupdesc basic
* These combinators and parsers do not consume input: they are the most primitive ways of producing
* successes and failures with the minimal possible effect on the parse. They are, however, reasonably
* useful; in particular, `pure` and `unit` can be put to good use in injecting results into a parser
* without needing to consume anything, or mapping another parser.
*
* @groupprio pos 10
* @groupname pos Position-Tracking Parsers
* @groupdesc pos
* These parsers provide a way to extract position information during a parse. This can be important
* for when the final result of the parser needs to encode position information for later consumption:
* this is particularly useful for abstract syntax trees.
*
* @groupprio monad 100
* @groupname monad Expensive Sequencing Combinators
* @groupdesc monad
* These combinators can sequence two parsers, where the first parser's result influences
* the structure of the second one. This may be because the second parser is generated
* from the result of the first, or that the first parser ''returns'' the second parser.
* Either way, the second parser cannot be known until runtime, when the first parser
* has been executed: this means that Parsley is forced to compile the second parser during
* parse-time, which is '''very''' expensive to do repeatedly. These combinators are only
* needed in exceptional circumstances, and should be avoided otherwise.
*/
object Parsley {
/** This class enables the prefix `~` combinator, which allows a parser in an otherwise strict
* position to be made lazy.
*
* @constructor This constructor should not be called manually, it is designed to be used via Scala's implicit resolution.
* @param p the parser that `~` is enabled on.
* @since 4.0.0
*/
implicit final class LazyParsley[A](p: =>Parsley[A]) {
/** This combinator makes a parser lazy.
*
* There are some combinators that are, due to Scala limitations,
* strict in all their parameters. Usually, a combinator is strict
* in its "first position", which is to say the first part of the
* combinator to be executed; and lazy in all other "positions".
* The rationale behind this is that recursion appearing in a
* "first position" ''will'' result in infinite recursion at parse-time,
* it is left-recursive after all, and so it makes little sense to
* waste efficiency and complicate the API to support laziness
* there. Since method receivers are strict and only
* arguments can be lazy under regular conditions, this works well.
*
* However, for combinators that are always strict, this poses a
* problem: a recursion point inside one of these strict fields
* will cause an infinite loop at runtime! This can be fixed by
* ensuring that this becomes part of a lazy argument. This is
* a solution described by the [[combinator.skip `skip`]]
* combinator, for instance: `p *> skip(q, .., r)` will ensure
* that the `skip` is in a lazy position in `*>` meaning that
* even if any of `q` to `r` must be lazy, they can go in the strict
* positions of skip because the `p *>` provides the required
* laziness. However, if this isn't possible (for instance, with
* the [[implicits.zipped `zipped`]] combinators), then how can
* this problem be solved?
*
* This is the job of the `~` combinator: very simply it wraps up