Fixes for block scalars and doc end markers

* Properly (now really) handle block scalars at doc root
 * Properly handle multiple document end markers
This commit is contained in:
Felix Krause 2016-03-19 15:03:09 +01:00
parent 22b8de876d
commit 0fc30241b9
1 changed files with 76 additions and 40 deletions

View File

@ -8,7 +8,7 @@ type
FastParseState = enum FastParseState = enum
fpInitial, fpBlockLineStart, fpBlockAfterObject, fpBlockAfterPlainScalar, fpInitial, fpBlockLineStart, fpBlockAfterObject, fpBlockAfterPlainScalar,
fpBlockObjectStart, fpBlockContinueScalar, fpExpectDocEnd, fpFlow, fpBlockObjectStart, fpBlockContinueScalar, fpExpectDocEnd, fpFlow,
fpFlowAfterObject fpFlowAfterObject, fpAfterDocument
FastParseLevelKind = enum FastParseLevelKind = enum
fplUnknown, fplSequence, fplMapKey, fplMapValue, fplSinglePairKey, fplUnknown, fplSequence, fplMapKey, fplMapValue, fplSinglePairKey,
@ -872,7 +872,7 @@ template blockScalar(lexer: BaseLexer, content: var string,
block outer: block outer:
while true: while true:
block inner: block inner:
for i in countup(1, parentIndent): for i in countup(1, parentIndent + 1):
case lexer.buf[lexer.bufpos] case lexer.buf[lexer.bufpos]
of ' ': discard of ' ': discard
of '\l': of '\l':
@ -887,8 +887,15 @@ template blockScalar(lexer: BaseLexer, content: var string,
stateAfter = if i == 1: fpBlockLineStart else: fpBlockObjectStart stateAfter = if i == 1: fpBlockLineStart else: fpBlockObjectStart
break outer break outer
lexer.bufpos.inc() lexer.bufpos.inc()
if parentIndent == -1 and lexer.buf[lexer.bufpos] == '.':
var isDocumentEnd: bool
startToken()
lexer.documentEnd(isDocumentEnd)
if isDocumentEnd:
stateAfter = fpExpectDocEnd
break outer
if detectedIndent: if detectedIndent:
for i in countup(1, blockIndent): for i in countup(1, blockIndent - 1 + max(0, -parentIndent)):
case lexer.buf[lexer.bufpos] case lexer.buf[lexer.bufpos]
of ' ': discard of ' ': discard
of '\l': of '\l':
@ -911,13 +918,8 @@ template blockScalar(lexer: BaseLexer, content: var string,
stateAfter = fpBlockLineStart stateAfter = fpBlockLineStart
break outer break outer
else: else:
if i == 1: startToken()
stateAfter = if parentIndent <= 0: fpBlockLineStart else: parserError("The text is less indented than expected ")
fpBlockObjectStart
break outer
else:
startToken()
parserError("The text is less indented than expected ")
lexer.bufpos.inc() lexer.bufpos.inc()
else: else:
while true: while true:
@ -937,8 +939,8 @@ template blockScalar(lexer: BaseLexer, content: var string,
else: else:
blockIndent = blockIndent =
lexer.getColNumber(lexer.bufpos) - max(0, parentIndent) lexer.getColNumber(lexer.bufpos) - max(0, parentIndent)
if blockIndent == 0: if blockIndent == 0 and parentIndent >= 0:
stateAfter = if blockIndent + max(0, parentIndent) > 0: stateAfter = if blockIndent + parentIndent > 0:
fpBlockObjectStart else: fpBlockLineStart fpBlockObjectStart else: fpBlockLineStart
break outer break outer
detectedIndent = true detectedIndent = true
@ -1000,6 +1002,27 @@ template blockScalar(lexer: BaseLexer, content: var string,
of ctStrip: discard of ctStrip: discard
debug("lex: \"" & content & '\"') debug("lex: \"" & content & '\"')
template consumeLineIfEmpty(lex: BaseLexer): bool =
var result = true
while true:
lex.bufpos.inc()
case lex.buf[lex.bufpos]
of ' ', '\t': discard
of '\l':
lex.bufpos = lex.handleLF(lex.bufpos)
break
of '\c':
lex.bufpos = lex.handleCR(lex.bufpos)
break
of '#', EndOfFile:
lex.lineEnding()
handleLineEnd(false)
break
else:
result = false
break
result
proc parse*(p: YamlParser, s: Stream): YamlStream = proc parse*(p: YamlParser, s: Stream): YamlStream =
var backend = iterator(): YamlStreamEvent = var backend = iterator(): YamlStreamEvent =
var var
@ -1057,25 +1080,10 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
p.lexer.finishLine() p.lexer.finishLine()
handleLineEnd(false) handleLineEnd(false)
of ' ', '\t': of ' ', '\t':
while true: if not p.lexer.consumeLineIfEmpty():
p.lexer.bufpos.inc() indentation = p.lexer.getColNumber(p.lexer.bufpos)
case p.lexer.buf[p.lexer.bufpos] yield startDocEvent()
of ' ', '\t': discard state = fpBlockObjectStart
of '\l':
p.lexer.bufpos = p.lexer.handleLF(p.lexer.bufpos)
break
of '\c':
p.lexer.bufpos = p.lexer.handleCR(p.lexer.bufpos)
break
of '#', EndOfFile:
p.lexer.lineEnding()
handleLineEnd(false)
break
else:
indentation = p.lexer.getColNumber(p.lexer.bufpos)
yield startDocEvent()
state = fpBlockObjectStart
break
of '\l': p.lexer.bufpos = p.lexer.handleLF(p.lexer.bufpos) of '\l': p.lexer.bufpos = p.lexer.handleLF(p.lexer.bufpos)
of '\c': p.lexer.bufpos = p.lexer.handleCR(p.lexer.bufpos) of '\c': p.lexer.bufpos = p.lexer.handleCR(p.lexer.bufpos)
of EndOfFile: return of EndOfFile: return
@ -1139,12 +1147,11 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
startToken() startToken()
p.lexer.documentEnd(isDocumentEnd) p.lexer.documentEnd(isDocumentEnd)
if isDocumentEnd: if isDocumentEnd:
closeEverything()
p.lexer.bufpos.inc(3) p.lexer.bufpos.inc(3)
p.lexer.lineEnding() p.lexer.lineEnding()
handleLineEnd(true) handleLineEnd(false)
closeEverything() state = fpAfterDocument
initDocValues()
state = fpInitial
else: else:
indentation = 0 indentation = 0
closeMoreIndentedLevels() closeMoreIndentedLevels()
@ -1407,6 +1414,7 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
p.lexer.plainScalar(content, cBlock) p.lexer.plainScalar(content, cBlock)
state = fpBlockAfterPlainScalar state = fpBlockAfterPlainScalar
of fpExpectDocEnd: of fpExpectDocEnd:
debug("state: expectDocEnd")
case p.lexer.buf[p.lexer.bufpos] case p.lexer.buf[p.lexer.bufpos]
of '-': of '-':
var token: LexedPossibleDirectivesEnd var token: LexedPossibleDirectivesEnd
@ -1425,12 +1433,12 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
startToken() startToken()
p.lexer.documentEnd(isDocumentEnd) p.lexer.documentEnd(isDocumentEnd)
if isDocumentEnd: if isDocumentEnd:
closeEverything()
p.lexer.bufpos.inc(3) p.lexer.bufpos.inc(3)
yield endDocEvent() p.lexer.lineEnding()
initDocValues() handleLineEnd(false)
state = fpInitial state = fpAfterDocument
else: else: parserError("Unexpected content (expected document end)")
parserError("Unexpected content (expected document end)")
of ' ', '\t', '#': of ' ', '\t', '#':
p.lexer.lineEnding() p.lexer.lineEnding()
handleLineEnd(true) handleLineEnd(true)
@ -1442,6 +1450,34 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
else: else:
startToken() startToken()
parserError("Unexpected content (expected document end)") parserError("Unexpected content (expected document end)")
of fpAfterDocument:
debug("state: afterDocument")
case p.lexer.buf[p.lexer.bufpos]
of '.':
var isDocumentEnd: bool
startToken()
p.lexer.documentEnd(isDocumentEnd)
if isDocumentEnd:
p.lexer.bufpos.inc(3)
p.lexer.lineEnding()
handleLineEnd(false)
else:
initDocValues()
yield startDocEvent()
state = fpBlockLineStart
of '#':
p.lexer.lineEnding()
handleLineEnd(false)
of '\t', ' ':
if not p.lexer.consumeLineIfEmpty():
indentation = p.lexer.getColNumber(p.lexer.bufpos)
initDocValues()
yield startDocEvent()
state = fpBlockObjectStart
of EndOfFile: break
else:
initDocValues()
state = fpInitial
of fpFlow: of fpFlow:
debug("state: flow") debug("state: flow")
p.lexer.skipWhitespaceCommentsAndNewlines() p.lexer.skipWhitespaceCommentsAndNewlines()