mirror of https://github.com/status-im/NimYAML.git
Implemented alias resolution
* Parse alias nodes properly * Fixed a bug that prevented you from having objects as map keys * Use AnchorId for reporting anchors instead of strings * Do not use nil strings for anchor and tag
This commit is contained in:
parent
e254d0f282
commit
f249813b90
|
@ -573,10 +573,13 @@ iterator tokens*(my: var YamlLexer): YamlLexerToken {.closure.} =
|
|||
my.column = curPos
|
||||
state = ylSingleQuotedScalar
|
||||
of '!':
|
||||
my.column = curPos
|
||||
lastSpecialChar = '!'
|
||||
of '&':
|
||||
my.column = curPos
|
||||
state = ylAnchor
|
||||
of '*':
|
||||
my.column = curPos
|
||||
state = ylAlias
|
||||
of ' ':
|
||||
discard
|
||||
|
@ -588,6 +591,7 @@ iterator tokens*(my: var YamlLexer): YamlLexerToken {.closure.} =
|
|||
my.column = curPos
|
||||
state = ylPlainScalar
|
||||
of '?', ':':
|
||||
my.column = curPos
|
||||
lastSpecialChar = c
|
||||
of '|':
|
||||
yieldToken(yamlPipe)
|
||||
|
@ -833,11 +837,28 @@ iterator tokens*(my: var YamlLexer): YamlLexerToken {.closure.} =
|
|||
else:
|
||||
my.content.add(c)
|
||||
of ylAlias:
|
||||
if lastSpecialChar != '\0':
|
||||
case c
|
||||
of EndOfFile, '\r', '\x0A', ' ', '\t', '{', '}', '[', ']':
|
||||
yieldToken(yamlAlias)
|
||||
state = ylInitialInLine
|
||||
continue
|
||||
else:
|
||||
my.content.add(lastSpecialChar)
|
||||
lastSpecialChar = '\0'
|
||||
case c
|
||||
of EndOfFile, '\r', '\x0A', ' ', '\t', '{', '}', '[', ']':
|
||||
yieldToken(yamlAlias)
|
||||
state = ylInitialInLine
|
||||
continue
|
||||
of ':':
|
||||
lastSpecialChar = ':'
|
||||
of ',':
|
||||
if flowDepth > 0:
|
||||
yieldToken(yamlAlias)
|
||||
state = ylInitialInLine
|
||||
continue
|
||||
my.content.add(c)
|
||||
else:
|
||||
my.content.add(c)
|
||||
|
||||
|
|
|
@ -9,20 +9,21 @@ type
|
|||
yamlError, yamlWarning
|
||||
|
||||
TagId* = distinct int
|
||||
AnchorId* = distinct int
|
||||
|
||||
YamlParserEvent* = ref object
|
||||
case kind*: YamlParserEventKind
|
||||
of yamlStartMap, yamlStartSequence:
|
||||
objAnchor* : string # may be nil, may not be empty
|
||||
objAnchor* : AnchorId
|
||||
objTag* : TagId
|
||||
of yamlScalar:
|
||||
scalarAnchor* : string # may be nil
|
||||
scalarAnchor* : AnchorId
|
||||
scalarTag* : TagId
|
||||
scalarContent*: string # may not be nil (but empty)
|
||||
of yamlEndMap, yamlEndSequence, yamlStartDocument, yamlEndDocument:
|
||||
discard
|
||||
of yamlAlias:
|
||||
aliasName* : string # may not be nil nor empty
|
||||
aliasTarget* : AnchorId
|
||||
of yamlError, yamlWarning:
|
||||
description* : string
|
||||
line* : int
|
||||
|
@ -31,10 +32,10 @@ type
|
|||
YamlParserState = enum
|
||||
ylInitial, ylSkipDirective, ylBlockLineStart, ylBlockAfterTag,
|
||||
ylBlockAfterAnchor, ylBlockAfterAnchorAndTag, ylBlockAfterScalar,
|
||||
ylBlockAfterColon, ylBlockMultilineScalar, ylBlockLineEnd,
|
||||
ylBlockScalarHeader, ylBlockScalar, ylFlow, ylFlowAfterObject,
|
||||
ylFlowAfterTag, ylFlowAfterAnchor, ylFlowAfterAnchorAndTag,
|
||||
ylExpectingDocumentEnd
|
||||
ylBlockAfterAlias, ylBlockAfterColon, ylBlockMultilineScalar,
|
||||
ylBlockLineEnd, ylBlockScalarHeader, ylBlockScalar, ylFlow,
|
||||
ylFlowAfterObject, ylFlowAfterTag, ylFlowAfterAnchor,
|
||||
ylFlowAfterAnchorAndTag, ylExpectingDocumentEnd
|
||||
|
||||
DocumentLevelMode = enum
|
||||
mBlockSequenceItem, mFlowSequenceItem, mExplicitBlockMapKey,
|
||||
|
@ -54,10 +55,12 @@ type
|
|||
|
||||
YamlSequentialParser* = object
|
||||
tags: OrderedTable[string, TagId]
|
||||
anchors: OrderedTable[string, AnchorId]
|
||||
|
||||
const
|
||||
tagNonSpecificEmark*: TagId = 0.TagId # "!" non-specific tag
|
||||
tagNonSpecificQmark*: TagId = 1.TagId # "?" non-specific tag
|
||||
tagExclamationMark*: TagId = 0.TagId # "!" non-specific tag
|
||||
tagQuestionMark* : TagId = 1.TagId # "?" non-specific tag
|
||||
anchorNone*: AnchorId = (-1).AnchorId # no anchor defined
|
||||
|
||||
# interface
|
||||
|
||||
|
@ -66,6 +69,9 @@ proc `==`*(left: YamlParserEvent, right: YamlParserEvent): bool
|
|||
proc `==`*(left, right: TagId): bool {.borrow.}
|
||||
proc `$`*(id: TagId): string {.borrow.}
|
||||
|
||||
proc `==`*(left, right: AnchorId): bool {.borrow.}
|
||||
proc `$`*(id: AnchorId): string {.borrow.}
|
||||
|
||||
proc initParser*(): YamlSequentialParser
|
||||
|
||||
# iterators cannot be pre-declared.
|
||||
|
@ -77,12 +83,15 @@ proc uri*(parser: YamlSequentialParser, id: TagId): string
|
|||
|
||||
proc registerUri*(parser: var YamlSequentialParser, uri: string): TagId
|
||||
|
||||
proc anchor*(parser: YamlSequentialParser, id: AnchorId): string
|
||||
|
||||
# implementation
|
||||
|
||||
proc initParser*(): YamlSequentialParser =
|
||||
result.tags = initOrderedTable[string, TagId]()
|
||||
result.tags["!"] = tagNonSpecificEmark
|
||||
result.tags["?"] = tagNonSpecificQmark
|
||||
result.tags["!"] = tagExclamationMark
|
||||
result.tags["?"] = tagQuestionMark
|
||||
result.anchors = initOrderedTable[string, AnchorId]()
|
||||
|
||||
proc uri*(parser: YamlSequentialParser, id: TagId): string =
|
||||
for pair in parser.tags.pairs:
|
||||
|
@ -95,6 +104,12 @@ proc registerUri*(parser: var YamlSequentialParser, uri: string): TagId =
|
|||
if parser.tags.hasKeyOrPut(uri, result):
|
||||
result = parser.tags[uri]
|
||||
|
||||
proc anchor*(parser: YamlSequentialParser, id: AnchorId): string =
|
||||
for pair in parser.anchors.pairs:
|
||||
if pair[1] == id:
|
||||
return pair[0]
|
||||
return nil
|
||||
|
||||
proc `==`*(left: YamlParserEvent, right: YamlParserEvent): bool =
|
||||
if left.kind != right.kind:
|
||||
return false
|
||||
|
@ -109,7 +124,7 @@ proc `==`*(left: YamlParserEvent, right: YamlParserEvent): bool =
|
|||
left.scalarTag == right.scalarTag and
|
||||
left.scalarContent == right.scalarContent
|
||||
of yamlAlias:
|
||||
result = left.aliasName == right.aliasName
|
||||
result = left.aliasTarget == right.aliasTarget
|
||||
of yamlError, yamlWarning:
|
||||
result = left.description == right.description and
|
||||
left.line == right.line and left.column == right.column
|
||||
|
@ -123,43 +138,56 @@ template yieldError(d: string) {.dirty.} =
|
|||
line: lex.line, column: lex.column)
|
||||
break parserLoop
|
||||
|
||||
template yieldScalar(content: string = "", quoted: bool = false) {.dirty.} =
|
||||
var retTag: TagId
|
||||
if isNil(tag):
|
||||
retTag = if quoted: tagNonSpecificEmark else: tagNonSpecificQmark
|
||||
template yieldUnexpectedToken(expected: string = "") {.dirty.} =
|
||||
var msg = "[" & $state & "] Unexpected token"
|
||||
if expected.len > 0:
|
||||
msg.add(" (expected " & expected & ")")
|
||||
msg.add(": " & $token)
|
||||
yieldError(msg)
|
||||
|
||||
proc resolveAnchor(parser: var YamlSequentialParser, anchor: var string):
|
||||
AnchorId {.inline.} =
|
||||
result = anchorNone
|
||||
if anchor.len > 0:
|
||||
result = cast[AnchorId](parser.anchors.len)
|
||||
if parser.anchors.hasKeyOrPut(anchor, result):
|
||||
result = parser.anchors[anchor]
|
||||
anchor = ""
|
||||
|
||||
proc resolveAlias(parser: var YamlSequentialParser, name: string): AnchorId =
|
||||
try:
|
||||
result = parser.anchors[name]
|
||||
except KeyError:
|
||||
result = anchorNone
|
||||
|
||||
proc resolveTag(parser: var YamlSequentialParser, tag: var string,
|
||||
quotedString: bool = false): TagId {.inline.} =
|
||||
if tag.len == 0:
|
||||
result = if quotedString: tagExclamationMark else: tagQuestionMark
|
||||
else:
|
||||
try:
|
||||
retTag = parser.tags[tag]
|
||||
result = parser.tags[tag]
|
||||
except KeyError:
|
||||
retTag = cast[TagId](parser.tags.len)
|
||||
parser.tags[tag] = retTag
|
||||
result = cast[TagId](parser.tags.len)
|
||||
parser.tags[tag] = result
|
||||
tag = ""
|
||||
|
||||
template yieldScalar(content: string = "", quoted: bool = false) {.dirty.} =
|
||||
yield YamlParserEvent(kind: yamlScalar,
|
||||
scalarAnchor: anchor, scalarTag: retTag,
|
||||
scalarAnchor: resolveAnchor(parser, anchor),
|
||||
scalarTag: resolveTag(parser, tag, quoted),
|
||||
scalarContent: content)
|
||||
anchor = nil
|
||||
tag = nil
|
||||
|
||||
template yieldStart(k: YamlParserEventKind) {.dirty.} =
|
||||
var retTag: TagId
|
||||
if isNil(tag):
|
||||
retTag = tagNonSpecificQmark
|
||||
else:
|
||||
try:
|
||||
retTag = parser.tags[tag]
|
||||
except KeyError:
|
||||
retTag = cast[TagId](parser.tags.len)
|
||||
parser.tags[tag] = retTag
|
||||
|
||||
yield YamlParserEvent(kind: k, objAnchor: anchor, objTag: retTag)
|
||||
anchor = nil
|
||||
tag = nil
|
||||
yield YamlParserEvent(kind: k, objAnchor: resolveAnchor(parser, anchor),
|
||||
objTag: resolveTag(parser, tag))
|
||||
|
||||
template yieldDocumentEnd() {.dirty.} =
|
||||
yield YamlParserEvent(kind: yamlEndDocument)
|
||||
tagShorthands = initTable[string, string]()
|
||||
tagShorthands["!"] = "!"
|
||||
tagShorthands["!!"] = "tag:yaml.org,2002:"
|
||||
parser.anchors = initOrderedTable[string, AnchorId]()
|
||||
|
||||
template closeLevel(lvl: DocumentLevel) {.dirty.} =
|
||||
case lvl.mode
|
||||
|
@ -171,20 +199,11 @@ template closeLevel(lvl: DocumentLevel) {.dirty.} =
|
|||
of mBlockSequenceItem, mFlowSequenceItem:
|
||||
yield YamlParserEvent(kind: yamlEndSequence)
|
||||
of mScalar:
|
||||
var retTag: TagId
|
||||
if isNil(tag):
|
||||
retTag = tagNonSpecificQmark
|
||||
else:
|
||||
try:
|
||||
retTag = parser.tags[tag]
|
||||
except KeyError:
|
||||
retTag = cast[TagId](parser.tags.len)
|
||||
parser.tags[tag] = retTag
|
||||
yield YamlParserEvent(kind: yamlScalar,
|
||||
scalarAnchor: resolveAnchor(parser, anchor),
|
||||
scalarTag: resolveTag(parser, tag),
|
||||
scalarContent: scalarCache)
|
||||
|
||||
yield YamlParserEvent(kind: yamlScalar, scalarAnchor: anchor,
|
||||
scalarTag: retTag, scalarContent: scalarCache)
|
||||
anchor = nil
|
||||
tag = nil
|
||||
else:
|
||||
yieldScalar()
|
||||
|
||||
|
@ -221,7 +240,7 @@ template handleBlockIndicator(expected, next: DocumentLevelMode,
|
|||
elif level.mode != mUnknown:
|
||||
yieldError("Invalid indentation")
|
||||
elif entering == yamlError:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
else:
|
||||
level.mode = next
|
||||
level.indicatorColumn = lex.column
|
||||
|
@ -272,11 +291,12 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
blockScalarTrailing: string = nil
|
||||
|
||||
# cached values
|
||||
tag: string = nil
|
||||
anchor: string = nil
|
||||
tag: string = ""
|
||||
anchor: string = ""
|
||||
scalarCache: string = nil
|
||||
scalarIndentation: int
|
||||
scalarCacheIsQuoted: bool = false
|
||||
aliasCache = anchorNone
|
||||
|
||||
lex.open(input)
|
||||
tagShorthands["!"] = "!"
|
||||
|
@ -407,6 +427,21 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
state = ylBlockAfterScalar
|
||||
else:
|
||||
yieldError("Unexpected scalar")
|
||||
of lexer.yamlAlias:
|
||||
aliasCache = resolveAlias(parser, lex.content)
|
||||
if aliasCache == anchorNone:
|
||||
yieldError("[alias] Unknown anchor: " & lex.content)
|
||||
if ancestry.len > 0:
|
||||
if level.mode == mUnknown:
|
||||
level = ancestry.pop()
|
||||
else:
|
||||
assert level.mode == mImplicitBlockMapKey
|
||||
leaveMoreIndentedLevels()
|
||||
case level.mode
|
||||
of mUnknown, mImplicitBlockMapKey, mBlockSequenceItem:
|
||||
state = ylBlockAfterAlias
|
||||
else:
|
||||
yieldError("Unexpected alias")
|
||||
of yamlStreamEnd:
|
||||
closeAllLevels()
|
||||
yield YamlParserEvent(kind: yamlEndDocument)
|
||||
|
@ -422,7 +457,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
state = ylFlow
|
||||
continue
|
||||
else:
|
||||
yieldError("[block line start] Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylBlockMultilineScalar:
|
||||
case token
|
||||
of yamlScalarPart:
|
||||
|
@ -439,7 +474,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
if level.mode != mScalar:
|
||||
state = ylBlockLineStart
|
||||
continue
|
||||
yieldError("[multiline scalar ?:-] Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of yamlDocumentEnd, yamlStreamEnd:
|
||||
closeAllLevels()
|
||||
scalarCache = nil
|
||||
|
@ -449,8 +484,12 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
closeAllLevels()
|
||||
state = ylInitial
|
||||
continue
|
||||
of lexer.yamlAlias:
|
||||
leaveMoreIndentedLevels()
|
||||
state = ylBlockLineStart
|
||||
continue
|
||||
else:
|
||||
yieldError("[multiline scalar] Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylBlockAfterScalar:
|
||||
case token
|
||||
of yamlColon:
|
||||
|
@ -459,8 +498,8 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
level.indentationColumn = scalarIndentation
|
||||
# tags and anchors are for key scalar, not for map.
|
||||
yield YamlParserEvent(kind: yamlStartMap,
|
||||
objAnchor: nil,
|
||||
objTag: tagNonSpecificQmark)
|
||||
objAnchor: anchorNone,
|
||||
objTag: tagQuestionMark)
|
||||
level.mode = mImplicitBlockMapValue
|
||||
ancestry.add(level)
|
||||
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
||||
|
@ -489,7 +528,38 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
yield YamlParserEvent(kind: yamlEndDocument)
|
||||
break
|
||||
else:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylBlockAfterAlias:
|
||||
case token
|
||||
of yamlColon:
|
||||
assert level.mode in [mUnknown, mImplicitBlockMapKey]
|
||||
if level.mode == mUnknown:
|
||||
yield YamlParserEvent(kind: yamlStartMap,
|
||||
objAnchor: anchorNone,
|
||||
objTag: tagQuestionMark)
|
||||
level.mode = mImplicitBlockMapValue
|
||||
ancestry.add(level)
|
||||
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
||||
indentationColumn: -1)
|
||||
yield YamlParserEvent(kind: yamlAlias, aliasTarget: aliasCache)
|
||||
state = ylBlockAfterColon
|
||||
of yamlLineStart:
|
||||
if level.mode == mImplicitBlockMapKey:
|
||||
yieldError("Missing colon after implicit map key")
|
||||
if level.mode == mUnknown:
|
||||
assert ancestry.len > 0
|
||||
level = ancestry.pop()
|
||||
yield YamlParserEvent(kind: yamlAlias, aliasTarget: aliasCache)
|
||||
state = ylBlockLineStart
|
||||
of yamlStreamEnd:
|
||||
yield YamlParserEvent(kind: yamlAlias, aliasTarget: aliasCache)
|
||||
if level.mode == mUnknown:
|
||||
assert ancestry.len > 0
|
||||
level = ancestry.pop()
|
||||
state = ylBlockLineEnd
|
||||
continue
|
||||
else:
|
||||
yieldUnexpectedToken()
|
||||
of ylBlockAfterTag:
|
||||
case token
|
||||
of yamlAnchor:
|
||||
|
@ -506,7 +576,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
state = ylFlow
|
||||
continue
|
||||
else:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylBlockAfterAnchor:
|
||||
case token
|
||||
of lexer.yamlScalar:
|
||||
|
@ -521,13 +591,13 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
continue
|
||||
of yamlTagHandle:
|
||||
handleTagHandle()
|
||||
state = ylBlockAfterTag
|
||||
state = ylBlockAfterAnchorAndTag
|
||||
of yamlVerbatimTag:
|
||||
tag = lex.content
|
||||
state = ylBlockAfterTag
|
||||
state = ylBlockAfterAnchorAndTag
|
||||
level.indentationColumn = lex.column
|
||||
else:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylBlockAfterAnchorAndTag:
|
||||
case token
|
||||
of lexer.yamlScalar:
|
||||
|
@ -541,7 +611,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
state = ylFlow
|
||||
continue
|
||||
else:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylBlockAfterColon:
|
||||
case token
|
||||
of lexer.yamlScalar:
|
||||
|
@ -574,9 +644,20 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
of yamlAnchor:
|
||||
anchor = lex.content
|
||||
state = ylBlockAfterAnchor
|
||||
of lexer.yamlAlias:
|
||||
var noAnchor = false
|
||||
try:
|
||||
aliasCache = parser.anchors[lex.content]
|
||||
except KeyError:
|
||||
noAnchor = true
|
||||
if noAnchor:
|
||||
# cannot use yield within try/except, so do it here
|
||||
yieldError("[alias] Unknown anchor: " & lex.content)
|
||||
yield YamlParserEvent(kind: yamlAlias, aliasTarget: aliasCache)
|
||||
level = ancestry.pop()
|
||||
state = ylBlockLineEnd
|
||||
else:
|
||||
yieldError("Unexpected token (expected scalar or line end): " &
|
||||
$token)
|
||||
yieldUnexpectedToken("scalar or line end")
|
||||
of ylBlockLineEnd:
|
||||
case token
|
||||
of yamlLineStart:
|
||||
|
@ -587,7 +668,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
yield YamlParserEvent(kind: yamlEndDocument)
|
||||
break
|
||||
else:
|
||||
yieldError("Unexpected token (expected line end):" & $token)
|
||||
yieldUnexpectedToken("line end")
|
||||
of ylBlockScalarHeader:
|
||||
case token
|
||||
of yamlPlus:
|
||||
|
@ -609,7 +690,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
blockScalarTrailing = ""
|
||||
state = ylBlockScalar
|
||||
else:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylBlockScalar:
|
||||
case token
|
||||
of yamlLineStart:
|
||||
|
@ -683,9 +764,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
||||
indentationColumn: -1)
|
||||
else:
|
||||
yieldError(
|
||||
"Unexpected token (expected scalar, comma or " &
|
||||
" map end): " & $token)
|
||||
yieldUnexpectedToken("scalar, comma or map end")
|
||||
of yamlComma:
|
||||
yieldScalar()
|
||||
level = ancestry.pop()
|
||||
|
@ -701,7 +780,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
yieldError("Internal error! Please report this bug.")
|
||||
of yamlOpeningBrace:
|
||||
if level.mode != mUnknown:
|
||||
yieldError("Unexpected token")
|
||||
yieldUnexpectedToken()
|
||||
level.mode = mFlowMapKey
|
||||
yieldStart(yamlStartMap)
|
||||
ancestry.add(level)
|
||||
|
@ -709,7 +788,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
indentationColumn: -1)
|
||||
of yamlOpeningBracket:
|
||||
if level.mode != mUnknown:
|
||||
yieldError("Unexpected token")
|
||||
yieldUnexpectedToken()
|
||||
level.mode = mFlowSequenceItem
|
||||
yieldStart(yamlStartSequence)
|
||||
ancestry.add(level)
|
||||
|
@ -720,7 +799,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
yieldScalar()
|
||||
level = ancestry.pop()
|
||||
if level.mode != mFlowMapValue:
|
||||
yieldError("Unexpected token")
|
||||
yieldUnexpectedToken()
|
||||
yield YamlParserEvent(kind: yamlEndMap)
|
||||
if ancestry.len > 0:
|
||||
level = ancestry.pop()
|
||||
|
@ -736,7 +815,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
yieldScalar()
|
||||
level = ancestry.pop()
|
||||
if level.mode != mFlowSequenceItem:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
else:
|
||||
yield YamlParserEvent(kind: yamlEndSequence)
|
||||
if ancestry.len > 0:
|
||||
|
@ -754,8 +833,13 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
of yamlAnchor:
|
||||
anchor = lex.content
|
||||
state = ylFlowAfterAnchor
|
||||
of lexer.yamlAlias:
|
||||
yield YamlParserEvent(kind: yamlAlias,
|
||||
aliasTarget: resolveAlias(parser, lex.content))
|
||||
state = ylFlowAfterObject
|
||||
level = ancestry.pop()
|
||||
else:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylFlowAfterTag:
|
||||
case token
|
||||
of yamlTagHandle:
|
||||
|
@ -791,7 +875,7 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
discard
|
||||
of yamlColon:
|
||||
if level.mode != mFlowMapKey:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
else:
|
||||
level.mode = mFlowMapValue
|
||||
ancestry.add(level)
|
||||
|
@ -812,37 +896,38 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
indentationColumn: -1)
|
||||
state = ylFlow
|
||||
else:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
echo "level.mode = ", level.mode
|
||||
yieldUnexpectedToken()
|
||||
of yamlClosingBrace:
|
||||
if level.mode != mFlowMapValue:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
else:
|
||||
yield YamlParserEvent(kind: yamlEndMap)
|
||||
if ancestry.len > 0:
|
||||
level = ancestry.pop()
|
||||
case level.mode
|
||||
of mFlowMapKey, mFlowMapValue, mFlowSequenceItem:
|
||||
state = ylFlow
|
||||
state = ylFlowAfterObject
|
||||
else:
|
||||
state = ylBlockLineEnd
|
||||
else:
|
||||
state = ylExpectingDocumentEnd
|
||||
of yamlClosingBracket:
|
||||
if level.mode != mFlowSequenceItem:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
else:
|
||||
yield YamlParserEvent(kind: yamlEndSequence)
|
||||
if ancestry.len > 0:
|
||||
level = ancestry.pop()
|
||||
case level.mode
|
||||
of mFlowMapKey, mFlowMapValue, mFlowSequenceItem:
|
||||
state = ylFlow
|
||||
state = ylFlowAfterObject
|
||||
else:
|
||||
state = ylBlockLineEnd
|
||||
else:
|
||||
state = ylExpectingDocumentEnd
|
||||
else:
|
||||
yieldError("Unexpected token: " & $token)
|
||||
yieldUnexpectedToken()
|
||||
of ylExpectingDocumentEnd:
|
||||
case token
|
||||
of yamlComment, yamlLineStart:
|
||||
|
@ -855,6 +940,5 @@ iterator events*(parser: var YamlSequentialParser,
|
|||
state = ylInitial
|
||||
continue
|
||||
else:
|
||||
yieldError("Unexpected token (expected document end): " &
|
||||
$token)
|
||||
yieldUnexpectedToken("document end")
|
||||
token = nextToken(lex)
|
|
@ -11,15 +11,16 @@ proc endDoc(): YamlParserEvent =
|
|||
new(result)
|
||||
result.kind = yamlEndDocument
|
||||
|
||||
proc scalar(content: string, tag: TagId = tagNonSpecificQmark,
|
||||
anchor: string = nil): YamlParserEvent =
|
||||
proc scalar(content: string, tag: TagId = tagQuestionMark,
|
||||
anchor: AnchorId = anchorNone): YamlParserEvent =
|
||||
new(result)
|
||||
result.kind = yamlScalar
|
||||
result.scalarAnchor = anchor
|
||||
result.scalarTag = tag
|
||||
result.scalarContent = content
|
||||
|
||||
proc startSequence(tag: TagId = tagNonSpecificQmark, anchor: string = nil):
|
||||
proc startSequence(tag: TagId = tagQuestionMark,
|
||||
anchor: AnchorId = anchorNone):
|
||||
YamlParserEvent =
|
||||
new(result)
|
||||
result.kind = yamlStartSequence
|
||||
|
@ -30,7 +31,7 @@ proc endSequence(): YamlParserEvent =
|
|||
new(result)
|
||||
result.kind = yamlEndSequence
|
||||
|
||||
proc startMap(tag: TagId = tagNonSpecificQmark, anchor: string = nil):
|
||||
proc startMap(tag: TagId = tagQuestionMark, anchor: AnchorId = anchorNone):
|
||||
YamlParserEvent =
|
||||
new(result)
|
||||
result.kind = yamlStartMap
|
||||
|
@ -41,6 +42,11 @@ proc endMap(): YamlParserEvent =
|
|||
new(result)
|
||||
result.kind = yamlEndMap
|
||||
|
||||
proc alias(target: AnchorId): YamlParserEvent =
|
||||
new(result)
|
||||
result.kind = yamlAlias
|
||||
result.aliasTarget = target
|
||||
|
||||
proc printDifference(expected, actual: YamlParserEvent) =
|
||||
if expected.kind != actual.kind:
|
||||
echo "expected " & $expected.kind & ", got " & $actual.kind
|
||||
|
@ -56,8 +62,8 @@ proc printDifference(expected, actual: YamlParserEvent) =
|
|||
echo "[\"", actual.scalarContent, "\".tag] expected tag ",
|
||||
expected.scalarTag, ", got ", actual.scalarTag
|
||||
elif expected.scalarAnchor != actual.scalarAnchor:
|
||||
echo "[scalar] expected anchor " & expected.scalarAnchor &
|
||||
", got " & actual.scalarAnchor
|
||||
echo "[scalar] expected anchor ", expected.scalarAnchor,
|
||||
", got ", actual.scalarAnchor
|
||||
elif expected.scalarContent != actual.scalarContent:
|
||||
let msg = "[scalar] expected content \"" &
|
||||
expected.scalarContent & "\", got \"" &
|
||||
|
@ -77,8 +83,16 @@ proc printDifference(expected, actual: YamlParserEvent) =
|
|||
echo "[scalar] Unknown difference"
|
||||
of yamlStartMap, yamlStartSequence:
|
||||
if expected.objTag != actual.objTag:
|
||||
echo "[object.tag] expected ", expected.objTag, ", got",
|
||||
echo "[object.tag] expected ", expected.objTag, ", got ",
|
||||
actual.objTag
|
||||
else:
|
||||
echo "[object.tag] Unknown difference"
|
||||
of yamlAlias:
|
||||
if expected.aliasTarget != actual.aliasTarget:
|
||||
echo "[alias] expected ", expected.aliasTarget, ", got ",
|
||||
actual.aliasTarget
|
||||
else:
|
||||
echo "[alias] Unknown difference"
|
||||
else:
|
||||
echo "Unknown difference in event kind " & $expected.kind
|
||||
|
||||
|
@ -138,9 +152,10 @@ suite "Parsing":
|
|||
startSequence(), scalar("b"), scalar("c"), endSequence(),
|
||||
endSequence(), endDoc())
|
||||
test "Parsing: Flow Sequence in Flow Map":
|
||||
ensure("{a: [b, c]}", startDoc(), startMap(), scalar("a"),
|
||||
ensure("{a: [b, c], [d, e]: f}", startDoc(), startMap(), scalar("a"),
|
||||
startSequence(), scalar("b"), scalar("c"), endSequence(),
|
||||
endMap(), endDoc())
|
||||
startSequence(), scalar("d"), scalar("e"), endSequence(),
|
||||
scalar("f"), endMap(), endDoc())
|
||||
test "Parsing: Flow Sequence in Map":
|
||||
ensure("a: [b, c]", startDoc(), startMap(), scalar("a"),
|
||||
startSequence(), scalar("b"), scalar("c"), endSequence(),
|
||||
|
@ -168,9 +183,9 @@ suite "Parsing":
|
|||
ensure("a: |-\x0A ab\x0A \x0A \x0A", startDoc(), startMap(),
|
||||
scalar("a"), scalar("ab"), endMap(), endDoc())
|
||||
test "Parsing: non-specific tags of quoted strings":
|
||||
ensure("\"a\"", startDoc(), scalar("a", tagNonSpecificEmark), endDoc())
|
||||
ensure("\"a\"", startDoc(), scalar("a", tagExclamationMark), endDoc())
|
||||
test "Parsing: explicit non-specific tag":
|
||||
ensure("! a", startDoc(), scalar("a", tagNonSpecificEmark), endDoc())
|
||||
ensure("! a", startDoc(), scalar("a", tagExclamationMark), endDoc())
|
||||
test "Parsing: secondary tag handle resolution":
|
||||
let id = parser.registerUri("tag:yaml.org,2002:str")
|
||||
ensure("!!str a", startDoc(), scalar("a", id), endDoc())
|
||||
|
@ -208,3 +223,44 @@ suite "Parsing":
|
|||
ensure("!!map { k: !!seq [ a, !!str b] }", startDoc(), startMap(idMap),
|
||||
scalar("k"), startSequence(idSeq), scalar("a"),
|
||||
scalar("b", idStr), endSequence(), endMap(), endDoc())
|
||||
test "Parsing: Simple Anchor":
|
||||
ensure("&a str", startDoc(), scalar("str", tagQuestionMark,
|
||||
0.AnchorId), endDoc())
|
||||
test "Parsing: Anchors in sequence":
|
||||
ensure(" - &a a\n - b\n - &c c\n - &a d", startDoc(), startSequence(),
|
||||
scalar("a", tagQuestionMark, 0.AnchorId), scalar("b"),
|
||||
scalar("c", tagQuestionMark, 1.AnchorId),
|
||||
scalar("d", tagQuestionMark, 0.AnchorId), endSequence(),
|
||||
endDoc())
|
||||
test "Parsing: Anchors in map":
|
||||
ensure("&a a: b\nc: &d d", startDoc(), startMap(),
|
||||
scalar("a", tagQuestionMark, 0.AnchorId),
|
||||
scalar("b"), scalar("c"),
|
||||
scalar("d", tagQuestionMark, 1.AnchorId),
|
||||
endMap(), endDoc())
|
||||
test "Parsing: Anchors and tags":
|
||||
let
|
||||
idStr = parser.registerUri("tag:yaml.org,2002:str")
|
||||
idInt = parser.registerUri("tag:yaml.org,2002:int")
|
||||
ensure(" - &a !!str a\n - !!int b\n - &c !!int c\n - &d d", startDoc(),
|
||||
startSequence(), scalar("a", idStr, 0.AnchorId),
|
||||
scalar("b", idInt), scalar("c", idInt, 1.AnchorId),
|
||||
scalar("d", tagQuestionMark, 2.AnchorId), endSequence(),
|
||||
endDoc())
|
||||
test "Parsing: Aliases in sequence":
|
||||
ensure(" - &a a\n - &b b\n - *a\n - *b", startDoc(), startSequence(),
|
||||
scalar("a", tagQuestionMark, 0.AnchorId),
|
||||
scalar("b", tagQuestionMark, 1.AnchorId), alias(0.AnchorId),
|
||||
alias(1.AnchorId), endSequence(), endDoc())
|
||||
test "Parsing: Aliases in map":
|
||||
ensure("&a a: &b b\n*a: *b", startDoc(), startMap(),
|
||||
scalar("a", tagQuestionMark, 0.AnchorId),
|
||||
scalar("b", tagQuestionMark, 1.AnchorId), alias(0.AnchorId),
|
||||
alias(1.AnchorId), endMap(), endDoc())
|
||||
test "Parsing: Aliases in flow":
|
||||
ensure("{ &a [a, &b b]: *b, *a: [c, *b, d]}", startDoc(), startMap(),
|
||||
startSequence(tagQuestionMark, 0.AnchorId), scalar("a"),
|
||||
scalar("b", tagQuestionMark, 1.AnchorId), endSequence(),
|
||||
alias(1.AnchorId), alias(0.AnchorId), startSequence(),
|
||||
scalar("c"), alias(1.AnchorId), scalar("d"), endSequence(),
|
||||
endMap(), endDoc())
|
Loading…
Reference in New Issue