mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-05 22:55:58 +00:00
Improve parser error messages a bit
This commit is contained in:
parent
30c901ddf1
commit
b514b85f39
@ -18,7 +18,7 @@ object JSItemQueryParser {
|
|||||||
new Failure(
|
new Failure(
|
||||||
fr.input,
|
fr.input,
|
||||||
fr.failedAt,
|
fr.failedAt,
|
||||||
js.Array(fr.messages.toList.toSeq.map(_.msg): _*)
|
js.Array(fr.messages.toList.toSeq.map(_.render): _*)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.orNull
|
.orNull
|
||||||
|
@ -18,48 +18,79 @@ final case class ParseFailure(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
def render: String = {
|
def render: String = {
|
||||||
val items = messages.map(_.msg).toList.mkString(", ")
|
val items = messages.map(_.render).toList.mkString(", ")
|
||||||
s"Failed to read input near $failedAt: $input\nDetails: $items"
|
s"Failed to read input near $failedAt: $input\nDetails: $items"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ParseFailure {
|
object ParseFailure {
|
||||||
|
|
||||||
final case class Message(offset: Int, msg: String)
|
sealed trait Message {
|
||||||
|
def offset: Int
|
||||||
|
def render: String
|
||||||
|
}
|
||||||
|
final case class SimpleMessage(offset: Int, msg: String) extends Message {
|
||||||
|
def render: String =
|
||||||
|
s"Failed at $offset: $msg"
|
||||||
|
}
|
||||||
|
final case class ExpectMessage(offset: Int, expected: List[String], exhaustive: Boolean) extends Message {
|
||||||
|
def render: String = {
|
||||||
|
val opts = expected.mkString(", ")
|
||||||
|
val dots = if (exhaustive) "" else "…"
|
||||||
|
s"Expected: ${opts}${dots}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private[query] def fromError(input: String)(pe: Parser.Error): ParseFailure =
|
private[query] def fromError(input: String)(pe: Parser.Error): ParseFailure =
|
||||||
ParseFailure(
|
ParseFailure(
|
||||||
input,
|
input,
|
||||||
pe.failedAtOffset,
|
pe.failedAtOffset,
|
||||||
Parser.Expectation.unify(pe.expected).map(expectationToMsg)
|
packMsg(Parser.Expectation.unify(pe.expected).map(expectationToMsg))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private[query] def packMsg(msg: Nel[Message]): Nel[Message] = {
|
||||||
|
val expectMsg = combineExpected(msg.collect({ case em: ExpectMessage => em }))
|
||||||
|
.sortBy(_.offset).headOption
|
||||||
|
|
||||||
|
val simpleMsg = msg.collect({ case sm: SimpleMessage => sm })
|
||||||
|
|
||||||
|
Nel.fromListUnsafe((simpleMsg ++ expectMsg).sortBy(_.offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
private[query] def combineExpected(msg: List[ExpectMessage]): List[ExpectMessage] =
|
||||||
|
msg.groupBy(_.offset).map({ case (offset, es) =>
|
||||||
|
ExpectMessage(offset, es.flatMap(_.expected).distinct.sorted, es.forall(_.exhaustive))
|
||||||
|
}).toList
|
||||||
|
|
||||||
private[query] def expectationToMsg(e: Parser.Expectation): Message =
|
private[query] def expectationToMsg(e: Parser.Expectation): Message =
|
||||||
e match {
|
e match {
|
||||||
case StartOfString(offset) =>
|
case StartOfString(offset) =>
|
||||||
Message(offset, "Expected start of string")
|
SimpleMessage(offset, "Expected start of string")
|
||||||
|
|
||||||
case FailWith(offset, message) =>
|
case FailWith(offset, message) =>
|
||||||
Message(offset, message)
|
SimpleMessage(offset, message)
|
||||||
|
|
||||||
case InRange(offset, lower, upper) =>
|
case InRange(offset, lower, upper) =>
|
||||||
if (lower == upper) Message(offset, s"Expected character: $lower")
|
if (lower == upper) ExpectMessage(offset, List(lower.toString), true)
|
||||||
else Message(offset, s"Expected character from range: [$lower .. $upper]")
|
else {
|
||||||
|
val expect = s"${lower}-${upper}"
|
||||||
|
ExpectMessage(offset, List(expect), true)
|
||||||
|
}
|
||||||
|
|
||||||
case Length(offset, expected, actual) =>
|
case Length(offset, expected, actual) =>
|
||||||
Message(offset, s"Expected input of length $expected, but got $actual")
|
SimpleMessage(offset, s"Expected input of length $expected, but got $actual")
|
||||||
|
|
||||||
case ExpectedFailureAt(offset, matched) =>
|
case ExpectedFailureAt(offset, matched) =>
|
||||||
Message(offset, s"Expected failing, but matched '$matched'")
|
SimpleMessage(offset, s"Expected failing, but matched '$matched'")
|
||||||
|
|
||||||
case EndOfString(offset, length) =>
|
case EndOfString(offset, length) =>
|
||||||
Message(offset, s"Expected end of string at length: $length")
|
SimpleMessage(offset, s"Expected end of string at length: $length")
|
||||||
|
|
||||||
case Fail(offset) =>
|
case Fail(offset) =>
|
||||||
Message(offset, s"Failed to parse near $offset")
|
SimpleMessage(offset, s"Failed to parse near $offset")
|
||||||
|
|
||||||
case OneOfStr(offset, strs) =>
|
case OneOfStr(offset, strs) =>
|
||||||
val options = strs.mkString(", ")
|
val options = strs.take(8)
|
||||||
Message(offset, s"Expected one of the following strings: $options")
|
ExpectMessage(offset, options.take(7), options.size < 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user