summaryrefslogtreecommitdiff
path: root/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/StringJsonLexer.kt
diff options
context:
space:
mode:
Diffstat (limited to 'formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/StringJsonLexer.kt')
-rw-r--r--formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/StringJsonLexer.kt37
1 files changed, 32 insertions, 5 deletions
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/StringJsonLexer.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/StringJsonLexer.kt
index 0ff980a2..9f2e5190 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/StringJsonLexer.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/StringJsonLexer.kt
@@ -73,19 +73,25 @@ internal class StringJsonLexer(override val source: String) : AbstractJsonLexer(
if (c == expected) return
unexpectedToken(expected)
}
+ currentPosition = -1 // for correct EOF reporting
unexpectedToken(expected) // EOF
}
override fun consumeKeyString(): String {
/*
- * For strings we assume that escaped symbols are rather an exception, so firstly
- * we optimistically scan for closing quote via intrinsified and blazing-fast 'indexOf',
- * than do our pessimistic check for backslash and fallback to slow-path if necessary.
- */
+ * For strings we assume that escaped symbols are rather an exception, so firstly
+ * we optimistically scan for closing quote via intrinsified and blazing-fast 'indexOf',
+ * than do our pessimistic check for backslash and fallback to slow-path if necessary.
+ */
consumeNextToken(STRING)
val current = currentPosition
val closingQuote = source.indexOf('"', current)
- if (closingQuote == -1) fail(TC_STRING)
+ if (closingQuote == -1) {
+ // advance currentPosition to a token after the end of the string to guess position in the error msg
+ // (not always correct, as `:`/`,` are valid contents of the string, but good guess anyway)
+ consumeStringLenient()
+ fail(TC_STRING, wasConsumed = false)
+ }
// Now we _optimistically_ know where the string ends (it might have been an escaped quote)
for (i in current until closingQuote) {
// Encountered escape sequence, should fallback to "slow" path and symbolic scanning
@@ -96,4 +102,25 @@ internal class StringJsonLexer(override val source: String) : AbstractJsonLexer(
this.currentPosition = closingQuote + 1
return source.substring(current, closingQuote)
}
+
+ override fun consumeStringChunked(isLenient: Boolean, consumeChunk: (stringChunk: String) -> Unit) {
+ (if (isLenient) consumeStringLenient() else consumeString()).chunked(BATCH_SIZE).forEach(consumeChunk)
+ }
+
+ override fun peekLeadingMatchingValue(keyToMatch: String, isLenient: Boolean): String? {
+ val positionSnapshot = currentPosition
+ try {
+ if (consumeNextToken() != TC_BEGIN_OBJ) return null // Malformed JSON, bailout
+ val firstKey = peekString(isLenient)
+ if (firstKey != keyToMatch) return null
+ discardPeeked() // consume firstKey
+ if (consumeNextToken() != TC_COLON) return null
+ return peekString(isLenient)
+ } finally {
+ // Restore the position
+ currentPosition = positionSnapshot
+ discardPeeked()
+ }
+ }
}
+