Support tags for sequences and maps in block style

This commit is contained in:
Felix Krause 2015-12-27 17:37:42 +01:00
parent d7f1e726ab
commit 2c9d065ecb
3 changed files with 29 additions and 18 deletions

View File

@ -731,6 +731,7 @@ iterator tokens(my: var YamlLexer): YamlLexerToken {.closure.} =
state = ylTagHandle state = ylTagHandle
my.content = "!" my.content = "!"
lastSpecialChar = '\0' lastSpecialChar = '\0'
my.column = curPos - 1
else: else:
my.content.add(lastSpecialChar) my.content.add(lastSpecialChar)
advanceTypeHint(lastSpecialChar) advanceTypeHint(lastSpecialChar)

View File

@ -106,6 +106,10 @@ template yieldScalar(content: string, typeHint: YamlTypeHint,
when defined(yamlDebug): when defined(yamlDebug):
echo "Parser token [mode=", level.mode, ", state=", state, "]: ", echo "Parser token [mode=", level.mode, ", state=", state, "]: ",
"scalar[\"", content, "\", type=", typeHint, "]" "scalar[\"", content, "\", type=", typeHint, "]"
if objectTag.len > 0:
if tag.len > 0:
yieldError("Duplicate tag for scalar")
tag = objectTag
yield YamlStreamEvent(kind: yamlScalar, yield YamlStreamEvent(kind: yamlScalar,
scalarAnchor: resolveAnchor(parser, anchor), scalarAnchor: resolveAnchor(parser, anchor),
scalarTag: resolveTag(parser, tag, quoted), scalarTag: resolveTag(parser, tag, quoted),
@ -227,7 +231,7 @@ template handleBlockIndicator(expected, possible: openarray[DocumentLevelMode],
cachedAnchor = anchor cachedAnchor = anchor
cachedTag = tag cachedTag = tag
anchor = "" anchor = ""
tag = "" tag = objectTag
yieldStart(entering) yieldStart(entering)
anchor = cachedAnchor anchor = cachedAnchor
tag = cachedTag tag = cachedTag
@ -286,6 +290,7 @@ proc parse*(parser: YamlSequentialParser, s: Stream): YamlStream =
# cached values # cached values
tag: string = "" tag: string = ""
objectTag: string = ""
anchor: string = "" anchor: string = ""
scalarCache: string = nil scalarCache: string = nil
scalarCacheType: YamlTypeHint scalarCacheType: YamlTypeHint
@ -363,6 +368,8 @@ proc parse*(parser: YamlSequentialParser, s: Stream): YamlStream =
case token case token
of tTagHandle: of tTagHandle:
handleTagHandle() handleTagHandle()
objectTag = tag
tag = ""
state = ypBlockLineEnd state = ypBlockLineEnd
of tComment: of tComment:
state = ypBlockLineEnd state = ypBlockLineEnd
@ -373,7 +380,11 @@ proc parse*(parser: YamlSequentialParser, s: Stream): YamlStream =
of ypBlockLineStart: of ypBlockLineStart:
case token case token
of tLineStart: of tLineStart:
discard if objectTag.len > 0:
yieldError("Duplicate tag for object")
else:
objectTag = tag
tag = ""
of tDash: of tDash:
handleBlockIndicator([mBlockSequenceItem], [], handleBlockIndicator([mBlockSequenceItem], [],
mBlockSequenceItem, yamlStartSequence) mBlockSequenceItem, yamlStartSequence)
@ -499,21 +510,20 @@ proc parse*(parser: YamlSequentialParser, s: Stream): YamlStream =
closeAllLevels() closeAllLevels()
state = ypAfterDirectivesEnd state = ypAfterDirectivesEnd
continue continue
of tAlias: else:
leaveMoreIndentedLevels() leaveMoreIndentedLevels()
if level.mode == mScalar:
yieldUnexpectedToken()
state = ypBlockLineStart state = ypBlockLineStart
continue continue
else:
yieldUnexpectedToken()
of ypBlockAfterScalar: of ypBlockAfterScalar:
case token case token
of tColon: of tColon:
assert level.mode in [mUnknown, mImplicitBlockMapKey, mScalar] assert level.mode in [mUnknown, mImplicitBlockMapKey, mScalar]
if level.mode in [mUnknown, mScalar]: if level.mode in [mUnknown, mScalar]:
# tags and anchors are for key scalar, not for map.
yield YamlStreamEvent(kind: yamlStartMap, yield YamlStreamEvent(kind: yamlStartMap,
mapAnchor: anchorNone, mapAnchor: anchorNone,
mapTag: tagQuestionMark) mapTag: parser.resolveTag(objectTag))
level.mode = mBlockMapValue level.mode = mBlockMapValue
ancestry.add(level) ancestry.add(level)
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1, level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
@ -584,11 +594,9 @@ proc parse*(parser: YamlSequentialParser, s: Stream): YamlStream =
of tAnchor: of tAnchor:
anchor = lex.content anchor = lex.content
state = ypBlockAfterAnchorAndTag state = ypBlockAfterAnchorAndTag
of tScalar, tColon, tStreamEnd: of tScalar, tColon, tStreamEnd, tScalarPart:
state = ypBlockLineStart state = ypBlockLineStart
continue continue
of tScalarPart:
startPlainScalar()
of tLineStart: of tLineStart:
state = ypBlockLineStart state = ypBlockLineStart
of tOpeningBracket, tOpeningBrace: of tOpeningBracket, tOpeningBrace:
@ -602,11 +610,9 @@ proc parse*(parser: YamlSequentialParser, s: Stream): YamlStream =
state = ypBlockLineStart state = ypBlockLineStart
continue continue
case token case token
of tScalar, tColon, tStreamEnd: of tScalar, tColon, tStreamEnd, tScalarPart:
state = ypBlockLineStart state = ypBlockLineStart
continue continue
of tScalarPart:
startPlainScalar()
of tLineStart: of tLineStart:
discard discard
of tOpeningBracket, tOpeningBrace: of tOpeningBracket, tOpeningBrace:
@ -627,11 +633,9 @@ proc parse*(parser: YamlSequentialParser, s: Stream): YamlStream =
state = ypBlockLineStart state = ypBlockLineStart
continue continue
case token case token
of tScalar, tColon, tStreamEnd: of tScalar, tColon, tStreamEnd, tScalarPart:
state = ypBlockLineStart state = ypBlockLineStart
continue continue
of tScalarPart:
startPlainScalar()
of tLineStart: of tLineStart:
discard discard
of tOpeningBracket, tOpeningBrace: of tOpeningBracket, tOpeningBrace:

View File

@ -50,8 +50,8 @@ proc printDifference(expected, actual: YamlStreamEvent) =
if expected.kind != actual.kind: if expected.kind != actual.kind:
echo "expected " & $expected.kind & ", got " & $actual.kind echo "expected " & $expected.kind & ", got " & $actual.kind
if actual.kind == yamlError: if actual.kind == yamlError:
echo "Error message: (", actual.line, ", ", actual.column, ") ", echo "Error message: (line: ", actual.line, ", column: ",
actual.description actual.column, ") ", actual.description
elif actual.kind == yamlWarning: elif actual.kind == yamlWarning:
echo "Warning message: " & actual.description echo "Warning message: " & actual.description
else: else:
@ -238,6 +238,12 @@ suite "Parsing":
ensure("? !!str a\n: !!int b\n? c\n: !!str d", startDoc(), startMap(), ensure("? !!str a\n: !!int b\n? c\n: !!str d", startDoc(), startMap(),
scalar("a", tagString), scalar("b", tagInteger), scalar("c"), scalar("a", tagString), scalar("b", tagInteger), scalar("c"),
scalar("d", tagString), endMap(), endDoc()) scalar("d", tagString), endMap(), endDoc())
test "Parsing: tags for block objects":
ensure("--- !!map\nfoo: !!seq\n - a\n - !!str b\n!!str bar: !!str baz",
startDoc(), startMap(tagMap), scalar("foo"),
startSequence(tagSequence), scalar("a"), scalar("b", tagString),
endSequence(), scalar("bar", tagString),
scalar("baz", tagString), endMap(), endDoc())
test "Parsing: tags for flow objects": test "Parsing: tags for flow objects":
ensure("!!map { k: !!seq [ a, !!str b] }", startDoc(), startMap(tagMap), ensure("!!map { k: !!seq [ a, !!str b] }", startDoc(), startMap(tagMap),
scalar("k"), startSequence(tagSequence), scalar("a"), scalar("k"), startSequence(tagSequence), scalar("a"),