Support missing keys/values in maps

This commit is contained in:
Felix Krause 2015-12-22 22:28:27 +01:00
parent ca077e54ca
commit 545bff673a
2 changed files with 52 additions and 23 deletions

View File

@ -192,7 +192,8 @@ template yieldDocumentEnd() {.dirty.} =
template closeLevel(lvl: DocumentLevel) {.dirty.} = template closeLevel(lvl: DocumentLevel) {.dirty.} =
case lvl.mode case lvl.mode
of mExplicitBlockMapKey, mFlowMapKey: of mExplicitBlockMapKey, mFlowMapKey:
yieldError("Missing Map value!") yieldScalar("")
yield YamlParserEvent(kind: yamlEndMap)
of mImplicitBlockMapKey, mBlockMapValue, mFlowMapValue: of mImplicitBlockMapKey, mBlockMapValue, mFlowMapValue:
yield YamlParserEvent(kind: yamlEndMap) yield YamlParserEvent(kind: yamlEndMap)
of mBlockSequenceItem, mFlowSequenceItem: of mBlockSequenceItem, mFlowSequenceItem:
@ -225,9 +226,10 @@ template closeAllLevels() {.dirty.} =
if ancestry.len == 0: break if ancestry.len == 0: break
level = ancestry.pop() level = ancestry.pop()
template handleBlockIndicator(expected: openarray[DocumentLevelMode], template handleBlockIndicator(expected, possible: openarray[DocumentLevelMode],
next: DocumentLevelMode, next: DocumentLevelMode,
entering: YamlParserEventKind) {.dirty.} = entering: YamlParserEventKind,
emptyScalarOnOpening: bool = false) {.dirty.} =
leaveMoreIndentedLevels() leaveMoreIndentedLevels()
if level.indicatorColumn == lex.column or if level.indicatorColumn == lex.column or
level.indicatorColumn == -1 and level.indentationColumn == lex.column: level.indicatorColumn == -1 and level.indentationColumn == lex.column:
@ -236,6 +238,17 @@ template handleBlockIndicator(expected: openarray[DocumentLevelMode],
ancestry.add(level) ancestry.add(level)
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1, level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
indentationColumn: -1) indentationColumn: -1)
else:
# `in` does not work if possible is [], so we have to check for that
when possible.len > 0:
if level.mode in possible:
yieldScalar("")
level.mode = next
ancestry.add(level)
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
indentationColumn: -1)
else:
yieldError("Invalid token after " & $level.mode)
else: else:
yieldError("Invalid token after " & $level.mode) yieldError("Invalid token after " & $level.mode)
elif level.mode != mUnknown: elif level.mode != mUnknown:
@ -246,6 +259,8 @@ template handleBlockIndicator(expected: openarray[DocumentLevelMode],
level.mode = next level.mode = next
level.indicatorColumn = lex.column level.indicatorColumn = lex.column
yieldStart(entering) yieldStart(entering)
if emptyScalarOnOpening:
yieldScalar("")
ancestry.add(level) ancestry.add(level)
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1, level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
indentationColumn: -1) indentationColumn: -1)
@ -381,14 +396,16 @@ iterator events*(parser: var YamlSequentialParser,
of yamlLineStart: of yamlLineStart:
discard discard
of yamlDash: of yamlDash:
handleBlockIndicator([mBlockSequenceItem], mBlockSequenceItem, handleBlockIndicator([mBlockSequenceItem], [],
yamlStartSequence) mBlockSequenceItem, yamlStartSequence)
of yamlQuestionmark: of yamlQuestionmark:
handleBlockIndicator([mImplicitBlockMapKey, mBlockMapValue], handleBlockIndicator([mImplicitBlockMapKey, mBlockMapValue],
[mExplicitBlockMapKey],
mExplicitBlockMapKey, yamlStartMap) mExplicitBlockMapKey, yamlStartMap)
of yamlColon: of yamlColon:
handleBlockIndicator([mExplicitBlockMapKey], handleBlockIndicator([mExplicitBlockMapKey],
mBlockMapValue, yamlError) [mBlockMapValue, mImplicitBlockMapKey],
mBlockMapValue, yamlStartMap, true)
of yamlPipe, yamlGreater: of yamlPipe, yamlGreater:
blockScalar = if token == yamlPipe: bsLiteral else: bsFolded blockScalar = if token == yamlPipe: bsLiteral else: bsFolded
blockScalarIndentation = -1 blockScalarIndentation = -1
@ -419,15 +436,16 @@ iterator events*(parser: var YamlSequentialParser,
scalarCacheIsQuoted = false scalarCacheIsQuoted = false
scalarIndentation = lex.column scalarIndentation = lex.column
of mBlockMapValue: of mBlockMapValue:
ancestry.add(level)
scalarCache = lex.content scalarCache = lex.content
scalarCacheIsQuoted = false scalarCacheIsQuoted = false
scalarIndentation = lex.column scalarIndentation = lex.column
level = DocumentLevel(mode: mScalar, indicatorColumn: -1, level.mode = mImplicitBlockMapKey
indentationColumn: of mExplicitBlockMapKey:
ancestry[ancestry.high].indentationColumn + 1) yieldScalar()
level.mode = mBlockMapValue
continue
else: else:
yieldError("Unexpected scalar") yieldError("Unexpected scalar in " & $level.mode)
state = ylBlockAfterScalar state = ylBlockAfterScalar
of lexer.yamlScalar: of lexer.yamlScalar:
leaveMoreIndentedLevels() leaveMoreIndentedLevels()

View File

@ -68,15 +68,15 @@ proc printDifference(expected, actual: YamlParserEvent) =
let msg = "[scalar] expected content \"" & let msg = "[scalar] expected content \"" &
expected.scalarContent & "\", got \"" & expected.scalarContent & "\", got \"" &
actual.scalarContent & "\" " actual.scalarContent & "\" "
if expected.scalarContent.len != actual.scalarContent.len:
echo msg, "(length does not match)"
else:
for i in 0..expected.scalarContent.high: for i in 0..expected.scalarContent.high:
if i >= actual.scalarContent.high: if expected.scalarContent[i] != actual.scalarContent[i]:
echo msg, "(expected more chars, first char missing: ",
cast[int](expected.scalarContent[i]), ")"
break
elif expected.scalarContent[i] != actual.scalarContent[i]:
echo msg, "(first different char at pos ", i, echo msg, "(first different char at pos ", i,
": expected ", ": expected ",
cast[int](expected.scalarContent[i]), ", got ", cast[int](expected.scalarContent[i]),
", got ",
cast[int](actual.scalarContent[i]), ")" cast[int](actual.scalarContent[i]), ")"
break break
else: else:
@ -135,6 +135,17 @@ suite "Parsing":
test "Parsing: Mixed Map (implicit to explicit)": test "Parsing: Mixed Map (implicit to explicit)":
ensure("a: b\n? c\n: d", startDoc(), startMap(), scalar("a"), ensure("a: b\n? c\n: d", startDoc(), startMap(), scalar("a"),
scalar("b"), scalar("c"), scalar("d"), endMap(), endDoc()) scalar("b"), scalar("c"), scalar("d"), endMap(), endDoc())
test "Parsing: Missing values in map":
ensure("? a\n? b\nc:", startDoc(), startMap(), scalar("a"), scalar(""),
scalar("b"), scalar(""), scalar("c"), scalar(""), endMap(),
endDoc())
test "Parsing: Missing keys in map":
ensure(": a\n: b", startDoc(), startMap(), scalar(""), scalar("a"),
scalar(""), scalar("b"), endMap(), endDoc())
test "Parsing: Multiline scalars in explicit map":
ensure("? a\n b\n: c\n d\n? e\n f", startDoc(), startMap(),
scalar("a b"), scalar("c d"), scalar("e f"), scalar(""),
endMap(), endDoc())
test "Parsing: Map in Sequence": test "Parsing: Map in Sequence":
ensure(" - key: value", startDoc(), startSequence(), startMap(), ensure(" - key: value", startDoc(), startSequence(), startMap(),
scalar("key"), scalar("value"), endMap(), endSequence(), scalar("key"), scalar("value"), endMap(), endSequence(),