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

View File

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