2015-12-05 11:10:17 +00:00
|
|
|
import streams, tables, strutils
|
|
|
|
|
2015-12-07 21:09:57 +00:00
|
|
|
import "private/lexer"
|
2015-12-05 11:10:17 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
YamlParserEventKind* = enum
|
|
|
|
yamlStartDocument, yamlEndDocument, yamlStartMap, yamlEndMap,
|
|
|
|
yamlStartSequence, yamlEndSequence, yamlScalar, yamlAlias,
|
|
|
|
yamlError, yamlWarning
|
|
|
|
|
2015-12-21 20:58:28 +00:00
|
|
|
TagId* = distinct int
|
|
|
|
|
2015-12-05 11:10:17 +00:00
|
|
|
YamlParserEvent* = ref object
|
|
|
|
case kind*: YamlParserEventKind
|
|
|
|
of yamlStartMap, yamlStartSequence:
|
|
|
|
objAnchor* : string # may be nil, may not be empty
|
2015-12-21 20:58:28 +00:00
|
|
|
objTag* : TagId
|
2015-12-05 11:10:17 +00:00
|
|
|
of yamlScalar:
|
|
|
|
scalarAnchor* : string # may be nil
|
2015-12-21 20:58:28 +00:00
|
|
|
scalarTag* : TagId
|
2015-12-05 11:10:17 +00:00
|
|
|
scalarContent*: string # may not be nil (but empty)
|
|
|
|
of yamlEndMap, yamlEndSequence, yamlStartDocument, yamlEndDocument:
|
|
|
|
discard
|
|
|
|
of yamlAlias:
|
|
|
|
aliasName* : string # may not be nil nor empty
|
|
|
|
of yamlError, yamlWarning:
|
|
|
|
description* : string
|
|
|
|
line* : int
|
|
|
|
column* : int
|
|
|
|
|
|
|
|
YamlParserState = enum
|
2015-12-11 21:55:21 +00:00
|
|
|
ylInitial, ylSkipDirective, ylBlockLineStart, ylBlockAfterTag,
|
2015-12-21 20:40:27 +00:00
|
|
|
ylBlockAfterAnchor, ylBlockAfterAnchorAndTag, ylBlockAfterScalar,
|
|
|
|
ylBlockAfterColon, ylBlockMultilineScalar, ylBlockLineEnd,
|
|
|
|
ylBlockScalarHeader, ylBlockScalar, ylFlow, ylFlowAfterObject,
|
|
|
|
ylExpectingDocumentEnd
|
2015-12-05 11:10:17 +00:00
|
|
|
|
2015-12-11 21:55:21 +00:00
|
|
|
DocumentLevelMode = enum
|
|
|
|
mBlockSequenceItem, mFlowSequenceItem, mExplicitBlockMapKey,
|
|
|
|
mExplicitBlockMapValue, mImplicitBlockMapKey, mImplicitBlockMapValue,
|
2015-12-17 20:44:41 +00:00
|
|
|
mFlowMapKey, mFlowMapValue, mScalar, mUnknown
|
2015-12-05 11:10:17 +00:00
|
|
|
|
|
|
|
DocumentLevel = object
|
2015-12-11 21:55:21 +00:00
|
|
|
mode: DocumentLevelMode
|
2015-12-05 11:10:17 +00:00
|
|
|
indicatorColumn: int
|
2015-12-11 21:55:21 +00:00
|
|
|
indentationColumn: int
|
2015-12-17 20:44:41 +00:00
|
|
|
|
|
|
|
LineStrippingMode = enum
|
|
|
|
lsStrip, lsClip, lsKeep
|
|
|
|
|
|
|
|
BlockScalarStyle = enum
|
|
|
|
bsLiteral, bsFolded
|
2015-12-21 20:40:27 +00:00
|
|
|
|
|
|
|
YamlSequentialParser* = object
|
|
|
|
tags: OrderedTable[string, TagId]
|
|
|
|
|
|
|
|
const
|
|
|
|
tagNonSpecificEmark*: TagId = 0.TagId # "!" non-specific tag
|
|
|
|
tagNonSpecificQmark*: TagId = 1.TagId # "?" non-specific tag
|
|
|
|
|
|
|
|
# interface
|
|
|
|
|
|
|
|
proc `==`*(left: YamlParserEvent, right: YamlParserEvent): bool
|
|
|
|
|
|
|
|
proc `==`*(left, right: TagId): bool {.borrow.}
|
2015-12-21 20:58:28 +00:00
|
|
|
proc `$`*(id: TagId): string {.borrow.}
|
2015-12-21 20:40:27 +00:00
|
|
|
|
|
|
|
proc initParser*(): YamlSequentialParser
|
|
|
|
|
|
|
|
# iterators cannot be pre-declared.
|
|
|
|
#
|
|
|
|
# iterator events*(parser: YamlSequentialParser,
|
|
|
|
# input: Stream): YamlParserEvent
|
|
|
|
|
|
|
|
proc uri*(parser: YamlSequentialParser, id: TagId): string
|
|
|
|
|
|
|
|
proc registerUri*(parser: var YamlSequentialParser, uri: string): TagId
|
|
|
|
|
|
|
|
# implementation
|
|
|
|
|
|
|
|
proc initParser*(): YamlSequentialParser =
|
|
|
|
result.tags = initOrderedTable[string, TagId]()
|
|
|
|
result.tags["!"] = tagNonSpecificEmark
|
|
|
|
result.tags["?"] = tagNonSpecificQmark
|
|
|
|
|
|
|
|
proc uri*(parser: YamlSequentialParser, id: TagId): string =
|
|
|
|
for pair in parser.tags.pairs:
|
|
|
|
if pair[1] == id:
|
|
|
|
return pair[0]
|
|
|
|
return nil
|
|
|
|
|
|
|
|
proc registerUri*(parser: var YamlSequentialParser, uri: string): TagId =
|
|
|
|
result = cast[TagId](parser.tags.len)
|
|
|
|
if parser.tags.hasKeyOrPut(uri, result):
|
|
|
|
result = parser.tags[uri]
|
2015-12-07 21:09:57 +00:00
|
|
|
|
|
|
|
proc `==`*(left: YamlParserEvent, right: YamlParserEvent): bool =
|
|
|
|
if left.kind != right.kind:
|
|
|
|
return false
|
|
|
|
case left.kind
|
|
|
|
of yamlStartDocument, yamlEndDocument, yamlEndMap, yamlEndSequence:
|
|
|
|
result = true
|
|
|
|
of yamlStartMap, yamlStartSequence:
|
|
|
|
result = left.objAnchor == right.objAnchor and
|
|
|
|
left.objTag == right.objTag
|
|
|
|
of yamlScalar:
|
|
|
|
result = left.scalarAnchor == right.scalarAnchor and
|
|
|
|
left.scalarTag == right.scalarTag and
|
|
|
|
left.scalarContent == right.scalarContent
|
|
|
|
of yamlAlias:
|
|
|
|
result = left.aliasName == right.aliasName
|
|
|
|
of yamlError, yamlWarning:
|
|
|
|
result = left.description == right.description and
|
|
|
|
left.line == right.line and left.column == right.column
|
2015-12-05 11:10:17 +00:00
|
|
|
|
|
|
|
template yieldWarning(d: string) {.dirty.} =
|
|
|
|
yield YamlParserEvent(kind: yamlWarning, description: d,
|
|
|
|
line: lex.line, column: lex.column)
|
|
|
|
|
|
|
|
template yieldError(d: string) {.dirty.} =
|
|
|
|
yield YamlParserEvent(kind: yamlError, description: d,
|
|
|
|
line: lex.line, column: lex.column)
|
2015-12-11 21:55:21 +00:00
|
|
|
break parserLoop
|
2015-12-05 11:10:17 +00:00
|
|
|
|
2015-12-21 20:40:27 +00:00
|
|
|
template yieldScalar(content: string = "", quoted: bool = false) {.dirty.} =
|
2015-12-21 20:58:28 +00:00
|
|
|
var retTag: TagId
|
|
|
|
if isNil(tag):
|
|
|
|
retTag = if quoted: tagNonSpecificEmark else: tagNonSpecificQmark
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
retTag = parser.tags[tag]
|
|
|
|
except KeyError:
|
|
|
|
retTag = cast[TagId](parser.tags.len)
|
|
|
|
parser.tags[tag] = retTag
|
|
|
|
|
2015-12-11 21:55:21 +00:00
|
|
|
yield YamlParserEvent(kind: yamlScalar,
|
2015-12-21 20:40:27 +00:00
|
|
|
scalarAnchor: anchor, scalarTag: retTag,
|
2015-12-11 21:55:21 +00:00
|
|
|
scalarContent: content)
|
|
|
|
anchor = nil
|
|
|
|
tag = nil
|
2015-12-05 11:10:17 +00:00
|
|
|
|
2015-12-11 21:55:21 +00:00
|
|
|
template yieldStart(k: YamlParserEventKind) {.dirty.} =
|
2015-12-21 20:58:28 +00:00
|
|
|
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
|
|
|
|
|
2015-12-21 20:40:27 +00:00
|
|
|
yield YamlParserEvent(kind: k, objAnchor: anchor, objTag: retTag)
|
2015-12-11 21:55:21 +00:00
|
|
|
anchor = nil
|
|
|
|
tag = nil
|
2015-12-05 11:10:17 +00:00
|
|
|
|
2015-12-11 21:55:21 +00:00
|
|
|
template closeLevel(lvl: DocumentLevel) {.dirty.} =
|
|
|
|
case lvl.mode
|
|
|
|
of mExplicitBlockMapKey, mFlowMapKey:
|
|
|
|
yieldError("Missing Map value!")
|
|
|
|
of mExplicitBlockMapValue, mImplicitBlockMapKey, mImplicitBlockMapValue,
|
|
|
|
mFlowMapValue:
|
|
|
|
yield YamlParserEvent(kind: yamlEndMap)
|
|
|
|
of mBlockSequenceItem, mFlowSequenceItem:
|
|
|
|
yield YamlParserEvent(kind: yamlEndSequence)
|
2015-12-14 20:26:34 +00:00
|
|
|
of mScalar:
|
2015-12-21 20:58:28 +00:00
|
|
|
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
|
2015-12-21 20:40:27 +00:00
|
|
|
|
2015-12-14 20:26:34 +00:00
|
|
|
yield YamlParserEvent(kind: yamlScalar, scalarAnchor: anchor,
|
2015-12-21 20:40:27 +00:00
|
|
|
scalarTag: retTag, scalarContent: scalarCache)
|
2015-12-14 20:26:34 +00:00
|
|
|
anchor = nil
|
|
|
|
tag = nil
|
2015-12-11 21:55:21 +00:00
|
|
|
else:
|
|
|
|
yieldScalar()
|
|
|
|
|
|
|
|
template leaveMoreIndentedLevels() {.dirty.} =
|
2015-12-14 20:26:34 +00:00
|
|
|
while ancestry.len > 0:
|
|
|
|
let parent = ancestry[ancestry.high]
|
|
|
|
if parent.indicatorColumn >= lex.column or
|
|
|
|
(parent.indicatorColumn == -1 and
|
|
|
|
parent.indentationColumn >= lex.column):
|
|
|
|
closeLevel(level)
|
|
|
|
level = ancestry.pop()
|
|
|
|
if level.mode == mImplicitBlockMapValue:
|
|
|
|
level.mode = mImplicitBlockMapKey
|
|
|
|
else:
|
|
|
|
break
|
2015-12-11 21:55:21 +00:00
|
|
|
|
2015-12-07 21:09:57 +00:00
|
|
|
template closeAllLevels() {.dirty.} =
|
2015-12-11 21:55:21 +00:00
|
|
|
while true:
|
|
|
|
closeLevel(level)
|
|
|
|
if ancestry.len == 0: break
|
|
|
|
level = ancestry.pop()
|
|
|
|
|
|
|
|
template handleBlockIndicator(expected, next: DocumentLevelMode,
|
|
|
|
entering: YamlParserEventKind) {.dirty.} =
|
|
|
|
leaveMoreIndentedLevels()
|
|
|
|
if level.indicatorColumn == lex.column:
|
|
|
|
if level.mode == expected:
|
|
|
|
level.mode = next
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
|
|
|
else:
|
|
|
|
yieldError("Invalid token after " & $level.mode)
|
|
|
|
elif level.mode != mUnknown:
|
|
|
|
yieldError("Invalid indentation")
|
|
|
|
elif entering == yamlError:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
|
|
|
else:
|
|
|
|
level.mode = next
|
|
|
|
level.indicatorColumn = lex.column
|
2015-12-21 20:40:27 +00:00
|
|
|
yieldStart(entering)
|
2015-12-11 21:55:21 +00:00
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
2015-12-07 21:09:57 +00:00
|
|
|
|
2015-12-21 20:40:27 +00:00
|
|
|
template startPlainScalar() {.dirty.} =
|
|
|
|
level.mode = mScalar
|
|
|
|
scalarCache = lex.content
|
|
|
|
state = ylBlockAfterScalar
|
|
|
|
|
|
|
|
template handleTagHandle() {.dirty.} =
|
|
|
|
let handle = lex.content
|
|
|
|
if tagShorthands.hasKey(handle):
|
|
|
|
token = nextToken(lex)
|
|
|
|
if finished(nextToken):
|
|
|
|
yieldError("Missing tag suffix")
|
|
|
|
continue
|
|
|
|
if token != yamlTagSuffix:
|
|
|
|
yieldError("Missing tag suffix")
|
|
|
|
continue
|
|
|
|
tag = tagShorthands[handle] & lex.content
|
|
|
|
level.indentationColumn = lex.column
|
|
|
|
else:
|
|
|
|
yieldError("Unknown tag shorthand: " & handle)
|
|
|
|
|
2015-12-21 20:58:28 +00:00
|
|
|
iterator events*(parser: var YamlSequentialParser,
|
2015-12-21 20:40:27 +00:00
|
|
|
input: Stream): YamlParserEvent {.closure.} =
|
2015-12-05 11:10:17 +00:00
|
|
|
var
|
2015-12-14 20:26:34 +00:00
|
|
|
# parsing state
|
2015-12-11 21:55:21 +00:00
|
|
|
lex: YamlLexer
|
2015-12-14 20:26:34 +00:00
|
|
|
state = ylInitial
|
|
|
|
|
|
|
|
# document state
|
2015-12-05 11:10:17 +00:00
|
|
|
foundYamlDirective = false
|
|
|
|
tagShorthands = initTable[string, string]()
|
2015-12-14 20:26:34 +00:00
|
|
|
|
|
|
|
# object tree state
|
2015-12-11 21:55:21 +00:00
|
|
|
ancestry = newSeq[DocumentLevel]()
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
2015-12-14 20:26:34 +00:00
|
|
|
|
2015-12-17 20:44:41 +00:00
|
|
|
# block scalar state
|
|
|
|
lineStrip: LineStrippingMode
|
|
|
|
blockScalar: BlockScalarStyle
|
|
|
|
blockScalarIndentation: int
|
|
|
|
blockScalarTrailing: string = nil
|
|
|
|
|
2015-12-14 20:26:34 +00:00
|
|
|
# cached values
|
2015-12-11 21:55:21 +00:00
|
|
|
tag: string = nil
|
|
|
|
anchor: string = nil
|
2015-12-14 20:26:34 +00:00
|
|
|
scalarCache: string = nil
|
|
|
|
scalarIndentation: int
|
2015-12-21 20:40:27 +00:00
|
|
|
scalarCacheIsQuoted: bool = false
|
2015-12-14 20:26:34 +00:00
|
|
|
|
2015-12-05 11:10:17 +00:00
|
|
|
lex.open(input)
|
|
|
|
|
2015-12-07 21:09:57 +00:00
|
|
|
var nextToken = tokens
|
2015-12-05 11:10:17 +00:00
|
|
|
var token = nextToken(lex)
|
2015-12-11 21:55:21 +00:00
|
|
|
block parserLoop:
|
|
|
|
while not finished(nextToken):
|
2015-12-05 11:10:17 +00:00
|
|
|
case state
|
|
|
|
of ylInitial:
|
2015-12-11 21:55:21 +00:00
|
|
|
case token
|
2015-12-05 11:10:17 +00:00
|
|
|
of yamlYamlDirective:
|
|
|
|
if foundYamlDirective:
|
2015-12-11 21:55:21 +00:00
|
|
|
yieldError("Duplicate %YAML directive")
|
|
|
|
var
|
|
|
|
warn = false
|
|
|
|
actualVersion = ""
|
|
|
|
for version in [1, 2]:
|
|
|
|
token = nextToken(lex)
|
|
|
|
if finished(nextToken):
|
|
|
|
yieldError("Missing or badly formatted YAML version")
|
|
|
|
if token != yamlVersionPart:
|
|
|
|
yieldError("Missing or badly formatted YAML version")
|
|
|
|
if parseInt(lex.content) != version:
|
|
|
|
warn = true
|
|
|
|
if actualVersion.len > 0: actualVersion &= "."
|
|
|
|
actualVersion &= $version
|
|
|
|
if warn:
|
|
|
|
yieldWarning("Unsupported version: " & actualVersion &
|
|
|
|
", trying to parse anyway")
|
|
|
|
foundYamlDirective = true
|
2015-12-05 11:10:17 +00:00
|
|
|
of yamlTagDirective:
|
|
|
|
token = nextToken(lex)
|
|
|
|
if finished(nextToken):
|
|
|
|
yieldError("Incomplete %TAG directive")
|
2015-12-11 21:55:21 +00:00
|
|
|
if token != yamlTagHandle:
|
2015-12-05 11:10:17 +00:00
|
|
|
yieldError("Invalid token (expected tag handle)")
|
|
|
|
let tagHandle = lex.content
|
|
|
|
token = nextToken(lex)
|
|
|
|
if finished(nextToken):
|
|
|
|
yieldError("Incomplete %TAG directive")
|
2015-12-11 21:55:21 +00:00
|
|
|
if token != yamlTagURI:
|
2015-12-05 11:10:17 +00:00
|
|
|
yieldError("Invalid token (expected tag URI)")
|
|
|
|
tagShorthands[tagHandle] = lex.content
|
|
|
|
of yamlUnknownDirective:
|
|
|
|
yieldWarning("Unknown directive: " & lex.content)
|
|
|
|
state = ylSkipDirective
|
|
|
|
of yamlComment:
|
|
|
|
discard
|
|
|
|
of yamlDirectivesEnd:
|
|
|
|
yield YamlParserEvent(kind: yamlStartDocument)
|
2015-12-11 21:55:21 +00:00
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
|
|
|
state = ylBlockLineStart
|
2015-12-07 21:09:57 +00:00
|
|
|
of yamlDocumentEnd, yamlStreamEnd:
|
2015-12-05 11:10:17 +00:00
|
|
|
yield YamlParserEvent(kind: yamlStartDocument)
|
|
|
|
yield YamlParserEvent(kind: yamlEndDocument)
|
|
|
|
else:
|
|
|
|
yield YamlParserEvent(kind: yamlStartDocument)
|
2015-12-07 21:09:57 +00:00
|
|
|
state = ylBlockLineStart
|
2015-12-05 11:10:17 +00:00
|
|
|
continue
|
|
|
|
of ylSkipDirective:
|
2015-12-11 21:55:21 +00:00
|
|
|
if token notin [yamlUnknownDirectiveParam, yamlTagHandle,
|
|
|
|
yamlTagURI, yamlVersionPart, yamlComment]:
|
2015-12-05 11:10:17 +00:00
|
|
|
state = ylInitial
|
|
|
|
continue
|
2015-12-07 21:09:57 +00:00
|
|
|
of ylBlockLineStart:
|
2015-12-11 21:55:21 +00:00
|
|
|
case token
|
2015-12-05 11:10:17 +00:00
|
|
|
of yamlLineStart:
|
|
|
|
discard
|
|
|
|
of yamlDash:
|
2015-12-11 21:55:21 +00:00
|
|
|
handleBlockIndicator(mBlockSequenceItem, mBlockSequenceItem,
|
|
|
|
yamlStartSequence)
|
|
|
|
of yamlQuestionmark:
|
|
|
|
handleBlockIndicator(mExplicitBlockMapValue,
|
|
|
|
mExplicitBlockMapKey, yamlStartMap)
|
|
|
|
of yamlColon:
|
|
|
|
handleBlockIndicator(mExplicitBlockMapKey,
|
|
|
|
mExplicitBlockMapValue, yamlError)
|
2015-12-17 20:44:41 +00:00
|
|
|
of yamlPipe, yamlGreater:
|
|
|
|
blockScalar = if token == yamlPipe: bsLiteral else: bsFolded
|
|
|
|
blockScalarIndentation = -1
|
|
|
|
lineStrip = lsClip
|
|
|
|
state = ylBlockScalarHeader
|
|
|
|
scalarCache = ""
|
|
|
|
level.mode = mScalar
|
2015-12-07 21:09:57 +00:00
|
|
|
of yamlTagHandle:
|
2015-12-21 20:40:27 +00:00
|
|
|
handleTagHandle()
|
|
|
|
state = ylBlockAfterTag
|
2015-12-07 21:09:57 +00:00
|
|
|
of yamlVerbatimTag:
|
2015-12-11 21:55:21 +00:00
|
|
|
tag = lex.content
|
2015-12-21 20:40:27 +00:00
|
|
|
state = ylBlockAfterTag
|
|
|
|
level.indentationColumn = lex.column
|
2015-12-11 21:55:21 +00:00
|
|
|
of yamlAnchor:
|
|
|
|
anchor = lex.content
|
2015-12-21 20:40:27 +00:00
|
|
|
level.indentationColumn = lex.column
|
2015-12-11 21:55:21 +00:00
|
|
|
state = ylBlockAfterAnchor
|
2015-12-14 20:26:34 +00:00
|
|
|
of yamlScalarPart:
|
|
|
|
leaveMoreIndentedLevels()
|
|
|
|
case level.mode
|
|
|
|
of mUnknown:
|
2015-12-21 20:40:27 +00:00
|
|
|
startPlainScalar()
|
|
|
|
level.indentationColumn = lex.column
|
2015-12-14 20:26:34 +00:00
|
|
|
of mImplicitBlockMapKey:
|
|
|
|
scalarCache = lex.content
|
2015-12-21 20:40:27 +00:00
|
|
|
scalarCacheIsQuoted = false
|
2015-12-14 20:26:34 +00:00
|
|
|
scalarIndentation = lex.column
|
|
|
|
of mImplicitBlockMapValue:
|
|
|
|
ancestry.add(level)
|
|
|
|
scalarCache = lex.content
|
2015-12-21 20:40:27 +00:00
|
|
|
scalarCacheIsQuoted = false
|
2015-12-14 20:26:34 +00:00
|
|
|
scalarIndentation = lex.column
|
|
|
|
level = DocumentLevel(mode: mScalar, indicatorColumn: -1,
|
|
|
|
indentationColumn:
|
|
|
|
ancestry[ancestry.high].indentationColumn + 1)
|
|
|
|
else:
|
|
|
|
yieldError("Unexpected scalar")
|
|
|
|
state = ylBlockAfterScalar
|
2015-12-07 21:09:57 +00:00
|
|
|
of lexer.yamlScalar:
|
2015-12-11 21:55:21 +00:00
|
|
|
leaveMoreIndentedLevels()
|
|
|
|
case level.mode
|
|
|
|
of mUnknown, mImplicitBlockMapKey:
|
2015-12-14 20:26:34 +00:00
|
|
|
scalarCache = lex.content
|
2015-12-21 20:40:27 +00:00
|
|
|
scalarCacheIsQuoted = true
|
2015-12-14 20:26:34 +00:00
|
|
|
scalarIndentation = lex.column
|
2015-12-11 21:55:21 +00:00
|
|
|
state = ylBlockAfterScalar
|
|
|
|
else:
|
|
|
|
yieldError("Unexpected scalar")
|
2015-12-07 21:09:57 +00:00
|
|
|
of yamlStreamEnd:
|
|
|
|
closeAllLevels()
|
|
|
|
yield YamlParserEvent(kind: yamlEndDocument)
|
|
|
|
break
|
|
|
|
of yamlDocumentEnd:
|
|
|
|
closeAllLevels()
|
|
|
|
yield YamlParserEvent(kind: yamlEndDocument)
|
|
|
|
state = ylInitial
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlOpeningBrace:
|
|
|
|
state = ylFlow
|
|
|
|
continue
|
|
|
|
of yamlOpeningBracket:
|
|
|
|
state = ylFlow
|
|
|
|
continue
|
2015-12-07 21:09:57 +00:00
|
|
|
else:
|
2015-12-14 20:26:34 +00:00
|
|
|
yieldError("[block line start] Unexpected token: " & $token)
|
|
|
|
of ylBlockMultilineScalar:
|
|
|
|
case token
|
|
|
|
of yamlScalarPart:
|
|
|
|
leaveMoreIndentedLevels()
|
|
|
|
if level.mode != mScalar:
|
|
|
|
state = ylBlockLineStart
|
|
|
|
continue
|
|
|
|
scalarCache &= " " & lex.content
|
|
|
|
state = ylBlockLineEnd
|
|
|
|
of yamlLineStart:
|
|
|
|
discard
|
|
|
|
of yamlColon, yamlDash, yamlQuestionMark:
|
|
|
|
leaveMoreIndentedLevels()
|
|
|
|
if level.mode != mScalar:
|
|
|
|
state = ylBlockLineStart
|
|
|
|
continue
|
|
|
|
yieldError("[multiline scalar ?:-] Unexpected token: " & $token)
|
|
|
|
of yamlDocumentEnd, yamlStreamEnd:
|
|
|
|
closeAllLevels()
|
|
|
|
scalarCache = nil
|
|
|
|
state = ylExpectingDocumentEnd
|
|
|
|
continue
|
|
|
|
of yamlDirectivesEnd:
|
|
|
|
closeAllLevels()
|
|
|
|
state = ylInitial
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
yieldError("[multiline scalar] Unexpected token: " & $token)
|
2015-12-07 21:09:57 +00:00
|
|
|
of ylBlockAfterScalar:
|
2015-12-11 21:55:21 +00:00
|
|
|
case token
|
2015-12-05 11:10:17 +00:00
|
|
|
of yamlColon:
|
2015-12-14 20:26:34 +00:00
|
|
|
assert level.mode in [mUnknown, mImplicitBlockMapKey, mScalar]
|
|
|
|
if level.mode in [mUnknown, mScalar]:
|
|
|
|
level.indentationColumn = scalarIndentation
|
2015-12-21 20:40:27 +00:00
|
|
|
# tags and anchors are for key scalar, not for map.
|
|
|
|
yield YamlParserEvent(kind: yamlStartMap,
|
2015-12-21 20:58:28 +00:00
|
|
|
objAnchor: nil,
|
|
|
|
objTag: tagNonSpecificQmark)
|
2015-12-11 21:55:21 +00:00
|
|
|
level.mode = mImplicitBlockMapValue
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
2015-12-21 20:40:27 +00:00
|
|
|
yieldScalar(scalarCache, scalarCacheIsQuoted)
|
2015-12-14 20:26:34 +00:00
|
|
|
scalarCache = nil
|
2015-12-07 21:09:57 +00:00
|
|
|
state = ylBlockAfterColon
|
|
|
|
of yamlLineStart:
|
2015-12-11 21:55:21 +00:00
|
|
|
if level.mode == mImplicitBlockMapKey:
|
|
|
|
yieldError("Missing colon after implicit map key")
|
2015-12-14 20:26:34 +00:00
|
|
|
if level.mode != mScalar:
|
2015-12-21 20:40:27 +00:00
|
|
|
yieldScalar(scalarCache, scalarCacheIsQuoted)
|
2015-12-14 20:26:34 +00:00
|
|
|
scalarCache = nil
|
|
|
|
if ancestry.len > 0:
|
|
|
|
level = ancestry.pop()
|
|
|
|
else:
|
|
|
|
state = ylExpectingDocumentEnd
|
2015-12-11 21:55:21 +00:00
|
|
|
else:
|
2015-12-14 20:26:34 +00:00
|
|
|
state = ylBlockMultilineScalar
|
2015-12-07 21:09:57 +00:00
|
|
|
of yamlStreamEnd:
|
2015-12-21 20:40:27 +00:00
|
|
|
yieldScalar(scalarCache, scalarCacheIsQuoted)
|
2015-12-14 20:26:34 +00:00
|
|
|
scalarCache = nil
|
2015-12-11 21:55:21 +00:00
|
|
|
if ancestry.len > 0:
|
|
|
|
level = ancestry.pop()
|
|
|
|
closeAllLevels()
|
2015-12-07 21:09:57 +00:00
|
|
|
yield YamlParserEvent(kind: yamlEndDocument)
|
|
|
|
break
|
|
|
|
else:
|
2015-12-11 21:55:21 +00:00
|
|
|
yieldError("Unexpected token: " & $token)
|
|
|
|
of ylBlockAfterTag:
|
|
|
|
case token
|
|
|
|
of yamlAnchor:
|
|
|
|
anchor = lex.content
|
2015-12-21 20:40:27 +00:00
|
|
|
state = ylBlockAfterAnchorAndTag
|
2015-12-11 21:55:21 +00:00
|
|
|
of lexer.yamlScalar:
|
|
|
|
state = ylBlockLineStart
|
|
|
|
continue
|
2015-12-21 20:40:27 +00:00
|
|
|
of yamlScalarPart:
|
|
|
|
startPlainScalar()
|
2015-12-11 21:55:21 +00:00
|
|
|
of yamlLineStart:
|
|
|
|
state = ylBlockLineStart
|
|
|
|
of yamlOpeningBracket, yamlOpeningBrace:
|
|
|
|
state = ylFlow
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
|
|
|
of ylBlockAfterAnchor:
|
|
|
|
case token
|
|
|
|
of lexer.yamlScalar:
|
|
|
|
state = ylBlockLineStart
|
|
|
|
continue
|
2015-12-21 20:40:27 +00:00
|
|
|
of lexer.yamlScalarPart:
|
|
|
|
startPlainScalar()
|
2015-12-11 21:55:21 +00:00
|
|
|
of yamlLineStart:
|
2015-12-21 20:40:27 +00:00
|
|
|
discard
|
|
|
|
of yamlOpeningBracket, yamlOpeningBrace:
|
|
|
|
state = ylFlow
|
|
|
|
continue
|
|
|
|
of yamlTagHandle:
|
|
|
|
handleTagHandle()
|
|
|
|
state = ylBlockAfterTag
|
|
|
|
of yamlVerbatimTag:
|
|
|
|
tag = lex.content
|
|
|
|
state = ylBlockAfterTag
|
|
|
|
level.indentationColumn = lex.column
|
|
|
|
else:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
|
|
|
of ylBlockAfterAnchorAndTag:
|
|
|
|
case token
|
|
|
|
of lexer.yamlScalar:
|
2015-12-11 21:55:21 +00:00
|
|
|
state = ylBlockLineStart
|
2015-12-21 20:40:27 +00:00
|
|
|
continue
|
|
|
|
of yamlScalarPart:
|
|
|
|
startPlainScalar()
|
|
|
|
of yamlLineStart:
|
|
|
|
discard
|
2015-12-11 21:55:21 +00:00
|
|
|
of yamlOpeningBracket, yamlOpeningBrace:
|
|
|
|
state = ylFlow
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
2015-12-07 21:09:57 +00:00
|
|
|
of ylBlockAfterColon:
|
2015-12-11 21:55:21 +00:00
|
|
|
case token
|
2015-12-07 21:09:57 +00:00
|
|
|
of lexer.yamlScalar:
|
2015-12-21 20:40:27 +00:00
|
|
|
yieldScalar(lex.content, true)
|
2015-12-11 21:55:21 +00:00
|
|
|
level = ancestry.pop()
|
|
|
|
assert level.mode == mImplicitBlockMapValue
|
|
|
|
level.mode = mImplicitBlockMapKey
|
2015-12-07 21:09:57 +00:00
|
|
|
state = ylBlockLineEnd
|
2015-12-14 20:26:34 +00:00
|
|
|
of yamlScalarPart:
|
2015-12-21 20:40:27 +00:00
|
|
|
startPlainScalar()
|
2015-12-07 21:09:57 +00:00
|
|
|
of yamlLineStart:
|
|
|
|
state = ylBlockLineStart
|
|
|
|
of yamlStreamEnd:
|
|
|
|
closeAllLevels()
|
|
|
|
yield YamlParserEvent(kind: yamlEndDocument)
|
|
|
|
break
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlOpeningBracket, yamlOpeningBrace:
|
|
|
|
state = ylFlow
|
|
|
|
continue
|
2015-12-17 20:44:41 +00:00
|
|
|
of yamlPipe, yamlGreater:
|
|
|
|
blockScalar = if token == yamlPipe: bsLiteral else: bsFolded
|
|
|
|
blockScalarIndentation = -1
|
|
|
|
lineStrip = lsClip
|
|
|
|
state = ylBlockScalarHeader
|
|
|
|
scalarCache = ""
|
|
|
|
level.mode = mScalar
|
2015-12-07 21:09:57 +00:00
|
|
|
else:
|
|
|
|
yieldError("Unexpected token (expected scalar or line end): " &
|
2015-12-11 21:55:21 +00:00
|
|
|
$token)
|
2015-12-07 21:09:57 +00:00
|
|
|
of ylBlockLineEnd:
|
2015-12-11 21:55:21 +00:00
|
|
|
case token
|
2015-12-07 21:09:57 +00:00
|
|
|
of yamlLineStart:
|
2015-12-14 20:26:34 +00:00
|
|
|
state = if level.mode == mScalar: ylBlockMultilineScalar else:
|
|
|
|
ylBlockLineStart
|
2015-12-07 21:09:57 +00:00
|
|
|
of yamlStreamEnd:
|
|
|
|
closeAllLevels()
|
|
|
|
yield YamlParserEvent(kind: yamlEndDocument)
|
|
|
|
break
|
|
|
|
else:
|
2015-12-11 21:55:21 +00:00
|
|
|
yieldError("Unexpected token (expected line end):" & $token)
|
2015-12-17 20:44:41 +00:00
|
|
|
of ylBlockScalarHeader:
|
|
|
|
case token
|
|
|
|
of yamlPlus:
|
|
|
|
if lineStrip != lsClip:
|
|
|
|
yieldError("Multiple chomping indicators!")
|
|
|
|
else:
|
|
|
|
lineStrip = lsKeep
|
|
|
|
of yamlDash:
|
|
|
|
if lineStrip != lsClip:
|
|
|
|
yieldError("Multiple chomping indicators!")
|
|
|
|
else:
|
|
|
|
lineStrip = lsStrip
|
|
|
|
of yamlBlockIndentationIndicator:
|
|
|
|
if blockScalarIndentation != -1:
|
|
|
|
yieldError("Multiple indentation indicators!")
|
|
|
|
else:
|
|
|
|
blockScalarIndentation = parseInt(lex.content)
|
|
|
|
of yamlLineStart:
|
|
|
|
blockScalarTrailing = ""
|
|
|
|
state = ylBlockScalar
|
|
|
|
else:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
|
|
|
of ylBlockScalar:
|
|
|
|
case token
|
|
|
|
of yamlLineStart:
|
|
|
|
if level.indentationColumn == -1:
|
|
|
|
discard
|
|
|
|
else:
|
|
|
|
case blockScalar
|
|
|
|
of bsLiteral:
|
|
|
|
blockScalarTrailing &= "\x0A"
|
|
|
|
of bsFolded:
|
|
|
|
case blockScalarTrailing.len
|
|
|
|
of 0:
|
|
|
|
blockScalarTrailing = " "
|
|
|
|
of 1:
|
|
|
|
blockScalarTrailing = "\x0A"
|
|
|
|
else:
|
|
|
|
discard
|
|
|
|
|
|
|
|
if lex.content.len > level.indentationColumn:
|
|
|
|
if blockScalar == bsFolded:
|
|
|
|
if blockScalarTrailing == " ":
|
|
|
|
blockScalarTrailing = "\x0A"
|
|
|
|
scalarCache &= blockScalarTrailing &
|
|
|
|
lex.content[level.indentationColumn..^1]
|
|
|
|
blockScalarTrailing = ""
|
|
|
|
|
|
|
|
of yamlScalarPart:
|
|
|
|
if ancestry.high > 0:
|
|
|
|
if ancestry[ancestry.high].indicatorColumn >= lex.column or
|
|
|
|
ancestry[ancestry.high].indicatorColumn == -1 and
|
|
|
|
ancestry[ancestry.high].indentationColumn >= lex.column:
|
|
|
|
# todo: trailing chomping?
|
|
|
|
closeLevel(level)
|
|
|
|
state = ylBlockLineStart
|
|
|
|
continue
|
|
|
|
if level.indentationColumn == -1:
|
|
|
|
level.indentationColumn = lex.column
|
|
|
|
else:
|
|
|
|
scalarCache &= blockScalarTrailing
|
|
|
|
blockScalarTrailing = ""
|
|
|
|
scalarCache &= lex.content
|
|
|
|
else:
|
|
|
|
case lineStrip
|
|
|
|
of lsStrip:
|
|
|
|
discard
|
|
|
|
of lsClip:
|
|
|
|
scalarCache &= "\x0A"
|
|
|
|
of lsKeep:
|
|
|
|
scalarCache &= blockScalarTrailing
|
|
|
|
closeLevel(level)
|
|
|
|
if ancestry.len == 0:
|
|
|
|
state = ylExpectingDocumentEnd
|
|
|
|
else:
|
|
|
|
level = ancestry.pop()
|
|
|
|
state = ylBlockLineStart
|
|
|
|
continue
|
2015-12-10 21:28:57 +00:00
|
|
|
of ylFlow:
|
2015-12-11 21:55:21 +00:00
|
|
|
case token
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlLineStart:
|
|
|
|
discard
|
2015-12-14 20:26:34 +00:00
|
|
|
of lexer.yamlScalar, yamlScalarPart:
|
2015-12-21 20:40:27 +00:00
|
|
|
yieldScalar(lex.content, token == lexer.yamlScalar)
|
2015-12-11 21:55:21 +00:00
|
|
|
level = ancestry.pop()
|
2015-12-10 21:28:57 +00:00
|
|
|
state = ylFlowAfterObject
|
|
|
|
of yamlColon:
|
2015-12-11 21:55:21 +00:00
|
|
|
yieldScalar()
|
|
|
|
level = ancestry.pop()
|
|
|
|
if level.mode == mFlowMapKey:
|
|
|
|
level.mode = mFlowMapValue
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
|
|
|
else:
|
2015-12-10 21:28:57 +00:00
|
|
|
yieldError(
|
|
|
|
"Unexpected token (expected scalar, comma or " &
|
2015-12-11 21:55:21 +00:00
|
|
|
" map end): " & $token)
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlComma:
|
2015-12-11 21:55:21 +00:00
|
|
|
yieldScalar()
|
|
|
|
level = ancestry.pop()
|
|
|
|
case level.mode
|
|
|
|
of mFlowMapValue:
|
|
|
|
level.mode = mFlowMapKey
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
|
|
|
of mFlowSequenceItem:
|
|
|
|
yieldScalar()
|
|
|
|
else:
|
2015-12-10 21:28:57 +00:00
|
|
|
yieldError("Internal error! Please report this bug.")
|
|
|
|
of yamlOpeningBrace:
|
2015-12-11 21:55:21 +00:00
|
|
|
if level.mode != mUnknown:
|
|
|
|
yieldError("Unexpected token")
|
|
|
|
level.mode = mFlowMapKey
|
|
|
|
yieldStart(yamlStartMap)
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlOpeningBracket:
|
2015-12-11 21:55:21 +00:00
|
|
|
if level.mode != mUnknown:
|
|
|
|
yieldError("Unexpected token")
|
|
|
|
level.mode = mFlowSequenceItem
|
|
|
|
yieldStart(yamlStartSequence)
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlClosingBrace:
|
2015-12-11 21:55:21 +00:00
|
|
|
if level.mode == mUnknown:
|
|
|
|
yieldScalar()
|
|
|
|
level = ancestry.pop()
|
|
|
|
if level.mode != mFlowMapValue:
|
|
|
|
yieldError("Unexpected token")
|
|
|
|
yield YamlParserEvent(kind: yamlEndMap)
|
|
|
|
if ancestry.len > 0:
|
|
|
|
level = ancestry.pop()
|
|
|
|
case level.mode
|
|
|
|
of mFlowMapKey, mFlowMapValue, mFlowSequenceItem:
|
2015-12-10 21:28:57 +00:00
|
|
|
state = ylFlowAfterObject
|
2015-12-11 21:55:21 +00:00
|
|
|
else:
|
|
|
|
state = ylBlockLineEnd
|
|
|
|
else:
|
|
|
|
state = ylExpectingDocumentEnd
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlClosingBracket:
|
2015-12-11 21:55:21 +00:00
|
|
|
if level.mode == mUnknown:
|
|
|
|
yieldScalar()
|
|
|
|
level = ancestry.pop()
|
|
|
|
if level.mode != mFlowSequenceItem:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
2015-12-10 21:28:57 +00:00
|
|
|
else:
|
|
|
|
yield YamlParserEvent(kind: yamlEndSequence)
|
2015-12-11 21:55:21 +00:00
|
|
|
if ancestry.len > 0:
|
|
|
|
level = ancestry.pop()
|
|
|
|
case level.mode
|
|
|
|
of mFlowMapKey, mFlowMapValue, mFlowSequenceItem:
|
|
|
|
state = ylFlowAfterObject
|
|
|
|
else:
|
|
|
|
state = ylBlockLineEnd
|
2015-12-10 21:28:57 +00:00
|
|
|
else:
|
2015-12-11 21:55:21 +00:00
|
|
|
state = ylExpectingDocumentEnd
|
2015-12-10 21:28:57 +00:00
|
|
|
else:
|
2015-12-11 21:55:21 +00:00
|
|
|
yieldError("Unexpected token: " & $token)
|
2015-12-10 21:28:57 +00:00
|
|
|
of ylFlowAfterObject:
|
2015-12-11 21:55:21 +00:00
|
|
|
case token
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlLineStart:
|
|
|
|
discard
|
|
|
|
of yamlColon:
|
2015-12-11 21:55:21 +00:00
|
|
|
if level.mode != mFlowMapKey:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
2015-12-10 21:28:57 +00:00
|
|
|
else:
|
2015-12-11 21:55:21 +00:00
|
|
|
level.mode = mFlowMapValue
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
2015-12-10 21:28:57 +00:00
|
|
|
state = ylFlow
|
|
|
|
of yamlComma:
|
2015-12-11 21:55:21 +00:00
|
|
|
case level.mode
|
|
|
|
of mFlowSequenceItem:
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
|
|
|
state = ylFlow
|
|
|
|
of mFlowMapValue:
|
|
|
|
level.mode = mFlowMapKey
|
|
|
|
ancestry.add(level)
|
|
|
|
level = DocumentLevel(mode: mUnknown, indicatorColumn: -1,
|
|
|
|
indentationColumn: -1)
|
2015-12-10 21:28:57 +00:00
|
|
|
state = ylFlow
|
|
|
|
else:
|
2015-12-11 21:55:21 +00:00
|
|
|
yieldError("Unexpected token: " & $token)
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlClosingBrace:
|
2015-12-11 21:55:21 +00:00
|
|
|
if level.mode != mFlowMapValue:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
2015-12-10 21:28:57 +00:00
|
|
|
else:
|
|
|
|
yield YamlParserEvent(kind: yamlEndMap)
|
2015-12-11 21:55:21 +00:00
|
|
|
if ancestry.len > 0:
|
|
|
|
level = ancestry.pop()
|
|
|
|
case level.mode
|
|
|
|
of mFlowMapKey, mFlowMapValue, mFlowSequenceItem:
|
|
|
|
state = ylFlow
|
|
|
|
else:
|
|
|
|
state = ylBlockLineEnd
|
|
|
|
else:
|
|
|
|
state = ylExpectingDocumentEnd
|
2015-12-10 21:28:57 +00:00
|
|
|
of yamlClosingBracket:
|
2015-12-11 21:55:21 +00:00
|
|
|
if level.mode != mFlowSequenceItem:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
2015-12-10 21:28:57 +00:00
|
|
|
else:
|
|
|
|
yield YamlParserEvent(kind: yamlEndSequence)
|
2015-12-11 21:55:21 +00:00
|
|
|
if ancestry.len > 0:
|
|
|
|
level = ancestry.pop()
|
|
|
|
case level.mode
|
|
|
|
of mFlowMapKey, mFlowMapValue, mFlowSequenceItem:
|
|
|
|
state = ylFlow
|
|
|
|
else:
|
|
|
|
state = ylBlockLineEnd
|
|
|
|
else:
|
|
|
|
state = ylExpectingDocumentEnd
|
|
|
|
else:
|
|
|
|
yieldError("Unexpected token: " & $token)
|
|
|
|
of ylExpectingDocumentEnd:
|
|
|
|
case token
|
|
|
|
of yamlComment, yamlLineStart:
|
|
|
|
discard
|
|
|
|
of yamlStreamEnd, yamlDocumentEnd:
|
|
|
|
yield YamlParserEvent(kind: yamlEndDocument)
|
|
|
|
state = ylInitial
|
|
|
|
of yamlDirectivesEnd:
|
|
|
|
yield YamlParserEvent(kind: yamlEndDocument)
|
|
|
|
state = ylInitial
|
|
|
|
continue
|
2015-12-10 21:28:57 +00:00
|
|
|
else:
|
2015-12-11 21:55:21 +00:00
|
|
|
yieldError("Unexpected token (expected document end): " &
|
|
|
|
$token)
|
2015-12-05 11:10:17 +00:00
|
|
|
token = nextToken(lex)
|