2016-08-15 19:30:49 +00:00
|
|
|
# NimYAML - YAML implementation in Nim
|
2016-09-21 19:20:57 +00:00
|
|
|
# (c) Copyright 2016 Felix Krause
|
2016-08-15 19:30:49 +00:00
|
|
|
#
|
|
|
|
# See the file "copying.txt", included in this
|
|
|
|
# distribution, for details about the copyright.
|
|
|
|
|
2016-09-21 19:20:57 +00:00
|
|
|
## ==================
|
2021-05-17 22:31:47 +00:00
|
|
|
## Module yaml/parser
|
2016-09-21 19:20:57 +00:00
|
|
|
## ==================
|
|
|
|
##
|
|
|
|
## This is the low-level parser API. A ``YamlParser`` enables you to parse any
|
|
|
|
## non-nil string or Stream object as YAML character stream.
|
|
|
|
|
2020-11-04 15:40:37 +00:00
|
|
|
import tables, strutils, macros, streams
|
2021-03-23 17:51:05 +00:00
|
|
|
import stream, private/lex, private/internal, private/escaping, data
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2018-08-23 13:31:22 +00:00
|
|
|
when defined(nimNoNil):
|
|
|
|
{.experimental: "notnil".}
|
2020-07-05 20:21:43 +00:00
|
|
|
|
2016-08-30 20:15:29 +00:00
|
|
|
type
|
2020-11-04 15:40:37 +00:00
|
|
|
YamlParser* = object
|
2016-09-20 19:53:38 +00:00
|
|
|
## A parser object. Retains its ``TagLibrary`` across calls to
|
|
|
|
## `parse <#parse,YamlParser,Stream>`_. Can be used
|
|
|
|
## to access anchor names while parsing a YAML character stream, but
|
|
|
|
## only until the document goes out of scope (i.e. until
|
|
|
|
## ``yamlEndDocument`` is yielded).
|
2020-11-03 20:17:31 +00:00
|
|
|
issueWarnings: bool
|
2016-09-20 19:53:38 +00:00
|
|
|
|
2020-11-06 15:21:58 +00:00
|
|
|
State = proc(c: Context, e: var Event): bool {.gcSafe.}
|
2016-08-30 20:15:29 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
Level = object
|
|
|
|
state: State
|
2016-09-12 16:04:26 +00:00
|
|
|
indentation: int
|
2016-08-30 20:15:29 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
Context = ref object of YamlStream
|
2020-11-06 20:39:50 +00:00
|
|
|
handles: seq[tuple[handle, uriPrefix: string]]
|
2020-11-04 21:47:52 +00:00
|
|
|
issueWarnings: bool
|
2020-11-03 20:17:31 +00:00
|
|
|
lex: Lexer
|
|
|
|
levels: seq[Level]
|
2020-11-06 15:21:58 +00:00
|
|
|
keyCache: seq[Event]
|
|
|
|
keyCachePos: int
|
|
|
|
caching: bool
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
headerProps, inlineProps: Properties
|
|
|
|
headerStart, inlineStart: Mark
|
|
|
|
blockIndentation: int
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
YamlLoadingError* = object of ValueError
|
2016-09-20 19:53:38 +00:00
|
|
|
## Base class for all exceptions that may be raised during the process
|
|
|
|
## of loading a YAML character stream.
|
2020-11-03 20:17:31 +00:00
|
|
|
mark*: Mark ## position at which the error has occurred.
|
2016-09-20 19:53:38 +00:00
|
|
|
lineContent*: string ## \
|
|
|
|
## content of the line where the error was encountered. Includes a
|
|
|
|
## second line with a marker ``^`` at the position where the error
|
|
|
|
## was encountered.
|
|
|
|
|
|
|
|
YamlParserError* = object of YamlLoadingError
|
|
|
|
## A parser error is raised if the character stream that is parsed is
|
|
|
|
## not a valid YAML character stream. This stream cannot and will not be
|
|
|
|
## parsed wholly nor partially and all events that have been emitted by
|
|
|
|
## the YamlStream the parser provides should be discarded.
|
|
|
|
##
|
|
|
|
## A character stream is invalid YAML if and only if at least one of the
|
|
|
|
## following conditions apply:
|
|
|
|
##
|
|
|
|
## - There are invalid characters in an element whose contents is
|
|
|
|
## restricted to a limited set of characters. For example, there are
|
|
|
|
## characters in a tag URI which are not valid URI characters.
|
|
|
|
## - An element has invalid indentation. This can happen for example if
|
|
|
|
## a block list element indicated by ``"- "`` is less indented than
|
|
|
|
## the element in the previous line, but there is no block sequence
|
|
|
|
## list open at the same indentation level.
|
|
|
|
## - The YAML structure is invalid. For example, an explicit block map
|
|
|
|
## indicated by ``"? "`` and ``": "`` may not suddenly have a block
|
|
|
|
## sequence item (``"- "``) at the same indentation level. Another
|
|
|
|
## possible violation is closing a flow style object with the wrong
|
|
|
|
## closing character (``}``, ``]``) or not closing it at all.
|
|
|
|
## - A custom tag shorthand is used that has not previously been
|
|
|
|
## declared with a ``%TAG`` directive.
|
|
|
|
## - Multiple tags or anchors are defined for the same node.
|
|
|
|
## - An alias is used which does not map to any anchor that has
|
|
|
|
## previously been declared in the same document.
|
|
|
|
## - An alias has a tag or anchor associated with it.
|
|
|
|
##
|
|
|
|
## Some elements in this list are vague. For a detailed description of a
|
|
|
|
## valid YAML character stream, see the YAML specification.
|
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
const defaultProperties = (yAnchorNone, yTagQuestionMark)
|
|
|
|
|
2020-11-04 15:40:37 +00:00
|
|
|
# parser states
|
2020-11-03 20:17:31 +00:00
|
|
|
|
2020-11-06 15:21:58 +00:00
|
|
|
{.push gcSafe, .}
|
2020-11-03 20:17:31 +00:00
|
|
|
proc atStreamStart(c: Context, e: var Event): bool
|
|
|
|
proc atStreamEnd(c: Context, e : var Event): bool
|
|
|
|
proc beforeDoc(c: Context, e: var Event): bool
|
|
|
|
proc beforeDocEnd(c: Context, e: var Event): bool
|
|
|
|
proc afterDirectivesEnd(c: Context, e: var Event): bool
|
|
|
|
proc beforeImplicitRoot(c: Context, e: var Event): bool
|
|
|
|
proc atBlockIndentation(c: Context, e: var Event): bool
|
|
|
|
proc beforeBlockIndentation(c: Context, e: var Event): bool
|
|
|
|
proc beforeNodeProperties(c: Context, e: var Event): bool
|
|
|
|
proc afterCompactParent(c: Context, e: var Event): bool
|
|
|
|
proc afterCompactParentProps(c: Context, e: var Event): bool
|
2020-11-06 15:21:58 +00:00
|
|
|
proc mergePropsOnNewline(c: Context, e: var Event): bool
|
2020-11-03 20:17:31 +00:00
|
|
|
proc beforeFlowItemProps(c: Context, e: var Event): bool
|
|
|
|
proc inBlockSeq(c: Context, e: var Event): bool
|
|
|
|
proc beforeBlockMapValue(c: Context, e: var Event): bool
|
|
|
|
proc atBlockIndentationProps(c: Context, e: var Event): bool
|
2020-11-06 15:21:58 +00:00
|
|
|
proc beforeFlowItem(c: Context, e: var Event): bool
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterFlowSeqSep(c: Context, e: var Event): bool
|
|
|
|
proc afterFlowMapSep(c: Context, e: var Event): bool
|
|
|
|
proc atBlockMapKeyProps(c: Context, e: var Event): bool
|
|
|
|
proc afterImplicitKey(c: Context, e: var Event): bool
|
|
|
|
proc afterBlockParent(c: Context, e: var Event): bool
|
|
|
|
proc afterBlockParentProps(c: Context, e: var Event): bool
|
|
|
|
proc afterImplicitPairStart(c: Context, e: var Event): bool
|
|
|
|
proc beforePairValue(c: Context, e: var Event): bool
|
|
|
|
proc atEmptyPairKey(c: Context, e: var Event): bool
|
|
|
|
proc afterFlowMapValue(c: Context, e: var Event): bool
|
|
|
|
proc afterFlowSeqSepProps(c: Context, e: var Event): bool
|
|
|
|
proc afterFlowSeqItem(c: Context, e: var Event): bool
|
|
|
|
proc afterPairValue(c: Context, e: var Event): bool
|
2020-11-06 20:39:50 +00:00
|
|
|
proc emitCached(c: Context, e: var Event): bool
|
2020-11-03 20:17:31 +00:00
|
|
|
{.pop.}
|
|
|
|
|
2020-11-05 19:23:42 +00:00
|
|
|
template pushLevel(c: Context, newState: State, newIndent: int) =
|
|
|
|
debug("parser: push " & newState.astToStr & ", indent = " & $newIndent)
|
|
|
|
c.levels.add(Level(state: newState, indentation: newIndent))
|
|
|
|
|
|
|
|
template pushLevel(c: Context, newState: State) =
|
|
|
|
debug("parser: push " & newState.astToStr)
|
|
|
|
c.levels.add(Level(state: newState))
|
|
|
|
|
|
|
|
template transition(c: Context, newState: State) =
|
|
|
|
debug("parser: transition " & newState.astToStr)
|
|
|
|
c.levels[^1].state = newState
|
|
|
|
|
|
|
|
template transition(c: Context, newState: State, newIndent) =
|
|
|
|
debug("parser: transtion " & newState.astToStr & ", indent = " & $newIndent)
|
|
|
|
c.levels[^1] = Level(state: newState, indentation: newIndent)
|
|
|
|
|
|
|
|
template updateIndentation(c: Context, newIndent: int) =
|
|
|
|
debug("parser: update indent = " & $newIndent)
|
|
|
|
c.levels[^1].indentation = newIndent
|
|
|
|
|
|
|
|
template popLevel(c: Context) =
|
|
|
|
debug("parser: pop")
|
|
|
|
discard c.levels.pop()
|
|
|
|
|
2020-11-06 20:39:50 +00:00
|
|
|
proc resolveHandle(c: Context, handle: string): string {.raises: [].} =
|
|
|
|
for item in c.handles:
|
|
|
|
if item.handle == handle:
|
|
|
|
return item.uriPrefix
|
|
|
|
return ""
|
|
|
|
|
2020-11-04 21:47:52 +00:00
|
|
|
proc init[T](c: Context, p: YamlParser, source: T) {.inline.} =
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(atStreamStart, -2)
|
2020-11-04 15:40:37 +00:00
|
|
|
c.nextImpl = proc(s: YamlStream, e: var Event): bool =
|
|
|
|
let c = Context(s)
|
|
|
|
return c.levels[^1].state(c, e)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.lastTokenContextImpl = proc(s: YamlStream, lineContent: var string): bool =
|
|
|
|
lineContent = Context(s).lex.currentLine()
|
|
|
|
return true
|
2020-11-04 15:40:37 +00:00
|
|
|
c.headerProps = defaultProperties
|
|
|
|
c.inlineProps = defaultProperties
|
2020-11-04 21:47:52 +00:00
|
|
|
c.issueWarnings = p.issueWarnings
|
2020-11-04 15:40:37 +00:00
|
|
|
c.lex.init(source)
|
2020-11-06 15:21:58 +00:00
|
|
|
c.keyCachePos = 0
|
|
|
|
c.caching = false
|
2020-11-04 15:40:37 +00:00
|
|
|
|
|
|
|
# interface
|
|
|
|
|
2021-03-23 17:51:05 +00:00
|
|
|
proc init*(p: var YamlParser, issueWarnings: bool = false) =
|
2020-11-06 15:21:58 +00:00
|
|
|
## Initializes a YAML parser.
|
2020-11-04 15:40:37 +00:00
|
|
|
p.issueWarnings = issueWarnings
|
|
|
|
|
2021-03-23 17:51:05 +00:00
|
|
|
proc initYamlParser*(issueWarnings: bool = false): YamlParser =
|
2020-11-06 15:21:58 +00:00
|
|
|
## Creates an initializes YAML parser and returns it
|
|
|
|
result.issueWarnings = issueWarnings
|
|
|
|
|
2020-11-04 15:40:37 +00:00
|
|
|
proc parse*(p: YamlParser, s: Stream): YamlStream =
|
|
|
|
let c = new(Context)
|
2020-11-04 21:47:52 +00:00
|
|
|
c.init(p, s)
|
2020-11-04 15:40:37 +00:00
|
|
|
return c
|
|
|
|
|
|
|
|
proc parse*(p: YamlParser, s: string): YamlStream =
|
|
|
|
let c = new(Context)
|
2020-11-04 21:47:52 +00:00
|
|
|
c.init(p, s)
|
2020-11-04 15:40:37 +00:00
|
|
|
return c
|
|
|
|
|
|
|
|
# implementation
|
|
|
|
|
|
|
|
proc isEmpty(props: Properties): bool =
|
|
|
|
result = props.anchor == yAnchorNone and
|
|
|
|
props.tag == yTagQuestionMark
|
2020-11-03 20:17:31 +00:00
|
|
|
|
|
|
|
proc generateError(c: Context, message: string):
|
2020-11-06 15:21:58 +00:00
|
|
|
ref YamlParserError {.raises: [], .} =
|
2020-11-03 20:17:31 +00:00
|
|
|
result = (ref YamlParserError)(
|
|
|
|
msg: message, parent: nil, mark: c.lex.curStartPos,
|
|
|
|
lineContent: c.lex.currentLine())
|
|
|
|
|
2020-11-10 12:55:22 +00:00
|
|
|
proc parseTag(c: Context): Tag =
|
2020-11-03 20:17:31 +00:00
|
|
|
let handle = c.lex.fullLexeme()
|
2020-11-06 20:39:50 +00:00
|
|
|
var uri = c.resolveHandle(handle)
|
2020-11-03 20:17:31 +00:00
|
|
|
if uri == "":
|
|
|
|
raise c.generateError("unknown handle: " & escape(handle))
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur != Token.Suffix:
|
|
|
|
raise c.generateError("unexpected token (expected tag suffix): " & $c.lex.cur)
|
|
|
|
uri.add(c.lex.evaluated)
|
2021-03-23 17:51:05 +00:00
|
|
|
return Tag(uri)
|
2020-11-03 20:17:31 +00:00
|
|
|
|
|
|
|
proc toStyle(t: Token): ScalarStyle =
|
|
|
|
return (case t
|
|
|
|
of Plain: ssPlain
|
|
|
|
of SingleQuoted: ssSingleQuoted
|
|
|
|
of DoubleQuoted: ssDoubleQuoted
|
|
|
|
of Literal: ssLiteral
|
|
|
|
of Folded: ssFolded
|
|
|
|
else: ssAny)
|
|
|
|
|
2020-11-06 15:21:58 +00:00
|
|
|
proc mergeProps(c: Context, src, target: var Properties) =
|
|
|
|
if src.tag != yTagQuestionMark:
|
|
|
|
if target.tag != yTagQuestionMark:
|
|
|
|
raise c.generateError("Only one tag allowed per node")
|
|
|
|
target.tag = src.tag
|
|
|
|
src.tag = yTagQuestionMark
|
|
|
|
if src.anchor != yAnchorNone:
|
|
|
|
if target.anchor != yAnchorNone:
|
|
|
|
raise c.generateError("Only one anchor allowed per node")
|
|
|
|
target.anchor = src.anchor
|
|
|
|
src.anchor = yAnchorNone
|
|
|
|
|
2020-11-04 21:47:52 +00:00
|
|
|
proc autoScalarTag(props: Properties, t: Token): Properties =
|
|
|
|
result = props
|
|
|
|
if t in {Token.SingleQuoted, Token.DoubleQuoted} and
|
|
|
|
props.tag == yTagQuestionMark:
|
|
|
|
result.tag = yTagExclamationMark
|
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc atStreamStart(c: Context, e: var Event): bool =
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(atStreamEnd)
|
|
|
|
c.pushLevel(beforeDoc, -1)
|
2020-11-03 20:17:31 +00:00
|
|
|
e = Event(startPos: c.lex.curStartPos, endPos: c.lex.curStartPos, kind: yamlStartStream)
|
2020-11-04 21:47:52 +00:00
|
|
|
c.lex.next()
|
2020-11-06 20:39:50 +00:00
|
|
|
resetHandles(c.handles)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
|
|
|
|
proc atStreamEnd(c: Context, e : var Event): bool =
|
|
|
|
e = Event(startPos: c.lex.curStartPos,
|
|
|
|
endPos: c.lex.curStartPos, kind: yamlEndStream)
|
|
|
|
return true
|
|
|
|
|
|
|
|
proc beforeDoc(c: Context, e: var Event): bool =
|
|
|
|
var version = ""
|
|
|
|
var seenDirectives = false
|
|
|
|
while true:
|
|
|
|
case c.lex.cur
|
|
|
|
of DocumentEnd:
|
|
|
|
if seenDirectives:
|
|
|
|
raise c.generateError("Missing `---` after directives")
|
|
|
|
c.lex.next()
|
|
|
|
of DirectivesEnd:
|
2020-11-06 20:39:50 +00:00
|
|
|
e = startDocEvent(true, version, c.handles, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeDocEnd)
|
|
|
|
c.pushLevel(afterDirectivesEnd, -1)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of StreamEnd:
|
2021-10-22 15:42:48 +00:00
|
|
|
if seenDirectives:
|
|
|
|
raise c.generateError("Missing `---` after directives")
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of Indentation:
|
2020-11-06 20:39:50 +00:00
|
|
|
e = startDocEvent(false, version, c.handles, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeDocEnd)
|
|
|
|
c.pushLevel(beforeImplicitRoot, -1)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of YamlDirective:
|
|
|
|
seenDirectives = true
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur != Token.DirectiveParam:
|
|
|
|
raise c.generateError("Invalid token (expected YAML version string): " & $c.lex.cur)
|
|
|
|
elif version != "":
|
|
|
|
raise c.generateError("Duplicate %YAML")
|
|
|
|
version = c.lex.fullLexeme()
|
2020-11-04 21:47:52 +00:00
|
|
|
if version != "1.2" and c.issueWarnings:
|
2020-11-03 20:17:31 +00:00
|
|
|
discard # TODO
|
|
|
|
c.lex.next()
|
|
|
|
of TagDirective:
|
|
|
|
seenDirectives = true
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur != Token.TagHandle:
|
|
|
|
raise c.generateError("Invalid token (expected tag handle): " & $c.lex.cur)
|
|
|
|
let tagHandle = c.lex.fullLexeme()
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur != Token.Suffix:
|
|
|
|
raise c.generateError("Invalid token (expected tag URI): " & $c.lex.cur)
|
2020-11-06 20:39:50 +00:00
|
|
|
discard registerHandle(c.handles, tagHandle, c.lex.evaluated)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
of UnknownDirective:
|
|
|
|
seenDirectives = true
|
|
|
|
# TODO: issue warning
|
|
|
|
while true:
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur != Token.DirectiveParam: break
|
|
|
|
else:
|
|
|
|
raise c.generateError("Unexpected token (expected directive or document start): " & $c.lex.cur)
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterDirectivesEnd(c: Context, e: var Event): bool =
|
|
|
|
case c.lex.cur
|
2020-11-06 15:21:58 +00:00
|
|
|
of nodePropertyKind:
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineStart = c.lex.curStartPos
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-04 21:47:52 +00:00
|
|
|
return false
|
2020-11-03 20:17:31 +00:00
|
|
|
of Indentation:
|
|
|
|
c.headerStart = c.inlineStart
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(atBlockIndentation)
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
2020-11-04 21:47:52 +00:00
|
|
|
return false
|
2021-10-22 15:22:43 +00:00
|
|
|
of DocumentEnd, DirectivesEnd, StreamEnd:
|
2020-11-03 20:17:31 +00:00
|
|
|
e = scalarEvent("", c.inlineProps, ssPlain, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-04 21:47:52 +00:00
|
|
|
return true
|
2020-11-06 15:21:58 +00:00
|
|
|
of scalarTokenKind:
|
|
|
|
e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur),
|
|
|
|
toStyle(c.lex.cur), c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
|
|
|
c.lex.next()
|
2020-11-04 21:47:52 +00:00
|
|
|
return true
|
2017-02-14 18:06:41 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Illegal content at `---`: " & $c.lex.cur)
|
|
|
|
|
|
|
|
proc beforeImplicitRoot(c: Context, e: var Event): bool =
|
|
|
|
if c.lex.cur != Token.Indentation:
|
|
|
|
raise c.generateError("Unexpected token (expected line start): " & $c.lex.cur)
|
|
|
|
c.inlineStart = c.lex.curEndPos
|
2020-11-10 14:40:01 +00:00
|
|
|
c.headerStart = c.lex.curEndPos
|
2020-11-05 19:23:42 +00:00
|
|
|
c.updateIndentation(c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
case c.lex.cur
|
|
|
|
of SeqItemInd, MapKeyInd, MapValueInd:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterCompactParent)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2020-11-06 15:21:58 +00:00
|
|
|
of scalarTokenKind, MapStart, SeqStart:
|
|
|
|
c.transition(atBlockIndentationProps)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of nodePropertyKind:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(atBlockIndentationProps)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
|
|
|
raise c.generateError("Unexpected token (expected collection start): " & $c.lex.cur)
|
2016-08-17 20:21:34 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc atBlockIndentation(c: Context, e: var Event): bool =
|
|
|
|
if c.blockIndentation == c.levels[^1].indentation and
|
|
|
|
(c.lex.cur != Token.SeqItemInd or
|
|
|
|
c.levels[^3].state == inBlockSeq):
|
2020-11-05 19:23:42 +00:00
|
|
|
e = scalarEvent("", c.headerProps, ssPlain,
|
2020-11-03 20:17:31 +00:00
|
|
|
c.headerStart, c.headerStart)
|
|
|
|
c.headerProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
c.inlineStart = c.lex.curStartPos
|
2020-11-05 19:23:42 +00:00
|
|
|
c.updateIndentation(c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
case c.lex.cur
|
|
|
|
of nodePropertyKind:
|
|
|
|
if isEmpty(c.headerProps):
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(mergePropsOnNewline)
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(atBlockIndentationProps)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of SeqItemInd:
|
|
|
|
e = startSeqEvent(csBlock, c.headerProps,
|
|
|
|
c.headerStart, c.lex.curEndPos)
|
|
|
|
c.headerProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(inBlockSeq, c.lex.recentIndentation())
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
|
|
|
c.pushLevel(afterCompactParent, c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
return true
|
|
|
|
of MapKeyInd:
|
|
|
|
e = startMapEvent(csBlock, c.headerProps,
|
|
|
|
c.headerStart, c.lex.curEndPos)
|
|
|
|
c.headerProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeBlockMapValue, c.lex.recentIndentation())
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
|
|
|
c.pushLevel(afterCompactParent, c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
return true
|
2020-11-03 20:17:31 +00:00
|
|
|
of Plain, SingleQuoted, DoubleQuoted:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.updateIndentation(c.lex.recentIndentation())
|
2020-11-04 21:47:52 +00:00
|
|
|
let scalarToken = c.lex.cur
|
2020-11-03 20:17:31 +00:00
|
|
|
e = scalarEvent(c.lex.evaluated, c.headerProps,
|
|
|
|
toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos)
|
|
|
|
c.headerProps = defaultProperties
|
|
|
|
let headerEnd = c.lex.curStartPos
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
|
|
|
if c.lex.lastScalarWasMultiline():
|
|
|
|
raise c.generateError("Implicit mapping key may not be multiline")
|
|
|
|
let props = e.scalarProperties
|
2020-11-04 21:47:52 +00:00
|
|
|
e.scalarProperties = autoScalarTag(defaultProperties, scalarToken)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.keyCache.add(move(e))
|
2020-11-03 20:17:31 +00:00
|
|
|
e = startMapEvent(csBlock, props, c.headerStart, headerEnd)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
2020-11-04 21:47:52 +00:00
|
|
|
e.scalarProperties = autoScalarTag(e.scalarProperties, scalarToken)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of Alias:
|
|
|
|
e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos)
|
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
let headerEnd = c.lex.curStartPos
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
2020-11-06 20:39:50 +00:00
|
|
|
c.keyCache.add(move(e))
|
2020-11-03 20:17:31 +00:00
|
|
|
e = startMapEvent(csBlock, c.headerProps, c.headerStart, headerEnd)
|
|
|
|
c.headerProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-03 20:17:31 +00:00
|
|
|
elif not isEmpty(c.headerProps):
|
|
|
|
raise c.generateError("Alias may not have properties")
|
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(atBlockIndentationProps)
|
|
|
|
return false
|
2016-09-13 10:01:21 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc atBlockIndentationProps(c: Context, e: var Event): bool =
|
2020-11-05 19:23:42 +00:00
|
|
|
c.updateIndentation(c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
case c.lex.cur
|
|
|
|
of MapValueInd:
|
2020-11-06 20:39:50 +00:00
|
|
|
c.keyCache.add(scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curEndPos))
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
e = startMapEvent(csBlock, c.headerProps, c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
c.headerProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of Plain, SingleQuoted, DoubleQuoted:
|
2020-11-04 21:47:52 +00:00
|
|
|
e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur),
|
|
|
|
toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
let headerEnd = c.lex.curStartPos
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
|
|
|
if c.lex.lastScalarWasMultiline():
|
|
|
|
raise c.generateError("Implicit mapping key may not be multiline")
|
2021-05-17 21:51:35 +00:00
|
|
|
c.keyCache.add(move(e))
|
2020-11-03 20:17:31 +00:00
|
|
|
e = startMapEvent(csBlock, c.headerProps, c.headerStart, headerEnd)
|
|
|
|
c.headerProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.mergeProps(c.headerProps, e.scalarProperties)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2020-11-06 15:21:58 +00:00
|
|
|
of MapStart, SeqStart:
|
|
|
|
let
|
|
|
|
startPos = c.lex.curStartPos
|
2020-11-06 20:39:50 +00:00
|
|
|
indent = c.lex.currentIndentation()
|
|
|
|
levelDepth = c.levels.len
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(beforeFlowItemProps)
|
|
|
|
c.caching = true
|
2020-11-06 20:39:50 +00:00
|
|
|
while c.levels.len >= levelDepth:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.keyCache.add(c.next())
|
|
|
|
c.caching = false
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
|
|
|
c.pushLevel(afterImplicitKey, indent)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-06 15:21:58 +00:00
|
|
|
if c.lex.curStartPos.line != startPos.line:
|
|
|
|
raise c.generateError("Implicit mapping key may not be multiline")
|
|
|
|
e = startMapEvent(csBlock, c.headerProps, c.headerStart, startPos)
|
|
|
|
c.headerProps = defaultProperties
|
|
|
|
return true
|
|
|
|
else:
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-06 15:21:58 +00:00
|
|
|
return false
|
|
|
|
of Literal, Folded:
|
|
|
|
c.mergeProps(c.inlineProps, c.headerProps)
|
|
|
|
e = scalarEvent(c.lex.evaluated, c.headerProps, toStyle(c.lex.cur),
|
|
|
|
c.inlineStart, c.lex.curEndPos)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.headerProps = defaultProperties
|
|
|
|
c.lex.next()
|
2020-11-06 15:21:58 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2020-11-06 15:21:58 +00:00
|
|
|
of Indentation:
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
2020-11-06 20:39:50 +00:00
|
|
|
c.transition(atBlockIndentation)
|
2020-11-06 15:21:58 +00:00
|
|
|
return false
|
2023-03-10 21:21:18 +00:00
|
|
|
of StreamEnd, DocumentEnd, DirectivesEnd:
|
|
|
|
e = scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curStartPos)
|
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
c.popLevel()
|
|
|
|
return true
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
|
|
|
raise c.generateError("Unexpected token (expected block content): " & $c.lex.cur)
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc beforeNodeProperties(c: Context, e: var Event): bool =
|
|
|
|
case c.lex.cur
|
|
|
|
of TagHandle:
|
|
|
|
if c.inlineProps.tag != yTagQuestionMark:
|
|
|
|
raise c.generateError("Only one tag allowed per node")
|
|
|
|
c.inlineProps.tag = c.parseTag()
|
|
|
|
of VerbatimTag:
|
|
|
|
if c.inlineProps.tag != yTagQuestionMark:
|
|
|
|
raise c.generateError("Only one tag allowed per node")
|
2021-05-17 21:51:35 +00:00
|
|
|
c.inlineProps.tag = Tag(move(c.lex.evaluated))
|
2020-11-03 20:17:31 +00:00
|
|
|
of Token.Anchor:
|
|
|
|
if c.inlineProps.anchor != yAnchorNone:
|
|
|
|
raise c.generateError("Only one anchor allowed per node")
|
|
|
|
c.inlineProps.anchor = c.lex.shortLexeme().Anchor
|
|
|
|
of Indentation:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.mergeProps(c.inlineProps, c.headerProps)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of Alias:
|
|
|
|
raise c.generateError("Alias may not have node properties")
|
2016-08-15 19:30:49 +00:00
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
c.lex.next()
|
|
|
|
return false
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterCompactParent(c: Context, e: var Event): bool =
|
|
|
|
c.inlineStart = c.lex.curStartPos
|
|
|
|
case c.lex.cur
|
|
|
|
of nodePropertyKind:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterCompactParentProps)
|
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
of SeqItemInd:
|
|
|
|
e = startSeqEvent(csBlock, c.headerProps, c.headerStart, c.lex.curEndPos)
|
|
|
|
c.headerProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(inBlockSeq, c.lex.recentIndentation())
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
|
|
|
c.pushLevel(afterCompactParent, c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
return true
|
|
|
|
of MapKeyInd:
|
|
|
|
e = startMapEvent(csBlock, c.headerProps, c.headerStart, c.lex.curEndPos)
|
|
|
|
c.headerProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeBlockMapValue, c.lex.recentIndentation())
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
|
|
|
c.pushLevel(afterCompactParent, c.lex.recentIndentation)
|
|
|
|
c.lex.next()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2017-02-14 18:06:41 +00:00
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterCompactParentProps)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterCompactParentProps(c: Context, e: var Event): bool =
|
2020-11-05 19:23:42 +00:00
|
|
|
c.updateIndentation(c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
case c.lex.cur
|
|
|
|
of nodePropertyKind:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of Indentation:
|
|
|
|
c.headerStart = c.inlineStart
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(atBlockIndentation, c.levels[^3].indentation)
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of MapValueInd:
|
2020-11-06 20:39:50 +00:00
|
|
|
c.keyCache.add(scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curStartPos))
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
e = startMapEvent(csBlock, defaultProperties, c.lex.curStartPos, c.lex.curStartPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of Alias:
|
|
|
|
e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos)
|
|
|
|
let headerEnd = c.lex.curStartPos
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
2020-11-06 20:39:50 +00:00
|
|
|
c.keyCache.add(move(e))
|
2020-11-03 20:17:31 +00:00
|
|
|
e = startMapEvent(csBlock, defaultProperties, headerEnd, headerEnd)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of scalarTokenKind:
|
2020-11-04 21:47:52 +00:00
|
|
|
e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur),
|
|
|
|
toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
let headerEnd = c.lex.curStartPos
|
2020-11-05 19:23:42 +00:00
|
|
|
c.updateIndentation(c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
|
|
|
if c.lex.lastScalarWasMultiline():
|
|
|
|
raise c.generateError("Implicit mapping key may not be multiline")
|
2020-11-06 20:39:50 +00:00
|
|
|
c.keyCache.add(move(e))
|
2020-11-03 20:17:31 +00:00
|
|
|
e = startMapEvent(csBlock, defaultProperties, headerEnd, headerEnd)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2023-03-10 21:21:18 +00:00
|
|
|
of MapStart, SeqStart, StreamEnd, DocumentEnd, DirectivesEnd:
|
2020-11-06 20:39:50 +00:00
|
|
|
c.transition(atBlockIndentationProps)
|
|
|
|
return false
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
|
|
|
raise c.generateError("Unexpected token (expected newline or flow item start: " & $c.lex.cur)
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterBlockParent(c: Context, e: var Event): bool =
|
|
|
|
c.inlineStart = c.lex.curStartPos
|
|
|
|
case c.lex.cur
|
|
|
|
of nodePropertyKind:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterBlockParentProps)
|
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
of SeqItemInd, MapKeyInd:
|
|
|
|
raise c.generateError("Compact notation not allowed after implicit key")
|
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterBlockParentProps)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterBlockParentProps(c: Context, e: var Event): bool =
|
2020-11-05 19:23:42 +00:00
|
|
|
c.updateIndentation(c.lex.recentIndentation())
|
2020-11-03 20:17:31 +00:00
|
|
|
case c.lex.cur
|
|
|
|
of nodePropertyKind:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of MapValueInd:
|
|
|
|
raise c.generateError("Compact notation not allowed after implicit key")
|
|
|
|
of scalarTokenKind:
|
2020-11-04 21:47:52 +00:00
|
|
|
e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur),
|
|
|
|
toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
|
|
|
raise c.generateError("Compact notation not allowed after implicit key")
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterCompactParentProps)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-06 15:21:58 +00:00
|
|
|
proc mergePropsOnNewline(c: Context, e: var Event): bool =
|
2020-11-05 19:23:42 +00:00
|
|
|
c.updateIndentation(c.lex.recentIndentation())
|
|
|
|
if c.lex.cur == Token.Indentation:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.mergeProps(c.inlineProps, c.headerProps)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterCompactParentProps)
|
|
|
|
return false
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc beforeDocEnd(c: Context, e: var Event): bool =
|
|
|
|
case c.lex.cur
|
|
|
|
of DocumentEnd:
|
2020-11-05 19:23:42 +00:00
|
|
|
e = endDocEvent(true, c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
c.transition(beforeDoc)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
2020-11-06 20:39:50 +00:00
|
|
|
resetHandles(c.handles)
|
2020-11-03 20:17:31 +00:00
|
|
|
of StreamEnd:
|
2020-11-05 19:23:42 +00:00
|
|
|
e = endDocEvent(false, c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
of DirectivesEnd:
|
2020-11-05 19:23:42 +00:00
|
|
|
e = endDocEvent(false, c.lex.curStartPos, c.lex.curStartPos)
|
|
|
|
c.transition(beforeDoc)
|
2020-11-06 20:39:50 +00:00
|
|
|
resetHandles(c.handles)
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
|
|
|
raise c.generateError("Unexpected token (expected document end): " & $c.lex.cur)
|
|
|
|
return true
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc inBlockSeq(c: Context, e: var Event): bool =
|
|
|
|
if c.blockIndentation > c.levels[^1].indentation:
|
|
|
|
raise c.generateError("Invalid indentation: got " & $c.blockIndentation & ", expected " & $c.levels[^1].indentation)
|
|
|
|
case c.lex.cur
|
|
|
|
of SeqItemInd:
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeBlockIndentation)
|
|
|
|
c.pushLevel(afterCompactParent, c.blockIndentation)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
else:
|
|
|
|
if c.levels[^3].indentation == c.levels[^1].indentation:
|
|
|
|
e = endSeqEvent(c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
|
|
|
c.popLevel()
|
|
|
|
return true
|
2016-08-15 19:30:49 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Illegal token (expected block sequence indicator): " & $c.lex.cur)
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc beforeBlockMapKey(c: Context, e: var Event): bool =
|
|
|
|
if c.blockIndentation > c.levels[^1].indentation:
|
|
|
|
raise c.generateError("Invalid indentation: got " & $c.blockIndentation & ", expected " & $c.levels[^1].indentation)
|
2020-11-06 20:39:50 +00:00
|
|
|
c.inlineStart = c.lex.curStartPos
|
2020-11-03 20:17:31 +00:00
|
|
|
case c.lex.cur
|
|
|
|
of MapKeyInd:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeBlockMapValue)
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
|
|
|
c.pushLevel(afterCompactParent, c.blockIndentation)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
return false
|
|
|
|
of nodePropertyKind:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(atBlockMapKeyProps)
|
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of Plain, SingleQuoted, DoubleQuoted:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(atBlockMapKeyProps)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of Alias:
|
|
|
|
e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos)
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of MapValueInd:
|
|
|
|
e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeBlockMapValue)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2016-08-17 18:04:59 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Unexpected token (expected mapping key): " & $c.lex.cur)
|
2016-08-17 18:04:59 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc atBlockMapKeyProps(c: Context, e: var Event): bool =
|
2016-09-12 16:04:26 +00:00
|
|
|
case c.lex.cur
|
2020-11-03 20:17:31 +00:00
|
|
|
of nodePropertyKind:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
of Alias:
|
|
|
|
e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos)
|
|
|
|
of Plain, SingleQuoted, DoubleQuoted:
|
2020-11-04 21:47:52 +00:00
|
|
|
e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur),
|
|
|
|
toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
if c.lex.lastScalarWasMultiline():
|
|
|
|
raise c.generateError("Implicit mapping key may not be multiline")
|
|
|
|
of MapValueInd:
|
|
|
|
e = scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curStartPos)
|
|
|
|
c.inlineProps = defaultProperties
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
else:
|
|
|
|
raise c.generateError("Unexpected token (expected implicit mapping key): " & $c.lex.cur)
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterImplicitKey)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
|
|
|
|
proc afterImplicitKey(c: Context, e: var Event): bool =
|
|
|
|
if c.lex.cur != Token.MapValueInd:
|
|
|
|
raise c.generateError("Unexpected token (expected ':'): " & $c.lex.cur)
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeBlockMapKey)
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
|
|
|
c.pushLevel(afterBlockParent, max(0, c.levels[^2].indentation))
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
|
|
|
|
proc beforeBlockMapValue(c: Context, e: var Event): bool =
|
|
|
|
if c.blockIndentation > c.levels[^1].indentation:
|
|
|
|
raise c.generateError("Invalid indentation")
|
2016-09-13 08:39:54 +00:00
|
|
|
case c.lex.cur
|
2020-11-03 20:17:31 +00:00
|
|
|
of MapValueInd:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeBlockMapKey)
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
|
|
|
c.pushLevel(afterCompactParent, c.blockIndentation)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
of MapKeyInd, Plain, SingleQuoted, DoubleQuoted, nodePropertyKind:
|
|
|
|
# the value is allowed to be missing after an explicit key
|
|
|
|
e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeBlockMapKey)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2016-09-13 08:39:54 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Unexpected token (expected mapping value): " & $c.lex.cur)
|
|
|
|
|
|
|
|
proc beforeBlockIndentation(c: Context, e: var Event): bool =
|
2020-11-04 15:40:37 +00:00
|
|
|
proc endBlockNode(e: var Event) =
|
2020-11-03 20:17:31 +00:00
|
|
|
if c.levels[^1].state == beforeBlockMapKey:
|
|
|
|
e = endMapEvent(c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
elif c.levels[^1].state == beforeBlockMapValue:
|
|
|
|
e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeBlockMapKey)
|
|
|
|
c.pushLevel(beforeBlockIndentation)
|
2020-11-03 20:17:31 +00:00
|
|
|
return
|
|
|
|
elif c.levels[^1].state == inBlockSeq:
|
|
|
|
e = endSeqEvent(c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
elif c.levels[^1].state == atBlockIndentation:
|
|
|
|
e = scalarEvent("", c.headerProps, ssPlain, c.headerStart, c.headerStart)
|
|
|
|
c.headerProps = defaultProperties
|
|
|
|
elif c.levels[^1].state == beforeBlockIndentation:
|
|
|
|
raise c.generateError("Unexpected double beforeBlockIndentation")
|
2016-09-13 08:39:54 +00:00
|
|
|
else:
|
2020-11-10 12:55:22 +00:00
|
|
|
raise c.generateError("Internal error (please report this bug): unexpected state at endBlockNode")
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
|
|
|
c.popLevel()
|
2016-09-12 19:38:56 +00:00
|
|
|
case c.lex.cur
|
2020-11-03 20:17:31 +00:00
|
|
|
of Indentation:
|
2020-11-04 18:32:09 +00:00
|
|
|
c.blockIndentation = c.lex.currentIndentation()
|
2020-11-03 20:17:31 +00:00
|
|
|
if c.blockIndentation < c.levels[^1].indentation:
|
2020-11-04 15:40:37 +00:00
|
|
|
endBlockNode(e)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
else:
|
|
|
|
c.lex.next()
|
|
|
|
return false
|
|
|
|
of StreamEnd, DocumentEnd, DirectivesEnd:
|
|
|
|
c.blockIndentation = 0
|
|
|
|
if c.levels[^1].state != beforeDocEnd:
|
2020-11-04 15:40:37 +00:00
|
|
|
endBlockNode(e)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
else:
|
|
|
|
return false
|
2016-08-15 19:30:49 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Unexpected content after node in block context (expected newline): " & $c.lex.cur)
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc beforeFlowItem(c: Context, e: var Event): bool =
|
|
|
|
c.inlineStart = c.lex.curStartPos
|
2016-09-12 19:38:56 +00:00
|
|
|
case c.lex.cur
|
2020-11-03 20:17:31 +00:00
|
|
|
of nodePropertyKind:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeFlowItemProps)
|
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
of Alias:
|
|
|
|
e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos)
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforeFlowItemProps)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc beforeFlowItemProps(c: Context, e: var Event): bool =
|
2016-09-12 19:38:56 +00:00
|
|
|
case c.lex.cur
|
2020-11-03 20:17:31 +00:00
|
|
|
of nodePropertyKind:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
of Alias:
|
|
|
|
e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos)
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
of scalarTokenKind:
|
2020-11-04 21:47:52 +00:00
|
|
|
e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur),
|
|
|
|
toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos)
|
|
|
|
c.inlineProps = defaultProperties
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
of MapStart:
|
|
|
|
e = startMapEvent(csFlow, c.inlineProps, c.inlineStart, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterFlowMapSep)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
of SeqStart:
|
|
|
|
e = startSeqEvent(csFlow, c.inlineProps, c.inlineStart, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterFlowSeqSep)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
of MapEnd, SeqEnd, SeqSep, MapValueInd:
|
|
|
|
e = scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2016-08-15 19:30:49 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Unexpected token (expected flow node): " & $c.lex.cur)
|
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
return true
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterFlowMapKey(c: Context, e: var Event): bool =
|
2016-09-12 19:38:56 +00:00
|
|
|
case c.lex.cur
|
2020-11-03 20:17:31 +00:00
|
|
|
of MapValueInd:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterFlowMapValue)
|
|
|
|
c.pushLevel(beforeFlowItem)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
return false
|
|
|
|
of SeqSep, MapEnd:
|
|
|
|
e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterFlowMapValue)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2016-08-15 19:30:49 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Unexpected token (expected ':'): " & $c.lex.cur)
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterFlowMapValue(c: Context, e: var Event): bool =
|
|
|
|
case c.lex.cur
|
|
|
|
of SeqSep:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterFlowMapSep)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
return false
|
|
|
|
of MapEnd:
|
|
|
|
e = endMapEvent(c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of Plain, SingleQuoted, DoubleQuoted, MapKeyInd, Token.Anchor, Alias, MapStart, SeqStart:
|
|
|
|
raise c.generateError("Missing ','")
|
2016-08-15 19:30:49 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Unexpected token (expected ',' or '}'): " & $c.lex.cur)
|
2016-08-15 19:30:49 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterFlowSeqItem(c: Context, e: var Event): bool =
|
2016-09-12 19:38:56 +00:00
|
|
|
case c.lex.cur
|
2020-11-03 20:17:31 +00:00
|
|
|
of SeqSep:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterFlowSeqSep)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
|
|
|
return false
|
|
|
|
of SeqEnd:
|
|
|
|
e = endSeqEvent(c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of Plain, SingleQuoted, DoubleQuoted, MapKeyInd, Token.Anchor, Alias, MapStart, SeqStart:
|
|
|
|
raise c.generateError("Missing ','")
|
2016-09-12 19:38:56 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
raise c.generateError("Unexpected token (expected ',' or ']'): " & $c.lex.cur)
|
2016-08-17 18:04:59 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterFlowMapSep(c: Context, e: var Event): bool =
|
|
|
|
case c.lex.cur
|
|
|
|
of MapKeyInd:
|
|
|
|
c.lex.next()
|
|
|
|
of MapEnd:
|
|
|
|
e = endMapEvent(c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2016-08-17 18:04:59 +00:00
|
|
|
return true
|
2020-11-10 21:12:09 +00:00
|
|
|
of SeqSep:
|
|
|
|
raise c.generateError("Missing mapping entry between commas (use '?' for an empty mapping entry)")
|
2020-11-03 20:17:31 +00:00
|
|
|
else: discard
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterFlowMapKey)
|
|
|
|
c.pushLevel(beforeFlowItem)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2016-08-30 20:15:29 +00:00
|
|
|
|
2020-11-06 15:21:58 +00:00
|
|
|
proc afterFlowSeqSep(c: Context, e: var Event): bool =
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineStart = c.lex.curStartPos
|
|
|
|
case c.lex.cur
|
|
|
|
of SeqSep:
|
|
|
|
e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curStartPos)
|
|
|
|
c.lex.next()
|
|
|
|
return true
|
|
|
|
of nodePropertyKind:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(afterFlowSeqSepProps)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeNodeProperties)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2020-11-06 15:21:58 +00:00
|
|
|
of Plain, SingleQuoted, DoubleQuoted, MapStart, SeqStart:
|
|
|
|
c.transition(afterFlowSeqSepProps)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
|
|
|
of MapKeyInd:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(afterFlowSeqSepProps)
|
2020-11-03 20:17:31 +00:00
|
|
|
e = startMapEvent(csFlow, defaultProperties, c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
c.lex.next()
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(afterFlowSeqItem)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforePairValue)
|
|
|
|
c.pushLevel(beforeFlowItem)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
|
|
|
of MapValueInd:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(afterFlowSeqItem)
|
2020-11-03 20:17:31 +00:00
|
|
|
e = startMapEvent(csFlow, defaultProperties, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(atEmptyPairKey)
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2020-11-06 15:21:58 +00:00
|
|
|
of SeqEnd:
|
|
|
|
e = endSeqEvent(c.lex.curStartPos, c.lex.curEndPos)
|
|
|
|
c.lex.next()
|
|
|
|
c.popLevel()
|
|
|
|
return true
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.transition(afterFlowSeqItem)
|
|
|
|
c.pushLevel(beforeFlowItem)
|
|
|
|
return false
|
2020-11-03 20:17:31 +00:00
|
|
|
|
2020-11-06 15:21:58 +00:00
|
|
|
proc afterFlowSeqSepProps(c: Context, e: var Event): bool =
|
|
|
|
# here we handle potential implicit single pairs within flow sequences.
|
|
|
|
c.transition(afterFlowSeqItem)
|
|
|
|
case c.lex.cur
|
|
|
|
of Plain, SingleQuoted, DoubleQuoted:
|
|
|
|
e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur),
|
|
|
|
toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.inlineProps = defaultProperties
|
|
|
|
c.lex.next()
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(afterImplicitPairStart)
|
2020-11-06 20:39:50 +00:00
|
|
|
if c.caching:
|
|
|
|
c.keyCache.add(startMapEvent(csFlow, defaultProperties, c.lex.curStartPos, c.lex.curStartPos))
|
|
|
|
else:
|
|
|
|
c.keyCache.add(move(e))
|
|
|
|
e = startMapEvent(csFlow, defaultProperties, c.lex.curStartPos, c.lex.curStartPos)
|
|
|
|
c.pushLevel(emitCached)
|
2016-08-17 18:04:59 +00:00
|
|
|
return true
|
2020-11-06 15:21:58 +00:00
|
|
|
of MapStart, SeqStart:
|
|
|
|
let
|
|
|
|
startPos = c.lex.curStartPos
|
|
|
|
indent = c.levels[^1].indentation
|
|
|
|
cacheStart = c.keyCache.len
|
2020-11-06 20:39:50 +00:00
|
|
|
levelDepth = c.levels.len
|
2020-11-06 15:21:58 +00:00
|
|
|
alreadyCaching = c.caching
|
|
|
|
c.pushLevel(beforeFlowItemProps)
|
|
|
|
c.caching = true
|
2020-11-06 20:39:50 +00:00
|
|
|
while c.levels.len > levelDepth:
|
2020-11-06 15:21:58 +00:00
|
|
|
c.keyCache.add(c.next())
|
|
|
|
c.caching = alreadyCaching
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
|
|
|
c.pushLevel(afterImplicitPairStart, indent)
|
|
|
|
if c.lex.curStartPos.line != startPos.line:
|
|
|
|
raise c.generateError("Implicit mapping key may not be multiline")
|
|
|
|
if not alreadyCaching:
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-06 15:21:58 +00:00
|
|
|
e = startMapEvent(csPair, defaultProperties, startPos, startPos)
|
|
|
|
return true
|
|
|
|
else:
|
|
|
|
# we are already filling a cache.
|
|
|
|
# so we just squeeze the map start in.
|
|
|
|
c.keyCache.insert(startMapEvent(csPair, defaultProperties, startPos, startPos), cacheStart)
|
|
|
|
return false
|
|
|
|
else:
|
|
|
|
if not alreadyCaching:
|
2020-11-06 20:39:50 +00:00
|
|
|
c.pushLevel(emitCached)
|
2020-11-06 15:21:58 +00:00
|
|
|
return false
|
2020-11-03 20:17:31 +00:00
|
|
|
else:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.pushLevel(beforeFlowItem)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2016-08-17 18:04:59 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc atEmptyPairKey(c: Context, e: var Event): bool =
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(beforePairValue)
|
2020-11-03 20:17:31 +00:00
|
|
|
e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curStartPos)
|
|
|
|
return true
|
|
|
|
|
|
|
|
proc beforePairValue(c: Context, e: var Event): bool =
|
|
|
|
if c.lex.cur == Token.MapValueInd:
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterPairValue)
|
|
|
|
c.pushLevel(beforeFlowItem)
|
2020-11-03 20:17:31 +00:00
|
|
|
c.lex.next()
|
2017-01-10 11:00:15 +00:00
|
|
|
return false
|
2016-08-17 18:04:59 +00:00
|
|
|
else:
|
2020-11-03 20:17:31 +00:00
|
|
|
# pair ends here without value
|
|
|
|
e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2016-09-19 17:33:29 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterImplicitPairStart(c: Context, e: var Event): bool =
|
|
|
|
c.lex.next()
|
2020-11-05 19:23:42 +00:00
|
|
|
c.transition(afterPairValue)
|
|
|
|
c.pushLevel(beforeFlowItem)
|
2020-11-03 20:17:31 +00:00
|
|
|
return false
|
2016-09-12 16:04:26 +00:00
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc afterPairValue(c: Context, e: var Event): bool =
|
|
|
|
e = endMapEvent(c.lex.curStartPos, c.lex.curEndPos)
|
2020-11-05 19:23:42 +00:00
|
|
|
c.popLevel()
|
2020-11-03 20:17:31 +00:00
|
|
|
return true
|
2017-01-09 18:09:07 +00:00
|
|
|
|
2020-11-06 20:39:50 +00:00
|
|
|
proc emitCached(c: Context, e: var Event): bool =
|
2020-11-06 15:21:58 +00:00
|
|
|
debug("emitCollection key: pos = " & $c.keyCachePos & ", len = " & $c.keyCache.len)
|
|
|
|
yAssert(c.keyCachePos < c.keyCache.len)
|
|
|
|
e = move(c.keyCache[c.keyCachePos])
|
|
|
|
inc(c.keyCachePos)
|
|
|
|
if c.keyCachePos == len(c.keyCache):
|
|
|
|
c.keyCache.setLen(0)
|
|
|
|
c.keyCachePos = 0
|
|
|
|
c.popLevel()
|
|
|
|
return true
|
|
|
|
|
2020-11-03 20:17:31 +00:00
|
|
|
proc display*(p: YamlParser, event: Event): string =
|
2017-02-14 18:40:40 +00:00
|
|
|
## Generate a representation of the given event with proper visualization of
|
|
|
|
## anchor and tag (if any). The generated representation is conformant to the
|
|
|
|
## format used in the yaml test suite.
|
|
|
|
##
|
|
|
|
## This proc is an informed version of ``$`` on ``YamlStreamEvent`` which can
|
|
|
|
## properly display the anchor and tag name as it occurs in the input.
|
|
|
|
## However, it shall only be used while using the streaming API because after
|
|
|
|
## finishing the parsing of a document, the parser drops all information about
|
|
|
|
## anchor and tag names.
|
|
|
|
case event.kind
|
2020-11-03 20:17:31 +00:00
|
|
|
of yamlStartStream: result = "+STR"
|
|
|
|
of yamlEndStream: result = "-STR"
|
2017-02-14 18:40:40 +00:00
|
|
|
of yamlEndMap: result = "-MAP"
|
|
|
|
of yamlEndSeq: result = "-SEQ"
|
2017-02-14 21:06:48 +00:00
|
|
|
of yamlStartDoc:
|
|
|
|
result = "+DOC"
|
2020-11-05 19:23:42 +00:00
|
|
|
if event.explicitDirectivesEnd: result &= " ---"
|
2017-02-14 21:30:48 +00:00
|
|
|
of yamlEndDoc:
|
|
|
|
result = "-DOC"
|
2020-11-05 19:23:42 +00:00
|
|
|
if event.explicitDocumentEnd: result &= " ..."
|
2017-02-14 20:53:15 +00:00
|
|
|
of yamlStartMap:
|
2020-11-03 20:17:31 +00:00
|
|
|
result = "+MAP" & renderAttrs(event.mapProperties, true)
|
2017-02-14 20:53:15 +00:00
|
|
|
of yamlStartSeq:
|
2020-11-03 20:17:31 +00:00
|
|
|
result = "+SEQ" & renderAttrs(event.seqProperties, true)
|
2017-02-14 18:40:40 +00:00
|
|
|
of yamlScalar:
|
2020-11-05 19:23:42 +00:00
|
|
|
result = "=VAL" & renderAttrs(event.scalarProperties,
|
|
|
|
event.scalarStyle in {ssPlain, ssFolded, ssLiteral})
|
|
|
|
case event.scalarStyle
|
|
|
|
of ssPlain, ssAny: result &= " :"
|
|
|
|
of ssSingleQuoted: result &= " \'"
|
|
|
|
of ssDoubleQuoted: result &= " \""
|
|
|
|
of ssLiteral: result &= " |"
|
|
|
|
of ssFolded: result &= " >"
|
2017-02-14 18:40:40 +00:00
|
|
|
result &= yamlTestSuiteEscape(event.scalarContent)
|
2020-11-03 20:17:31 +00:00
|
|
|
of yamlAlias: result = "=ALI *" & $event.aliasTarget
|