Skip to content

Commit

Permalink
Merge pull request #144 from typelevel/fix/143
Browse files Browse the repository at this point in the history
Fix #143
  • Loading branch information
travisbrown authored Jan 5, 2019
2 parents 6860b30 + ffb3170 commit 6388d6f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 1 deletion.
19 changes: 18 additions & 1 deletion parser/src/main/scala/jawn/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,23 @@ abstract class Parser[J] {
protected[this] def die(i: Int, msg: String): Nothing =
die(i, msg, ErrorContext)

/**
* A version of `at` that returns as much of the indicated substring as
* possible without throwing exceptions.
*
* This method is necessary because `at(i, j)` may fail with an exception even
* when `atEof(i, j)` returns false (see #143 for an example). This method is
* a workaround; it is not optimized or robust against invalid input and
* should not be used outside of the context of `die`.
*/
@tailrec private[this] def safeAt(i: Int, j: Int): CharSequence =
if (j <= i) "" else {
try at(i, j) catch {
case _: Exception =>
safeAt(i, j - 1)
}
}

/**
* Used to generate error messages with character info and offsets.
*
Expand All @@ -108,7 +125,7 @@ abstract class Parser[J] {
} else {
var offset = 0
while (offset < chars && !atEof(i + offset)) offset += 1
val txt = at(i, i + offset)
val txt = safeAt(i, i + offset)
if (atEof(i + offset)) s"'$txt'" else s"'$txt...'"
}
val s = "%s got %s (line %d, column %d)" format (msg, got, y, x)
Expand Down
13 changes: 13 additions & 0 deletions parser/src/test/scala/jawn/SyntaxCheck.scala
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class SyntaxCheck extends PropSpec with Matchers with PropertyChecks {
}

property("empty is invalid") { isValidSyntax("") shouldBe false }
property("} is invalid") { isValidSyntax("}") shouldBe false }

property("literal TAB is invalid") { isValidSyntax(qs("\t")) shouldBe false }
property("literal NL is invalid") { isValidSyntax(qs("\n")) shouldBe false }
Expand Down Expand Up @@ -220,4 +221,16 @@ class SyntaxCheck extends PropSpec with Matchers with PropertyChecks {
property("error location 2") { testErrorLoc("[1, 2, \n x3]", 2, 4) }
property("error location 3") { testErrorLoc("[1, 2,\n\n\n\n\nx3]", 6, 1) }
property("error location 4") { testErrorLoc("[1, 2,\n\n3,\n4,\n\n x3]", 6, 2) }

property("absorb should fail fast on bad inputs") {
def absorbFails(in: String): Boolean = {
val async = AsyncParser[Unit](AsyncParser.UnwrapArray)
async.absorb("}")(NullFacade).isLeft
}

val badInputs = Seq("}", "fälse", "n0ll", "try", "0x", "0.x", "0ex", "[1; 2]", "{\"a\"; 1}", "{1: 2}")
badInputs.foreach { input =>
absorbFails(input) shouldBe true
}
}
}

0 comments on commit 6388d6f

Please sign in to comment.