diff options
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.kt | 37 |
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() + } + } } + |