Skip to content

Combinator Parsing library: parser generator rep1 doesn't propagate errors #1100

Closed
@scabug

Description

@scabug

Parser generator

def rep1[T](first: => Parser[T], p: => Parser[T]): Parser[List[T]]

in scala.util.parsing.combinator.Parsers never returns error. So if first or p parser returns error this error is not propagated further.

It is almost obvious from code of this method:

  def rep1[T](first: => Parser[T], p: => Parser[T]): Parser[List[T]] = Parser{ in0 =>
    val xs = new scala.collection.mutable.ListBuffer[T]
    var in = in0

    var res = first(in)

    while(res.successful) {
      xs += res.get
      in = res.next
      res = p(in)
    }

    // assert(res.isInstanceOf[NoSuccess])

    if (!xs.isEmpty) {
      // the next parser should start parsing where p failed, 
      // since `!p(in).successful', the next input to be consumed is `in'
      Success(xs.toList, in)  // TODO: I don't think in == res.next holds
    }
    else {
      Failure(res.asInstanceOf[NoSuccess].msg, in0)
    }
  }

Suppose that after while finished res is an Error. This error is not propagated further - the result of rep1 depends only on emptiness of list xs!

res should be tested. The implementation of this method should be changed to something like this:

  def rep1[T](first: => Parser[T], p: => Parser[T]): Parser[List[T]] = Parser{ in0 =>
    val xs = new scala.collection.mutable.ListBuffer[T]
    var in = in0
    var res = first(in)
    while(res.successful) {
      xs += res.get
      in = res.next
      res = p(in)
    }
    
    res match {
      case e: Error => e
      case _  => if (!xs.isEmpty) Success(xs.toList, in) else Failure(res.asInstanceOf[NoSuccess].msg, in0) 
    }
  }

As a result of incorrect rep1, combinators * and + work also incorrectly (they finally call mentioned method).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions