Skip to content

Commit

Permalink
Error rework: Patch (#62)
Browse files Browse the repository at this point in the history
* Moved the newline stripping to a more sensible place

* Added temporary workaround for hard tabs...

* changed to character replace to avoid regex

* Hiding the internals from the scaladoc

* Removed stale hints when new hints are added, if we made it further in the input stream, old hints are useless

* Fixed bug where merging hints from labels promoted potentially stale hints to available
  • Loading branch information
j-mie6 authored Feb 8, 2021
1 parent 30e5c72 commit 010d557
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 18 deletions.
7 changes: 5 additions & 2 deletions src/main/scala/parsley/internal/instructions/Context.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,16 @@ private [parsley] final class Context(private [instructions] var instrs: Array[I
this.hintStack = this.hintStack.tail
}
private [instructions] def mergeHints(): Unit = {
this.hints ++= this.hintStack.head._2
val (hintsValidOffset, hints) = this.hintStack.head
if (hintsValidOffset == offset) this.hints ++= hints
commitHints()
}
private [instructions] def addErrorToHints(): Unit = errs.head match {
case TrivialError(errOffset, _, _, _, es) if errOffset == offset && es.nonEmpty =>
//println(s"$es have been hinted")
// If our new hints have taken place further in the input stream, then they must invalidate the old ones
if (hintsValidOffset < offset) hints.clear()
hintsValidOffset = offset
hints += new Hint(es)
case _ => //println(s"${errs.head} was not suitable for hinting")
}
Expand All @@ -120,7 +124,6 @@ private [parsley] final class Context(private [instructions] var instrs: Array[I
}

// $COVERAGE-OFF$
//override def toString: String = pretty
private [instructions] def pretty: String = {
s"""[
| stack = [${stack.mkString(", ")}]
Expand Down
31 changes: 15 additions & 16 deletions src/main/scala/parsley/internal/instructions/Errors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ParseError.Unknown
import Raw.Unprintable
import scala.util.matching.Regex

sealed trait ParseError {
private [internal] sealed trait ParseError {
val offset: Int
val col: Int
val line: Int
Expand Down Expand Up @@ -47,7 +47,7 @@ sealed trait ParseError {
val segment = helper.segmentBetween(startOffset, endOffset)
val caretAt = offset - startOffset
val caretPad = " " * caretAt
(segment, s"$caretPad^")
(segment.replace('\t', ' '), s"$caretPad^")
}

protected final def assemble(sourceName: Option[String], helper: Context#InputHelper, infoLines: List[String]): String = {
Expand All @@ -60,33 +60,32 @@ sealed trait ParseError {
| >${caret}""".stripMargin
}
}
case class TrivialError(offset: Int, line: Int, col: Int, unexpected: Option[ErrorItem], expecteds: Set[ErrorItem]) extends ParseError {
private [internal] case class TrivialError(offset: Int, line: Int, col: Int, unexpected: Option[ErrorItem], expecteds: Set[ErrorItem]) extends ParseError {
def withHints(hints: Iterable[Hint]): ParseError = copy(expecteds = hints.foldLeft(expecteds)((es, h) => es union h.hint))

def pretty(sourceName: Option[String], helper: Context#InputHelper): String = {
assemble(sourceName, helper, List(unexpectedInfo, expectedInfo).flatten)
}

private def unexpectedInfo: Option[String] = unexpected.map(u => s"unexpected ${u.msg.takeWhile(_ != '\n')}")
private def unexpectedInfo: Option[String] = unexpected.map(u => s"unexpected ${u.msg}")
private def expectedInfo: Option[String] = disjunct(expecteds.map(_.msg).toList).map(es => s"expected $es")
}
case class FailError(offset: Int, line: Int, col: Int, msgs: Set[String]) extends ParseError {
private [internal] case class FailError(offset: Int, line: Int, col: Int, msgs: Set[String]) extends ParseError {
def withHints(hints: Iterable[Hint]): ParseError = this
def pretty(sourceName: Option[String], helper: Context#InputHelper): String = {
assemble(sourceName, helper, msgs.toList)
}
}

object ParseError {
def unexpected(msg: String, offset: Int, line: Int, col: Int) = TrivialError(offset, line, col, Some(Desc(msg)), Set.empty)
def fail(msg: String, offset: Int, line: Int, col: Int) = FailError(offset, line, col, Set(msg))
private [internal] object ParseError {
def fail(msg: String, offset: Int, line: Int, col: Int): ParseError = FailError(offset, line, col, Set(msg))
val Unknown = "unknown parse error"
}

sealed trait ErrorItem {
private [internal] sealed trait ErrorItem {
val msg: String
}
object ErrorItem {
private [internal] object ErrorItem {
def higherPriority(e1: ErrorItem, e2: ErrorItem): ErrorItem = (e1, e2) match {
case (EndOfInput, _) => EndOfInput
case (_, EndOfInput) => EndOfInput
Expand All @@ -95,24 +94,24 @@ object ErrorItem {
case (Raw(r1), Raw(r2)) => if (r1.length >= r2.length) e1 else e2
}
}
case class Raw(cs: String) extends ErrorItem {
private [internal] case class Raw(cs: String) extends ErrorItem {
override val msg = cs match {
case "\n" => "newline"
case "\t" => "tab"
case " " => "space"
case Unprintable(up) => s"unprintable character (${up.head.toInt})"
case cs => "\"" + cs + "\""
case cs => "\"" + cs.takeWhile(_ != '\n') + "\""
}
}
object Raw {
private [internal] object Raw {
val Unprintable: Regex = "(\\p{C})".r
def apply(c: Char): Raw = new Raw(s"$c")
}
case class Desc(msg: String) extends ErrorItem
case object EndOfInput extends ErrorItem {
private [internal] case class Desc(msg: String) extends ErrorItem
private [internal] case object EndOfInput extends ErrorItem {
override val msg = "end of input"
}

final class Hint(val hint: Set[ErrorItem]) extends AnyVal {
private [instructions] final class Hint(val hint: Set[ErrorItem]) extends AnyVal {
override def toString: String = hint.toString
}

0 comments on commit 010d557

Please sign in to comment.