All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.maryk.yaml.LiteralStringReader.kt Maven / Gradle / Ivy

package maryk.yaml

import maryk.json.JsonToken
import maryk.json.TokenType
import maryk.lib.extensions.isLineBreak
import maryk.lib.extensions.isSpacing
import maryk.yaml.ChompStyle.CLIP
import maryk.yaml.ChompStyle.KEEP
import maryk.yaml.ChompStyle.STRIP

internal enum class ChompStyle {
    STRIP, CLIP, KEEP
}

/** Literal style string reader */
internal open class LiteralStringReader(
    yamlReader: YamlReaderImpl,
    parentReader: P,
    private var jsonTokenConstructor: (String?) -> JsonToken
) : YamlCharWithParentReader

(yamlReader, parentReader) { private val parentIndentCount = this.parentReader.indentCount() protected var storedValue: String = "" protected var indentCount: Int? = null protected var foundLineBreaks: Int = 0 private var chompStyle: ChompStyle = CLIP override fun readUntilToken(extraIndent: Int, tag: TokenType?): JsonToken { // Read options and end at first line break readStartForOptionsAndReturnIndent("Literal |") findAndSetStartingIndentation() loop@ while (true) { when (this.lastChar) { '\n', '\r' -> { this.storedValue += this.lastChar this.foundLineBreaks = 0 read() var currentIndentCount = 0 whitespace@ while (this.lastChar.isWhitespace()) { if (this.lastChar.isLineBreak()) { currentIndentCount = 0 this.foundLineBreaks++ } else { currentIndentCount++ } read() if (currentIndentCount == this.indentCount) { break@whitespace } } if (currentIndentCount < this.indentCount!!) { this.yamlReader.setUnclaimedIndenting(currentIndentCount) break@loop } for (it in 0 until this.foundLineBreaks) { this.storedValue += '\n' } } else -> { this.storeCharAndProceed() } } } return this.createTokenAndClose() } protected fun readStartForOptionsAndReturnIndent(description: String) { options@ while (true) { when { this.lastChar.isDigit() && this.lastChar != '0' -> { if (this.indentCount != null) { throw InvalidYamlContent("Cannot define indentation twice") } this.indentCount = this.lastChar.toString().toInt() + this.parentIndentCount } this.lastChar == '+' -> { if (this.chompStyle != CLIP) { throw InvalidYamlContent("Cannot define chomping twice") } this.chompStyle = KEEP } this.lastChar == '-' -> { if (this.chompStyle != CLIP) { throw InvalidYamlContent("Cannot define chomping twice") } this.chompStyle = STRIP } else -> { break@options } } read() } // Previous reader left it just after | while (this.lastChar.isSpacing()) { read() } if (!this.lastChar.isLineBreak()) { throw InvalidYamlContent("$description should always be followed by a linebreak") } } protected fun findAndSetStartingIndentation(): Int { read() // go past line break var currentIndentCount = 0 while (this.lastChar.isWhitespace()) { if (this.lastChar.isLineBreak()) { this.storedValue += this.lastChar currentIndentCount = 0 } else { currentIndentCount++ } read() } if (currentIndentCount < this.parentIndentCount) { throw InvalidYamlContent("Literal scalar with | should contain a value") } if (this.indentCount == null) { this.indentCount = currentIndentCount } else if (this.indentCount!! > currentIndentCount) { throw InvalidYamlContent("Expected a continuation of block") } else { if (currentIndentCount > this.indentCount!!) { for (it in 0..currentIndentCount - this.indentCount!!) { this.storedValue += ' ' } } } return currentIndentCount } protected fun storeCharAndProceed() { this.storedValue += lastChar read() } override fun handleReaderInterrupt(): JsonToken { return this.createTokenAndClose() } protected fun createTokenAndClose(): JsonToken { when (this.chompStyle) { KEEP -> for (it in 0 until this.foundLineBreaks) { this.storedValue += '\n' } CLIP -> { this.storedValue = this.storedValue.trimEnd('\n') this.storedValue += '\n' } STRIP -> { this.storedValue = this.storedValue.trimEnd('\n') } } this.currentReader = this.parentReader return this.jsonTokenConstructor(this.storedValue) } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy