@@ -136,14 +136,22 @@ trait Parsers {
136
136
* @param result The parser's output
137
137
* @param next The parser's remaining input
138
138
*/
139
- case class Success [+ T ](result : T , override val next : Input ) extends ParseResult [T ] {
140
- def map [U ](f : T => U ) = Success (f(result), next)
141
- def mapPartial [U ](f : PartialFunction [T , U ], error : T => String ): ParseResult [U ]
142
- = if (f.isDefinedAt(result)) Success (f(result), next)
143
- else Failure (error(result), next)
139
+ abstract case class Success [+ T ](result : T , override val next : Input ) extends ParseResult [T ] {
140
+ val lastFailure : Option [Failure ]
144
141
145
- def flatMapWithNext [U ](f : T => Input => ParseResult [U ]): ParseResult [U ]
146
- = f(result)(next)
142
+ def map [U ](f : T => U ) = Success (f(result), next, lastFailure)
143
+
144
+ def mapPartial [U ](f : PartialFunction [T , U ], error : T => String ): ParseResult [U ] =
145
+ if (f.isDefinedAt(result)) Success (f(result), next, lastFailure)
146
+ else Failure (error(result), next)
147
+
148
+ def flatMapWithNext [U ](f : T => Input => ParseResult [U ]): ParseResult [U ] = f(result)(next) match {
149
+ case s @ Success (result, rest) =>
150
+ val failure = selectLastFailure(this .lastFailure, s.lastFailure)
151
+ Success (result, rest, failure)
152
+ case f : Failure => selectLastFailure(Some (f), lastFailure).get
153
+ case e : Error => e
154
+ }
147
155
148
156
def filterWithError (p : T => Boolean , error : T => String , position : Input ): ParseResult [T ] =
149
157
if (p(result)) this
@@ -192,10 +200,16 @@ trait Parsers {
192
200
/** The toString method of a Failure yields an error message. */
193
201
override def toString = s " [ ${next.pos}] failure: $msg\n\n ${next.pos.longString}"
194
202
195
- def append [U >: Nothing ](a : => ParseResult [U ]): ParseResult [U ] = { val alt = a; alt match {
196
- case Success (_, _) => alt
197
- case ns : NoSuccess => if (alt.next.pos < next.pos) this else alt
198
- }}
203
+ def append [U >: Nothing ](a : => ParseResult [U ]): ParseResult [U ] = {
204
+ val alt = a
205
+
206
+ alt match {
207
+ case s @ Success (result, rest) =>
208
+ val failure = selectLastFailure(Some (this ), s.lastFailure)
209
+ Success (result, rest, failure)
210
+ case ns : NoSuccess => if (alt.next.pos < next.pos) this else alt
211
+ }
212
+ }
199
213
}
200
214
201
215
/** The fatal failure case of ParseResult: contains an error-message and
@@ -214,6 +228,19 @@ trait Parsers {
214
228
def Parser [T ](f : Input => ParseResult [T ]): Parser [T ]
215
229
= new Parser [T ]{ def apply (in : Input ) = f(in) }
216
230
231
+ private [combinator] def Success [U ](res : U , next : Input , failure : Option [Failure ]): ParseResult [U ] =
232
+ new Success (res, next) { override val lastFailure : Option [Failure ] = failure }
233
+
234
+ private [combinator] def selectLastFailure (failure0 : Option [Failure ], failure1 : Option [Failure ]): Option [Failure ] =
235
+ (failure0, failure1) match {
236
+ case (Some (f0), Some (f1)) =>
237
+ if (f0.next.pos < f1.next.pos) Some (f1)
238
+ else Some (f0)
239
+ case (Some (f0), _) => Some (f0)
240
+ case (_, Some (f1)) => Some (f1)
241
+ case _ => None
242
+ }
243
+
217
244
def OnceParser [T ](f : Input => ParseResult [T ]): Parser [T ] with OnceParser [T ]
218
245
= new Parser [T ] with OnceParser [T ] { def apply (in : Input ) = f(in) }
219
246
@@ -633,7 +660,7 @@ trait Parsers {
633
660
*/
634
661
def acceptIf (p : Elem => Boolean )(err : Elem => String ): Parser [Elem ] = Parser { in =>
635
662
if (in.atEnd) Failure (" end of input" , in)
636
- else if (p(in.first)) Success (in.first, in.rest)
663
+ else if (p(in.first)) Success (in.first, in.rest, None )
637
664
else Failure (err(in.first), in)
638
665
}
639
666
@@ -652,7 +679,7 @@ trait Parsers {
652
679
*/
653
680
def acceptMatch [U ](expected : String , f : PartialFunction [Elem , U ]): Parser [U ] = Parser { in =>
654
681
if (in.atEnd) Failure (" end of input" , in)
655
- else if (f.isDefinedAt(in.first)) Success (f(in.first), in.rest)
682
+ else if (f.isDefinedAt(in.first)) Success (f(in.first), in.rest, None )
656
683
else Failure (expected+ " expected" , in)
657
684
}
658
685
@@ -685,7 +712,7 @@ trait Parsers {
685
712
* @param v The result for the parser
686
713
* @return A parser that always succeeds, with the given result `v`
687
714
*/
688
- def success [T ](v : T ) = Parser { in => Success (v, in) }
715
+ def success [T ](v : T ) = Parser { in => Success (v, in, None ) }
689
716
690
717
/** A helper method that turns a `Parser` into one that will
691
718
* print debugging information to stdout before and after
@@ -750,19 +777,24 @@ trait Parsers {
750
777
lazy val p = p0 // lazy argument
751
778
val elems = new ListBuffer [T ]
752
779
753
- def continue (in : Input ): ParseResult [List [T ]] = {
780
+ def continue (in : Input , failure : Option [ Failure ] ): ParseResult [List [T ]] = {
754
781
val p0 = p // avoid repeatedly re-evaluating by-name parser
755
- @ tailrec def applyp (in0 : Input ): ParseResult [List [T ]] = p0(in0) match {
756
- case Success (x, rest) => elems += x ; applyp(rest)
782
+ @ tailrec def applyp (in0 : Input , failure : Option [Failure ]): ParseResult [List [T ]] = p0(in0) match {
783
+ case s @ Success (x, rest) =>
784
+ val selectedFailure = selectLastFailure(s.lastFailure, failure)
785
+ elems += x
786
+ applyp(rest, selectedFailure)
757
787
case e @ Error (_, _) => e // still have to propagate error
758
- case _ => Success (elems.toList, in0)
788
+ case f : Failure =>
789
+ val selectedFailure = selectLastFailure(failure, Some (f))
790
+ Success (elems.toList, in0, selectedFailure)
759
791
}
760
792
761
- applyp(in)
793
+ applyp(in, failure )
762
794
}
763
795
764
796
first(in) match {
765
- case Success (x, rest) => elems += x ; continue(rest)
797
+ case s @ Success (x, rest) => elems += x ; continue(rest, s.lastFailure )
766
798
case ns : NoSuccess => ns
767
799
}
768
800
}
@@ -782,14 +814,14 @@ trait Parsers {
782
814
val elems = new ListBuffer [T ]
783
815
val p0 = p // avoid repeatedly re-evaluating by-name parser
784
816
785
- @ tailrec def applyp (in0 : Input ): ParseResult [List [T ]] =
786
- if (elems.length == num) Success (elems.toList, in0)
817
+ @ tailrec def applyp (in0 : Input , failure : Option [ Failure ] ): ParseResult [List [T ]] =
818
+ if (elems.length == num) Success (elems.toList, in0, failure )
787
819
else p0(in0) match {
788
- case Success (x, rest) => elems += x ; applyp(rest)
820
+ case s @ Success (x, rest) => elems += x ; applyp(rest, s.lastFailure )
789
821
case ns : NoSuccess => ns
790
822
}
791
823
792
- applyp(in)
824
+ applyp(in, None )
793
825
}
794
826
795
827
/** A parser generator for non-empty repetitions.
@@ -871,7 +903,7 @@ trait Parsers {
871
903
def not [T ](p : => Parser [T ]): Parser [Unit ] = Parser { in =>
872
904
p(in) match {
873
905
case Success (_, _) => Failure (" Expected failure" , in)
874
- case _ => Success ((), in)
906
+ case _ => Success ((), in, None )
875
907
}
876
908
}
877
909
@@ -885,7 +917,7 @@ trait Parsers {
885
917
*/
886
918
def guard [T ](p : => Parser [T ]): Parser [T ] = Parser { in =>
887
919
p(in) match {
888
- case s@ Success (s1,_) => Success (s1, in)
920
+ case s@ Success (s1,_) => Success (s1, in, s.lastFailure )
889
921
case e => e
890
922
}
891
923
}
@@ -900,7 +932,7 @@ trait Parsers {
900
932
*/
901
933
def positioned [T <: Positional ](p : => Parser [T ]): Parser [T ] = Parser { in =>
902
934
p(in) match {
903
- case Success (t, in1) => Success (if (t.pos == NoPosition ) t setPos in.pos else t, in1)
935
+ case s @ Success (t, in1) => Success (if (t.pos == NoPosition ) t setPos in.pos else t, in1, s.lastFailure )
904
936
case ns : NoSuccess => ns
905
937
}
906
938
}
@@ -918,7 +950,10 @@ trait Parsers {
918
950
def apply (in : Input ) = p(in) match {
919
951
case s @ Success (out, in1) =>
920
952
if (in1.atEnd) s
921
- else Failure (" end of input expected" , in1)
953
+ else s.lastFailure match {
954
+ case Some (failure) => failure
955
+ case _ => Failure (" end of input expected" , in1)
956
+ }
922
957
case ns => ns
923
958
}
924
959
}
0 commit comments