2015-12-28 21:24:05 +00:00
|
|
|
# NimYAML - YAML implementation in Nim
|
|
|
|
# (c) Copyright 2015 Felix Krause
|
|
|
|
#
|
|
|
|
# See the file "copying.txt", included in this
|
|
|
|
# distribution, for details about the copyright.
|
|
|
|
|
2015-12-27 15:36:32 +00:00
|
|
|
type
|
|
|
|
DumperState = enum
|
2016-01-11 18:12:55 +00:00
|
|
|
dBlockExplicitMapKey, dBlockImplicitMapKey, dBlockMapValue,
|
2016-01-11 18:53:19 +00:00
|
|
|
dBlockInlineMap, dBlockSequenceItem, dFlowImplicitMapKey, dFlowMapValue,
|
|
|
|
dFlowExplicitMapKey, dFlowSequenceItem, dFlowMapStart,
|
|
|
|
dFlowSequenceStart
|
2015-12-27 15:36:32 +00:00
|
|
|
|
2016-01-05 18:58:46 +00:00
|
|
|
proc needsEscaping(scalar: string): bool {.raises: [].} =
|
2015-12-29 17:22:55 +00:00
|
|
|
scalar.len == 0 or
|
|
|
|
scalar.find({'{', '}', '[', ']', ',', '#', '-', ':', '?', '%',
|
|
|
|
'\x0A', '\c'}) != -1
|
2015-12-27 15:36:32 +00:00
|
|
|
|
2016-01-05 18:58:46 +00:00
|
|
|
proc writeDoubleQuoted(scalar: string, s: Stream)
|
|
|
|
{.raises: [YamlPresenterOutputError].} =
|
|
|
|
try:
|
|
|
|
s.write('"')
|
|
|
|
for c in scalar:
|
|
|
|
if c == '"':
|
|
|
|
s.write('\\')
|
|
|
|
s.write(c)
|
|
|
|
s.write('"')
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterOutputError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
|
|
|
|
|
|
|
template safeWrite(s: string or char) {.dirty.} =
|
|
|
|
try:
|
|
|
|
target.write(s)
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterOutputError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
|
2016-01-04 20:46:33 +00:00
|
|
|
proc startItem(target: Stream, style: YamlPresentationStyle, indentation: int,
|
2016-01-11 18:12:55 +00:00
|
|
|
state: var DumperState, isObject: bool)
|
|
|
|
{.raises: [YamlPresenterOutputError].} =
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
case state
|
2016-01-11 18:12:55 +00:00
|
|
|
of dBlockMapValue:
|
2016-01-05 18:58:46 +00:00
|
|
|
target.write('\x0A')
|
2015-12-27 15:36:32 +00:00
|
|
|
target.write(repeat(' ', indentation))
|
2016-01-11 18:12:55 +00:00
|
|
|
if isObject or style == ypsCanonical:
|
|
|
|
target.write("? ")
|
|
|
|
state = dBlockExplicitMapKey
|
|
|
|
else:
|
|
|
|
state = dBlockImplicitMapKey
|
2016-01-11 18:53:19 +00:00
|
|
|
of dBlockInlineMap:
|
|
|
|
state = dBlockImplicitMapKey
|
2016-01-05 18:58:46 +00:00
|
|
|
of dBlockExplicitMapKey:
|
|
|
|
target.write('\x0A')
|
2015-12-27 15:36:32 +00:00
|
|
|
target.write(repeat(' ', indentation))
|
2016-01-05 18:58:46 +00:00
|
|
|
target.write(": ")
|
2016-01-11 18:12:55 +00:00
|
|
|
state = dBlockMapValue
|
2016-01-05 18:58:46 +00:00
|
|
|
of dBlockImplicitMapKey:
|
|
|
|
target.write(": ")
|
2016-01-11 18:12:55 +00:00
|
|
|
state = dBlockMapValue
|
2016-01-05 18:58:46 +00:00
|
|
|
of dFlowExplicitMapKey:
|
2016-01-11 19:58:24 +00:00
|
|
|
if style != ypsMinimal:
|
|
|
|
target.write('\x0A')
|
|
|
|
target.write(repeat(' ', indentation))
|
2016-01-05 18:58:46 +00:00
|
|
|
target.write(": ")
|
2016-01-11 18:12:55 +00:00
|
|
|
state = dFlowMapValue
|
|
|
|
of dFlowMapValue:
|
2016-01-11 19:59:49 +00:00
|
|
|
if (isObject and style != ypsMinimal) or
|
|
|
|
style in [ypsJson, ypsCanonical]:
|
2016-01-11 18:12:55 +00:00
|
|
|
target.write(",\x0A" & repeat(' ', indentation))
|
|
|
|
if style != ypsJson:
|
|
|
|
target.write("? ")
|
|
|
|
state = dFlowExplicitMapKey
|
2016-01-11 20:01:36 +00:00
|
|
|
elif isObject and style == ypsMinimal:
|
|
|
|
target.write(", ? ")
|
2016-01-05 18:58:46 +00:00
|
|
|
else:
|
|
|
|
target.write(", ")
|
2016-01-11 18:12:55 +00:00
|
|
|
state = dFlowImplicitMapKey
|
|
|
|
of dFlowMapStart:
|
2016-01-11 19:58:24 +00:00
|
|
|
if (isObject and style != ypsMinimal) or
|
|
|
|
style in [ypsJson, ypsCanonical]:
|
2016-01-11 18:12:55 +00:00
|
|
|
target.write("\x0A" & repeat(' ', indentation))
|
|
|
|
if style != ypsJson:
|
|
|
|
target.write("? ")
|
|
|
|
state = dFlowExplicitMapKey
|
|
|
|
else:
|
|
|
|
state = dFlowImplicitMapKey
|
|
|
|
of dFlowImplicitMapKey:
|
|
|
|
target.write(": ")
|
|
|
|
state = dFlowMapValue
|
2016-01-05 18:58:46 +00:00
|
|
|
of dBlockSequenceItem:
|
|
|
|
target.write('\x0A')
|
|
|
|
target.write(repeat(' ', indentation))
|
|
|
|
target.write("- ")
|
|
|
|
of dFlowSequenceStart:
|
|
|
|
case style
|
|
|
|
of ypsMinimal, ypsDefault:
|
|
|
|
discard
|
|
|
|
of ypsCanonical, ypsJson:
|
|
|
|
target.write('\x0A')
|
|
|
|
target.write(repeat(' ', indentation))
|
|
|
|
of ypsBlockOnly:
|
|
|
|
discard # can never happen
|
|
|
|
state = dFlowSequenceItem
|
|
|
|
of dFlowSequenceItem:
|
|
|
|
case style
|
|
|
|
of ypsMinimal, ypsDefault:
|
|
|
|
target.write(", ")
|
|
|
|
of ypsCanonical, ypsJson:
|
|
|
|
target.write(",\x0A")
|
|
|
|
target.write(repeat(' ', indentation))
|
|
|
|
of ypsBlockOnly:
|
|
|
|
discard # can never happen
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterOutputError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
|
|
|
|
proc writeTagAndAnchor(target: Stream, tag: TagId, tagLib: YamlTagLibrary,
|
2016-01-05 18:58:46 +00:00
|
|
|
anchor: AnchorId) {.raises:[YamlPresenterOutputError].} =
|
|
|
|
try:
|
|
|
|
if tag notin [yTagQuestionMark, yTagExclamationMark]:
|
|
|
|
let tagUri = tagLib.uri(tag)
|
|
|
|
if tagUri.startsWith(tagLib.secondaryPrefix):
|
|
|
|
target.write("!!")
|
|
|
|
target.write(tagUri[18..^1])
|
|
|
|
target.write(' ')
|
|
|
|
elif tagUri.startsWith("!"):
|
|
|
|
target.write(tagUri)
|
|
|
|
target.write(' ')
|
|
|
|
else:
|
|
|
|
target.write("!<")
|
|
|
|
target.write(tagUri)
|
|
|
|
target.write("> ")
|
|
|
|
if anchor != yAnchorNone:
|
|
|
|
target.write("&")
|
|
|
|
# TODO: properly select an anchor
|
|
|
|
target.write(cast[byte]('a') + cast[byte](anchor))
|
2016-01-04 20:46:33 +00:00
|
|
|
target.write(' ')
|
2016-01-05 18:58:46 +00:00
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterOutputError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
|
2015-12-29 17:22:55 +00:00
|
|
|
proc present*(s: YamlStream, target: Stream, tagLib: YamlTagLibrary,
|
2016-01-04 20:46:33 +00:00
|
|
|
style: YamlPresentationStyle = ypsDefault,
|
|
|
|
indentationStep: int = 2) =
|
2015-12-27 15:36:32 +00:00
|
|
|
var
|
|
|
|
cached = initQueue[YamlStreamEvent]()
|
|
|
|
cacheIterator = iterator(): YamlStreamEvent =
|
|
|
|
while true:
|
|
|
|
while cached.len > 0:
|
|
|
|
yield cached.dequeue()
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
let item = s()
|
|
|
|
if finished(s):
|
|
|
|
break
|
|
|
|
cached.enqueue(item)
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterStreamError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation = 0
|
|
|
|
levels = newSeq[DumperState]()
|
|
|
|
|
|
|
|
for item in cacheIterator():
|
|
|
|
case item.kind
|
|
|
|
of yamlStartDocument:
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2015-12-27 15:36:32 +00:00
|
|
|
# TODO: tag directives
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
target.write("%YAML 1.2\x0A")
|
|
|
|
if tagLib.secondaryPrefix != yamlTagRepositoryPrefix:
|
|
|
|
target.write("%TAG !! " &
|
|
|
|
tagLib.secondaryPrefix & '\x0A')
|
|
|
|
target.write("--- ")
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterOutputError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
of yamlScalar:
|
|
|
|
if levels.len == 0:
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite('\x0A')
|
2015-12-27 15:36:32 +00:00
|
|
|
else:
|
2016-01-11 18:12:55 +00:00
|
|
|
startItem(target, style, indentation, levels[levels.high],
|
|
|
|
false)
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2015-12-27 15:36:32 +00:00
|
|
|
writeTagAndAnchor(target,
|
|
|
|
item.scalarTag, tagLib, item.scalarAnchor)
|
|
|
|
|
2016-01-05 18:06:55 +00:00
|
|
|
if style == ypsJson:
|
|
|
|
if item.scalarTag in [yTagQuestionMark, yTagBoolean] and
|
|
|
|
item.scalarType in [yTypeBoolTrue, yTypeBoolFalse]:
|
|
|
|
if item.scalarType == yTypeBoolTrue:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite("true")
|
2016-01-05 18:06:55 +00:00
|
|
|
else:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite("false")
|
2016-01-05 18:06:55 +00:00
|
|
|
elif item.scalarTag in [yTagQuestionMark, yTagNull] and
|
|
|
|
item.scalarType == yTypeNull:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite("null")
|
2016-01-05 18:06:55 +00:00
|
|
|
elif item.scalarTag in [yTagQuestionMark, yTagFloat] and
|
|
|
|
item.scalarType in [yTypeFloatInf, yTypeFloatNaN]:
|
2016-01-05 18:58:46 +00:00
|
|
|
raise newException(YamlPresenterJsonError,
|
2016-01-05 18:06:55 +00:00
|
|
|
"Infinity and not-a-number values cannot be presented as JSON!")
|
2015-12-29 17:22:55 +00:00
|
|
|
else:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite(item.scalarContent)
|
2016-01-04 20:46:33 +00:00
|
|
|
elif style == ypsCanonical or item.scalarContent.needsEscaping or
|
|
|
|
(style == ypsJson and
|
2015-12-29 17:22:55 +00:00
|
|
|
(item.scalarTag notin [yTagQuestionMark, yTagInteger, yTagFloat,
|
|
|
|
yTagBoolean, yTagNull] or
|
|
|
|
(item.scalarTag == yTagQuestionMark and item.scalarType notin
|
|
|
|
[yTypeBoolFalse, yTypeBoolTrue, yTypeInteger, yTypeFloat,
|
|
|
|
yTypeNull]))):
|
2015-12-27 15:36:32 +00:00
|
|
|
writeDoubleQuoted(item.scalarContent, target)
|
|
|
|
else:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite(item.scalarContent)
|
2015-12-27 15:36:32 +00:00
|
|
|
of yamlAlias:
|
2016-01-05 18:06:55 +00:00
|
|
|
assert levels.len > 0
|
2016-01-11 18:12:55 +00:00
|
|
|
startItem(target, style, indentation, levels[levels.high], false)
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
target.write('*')
|
|
|
|
target.write(cast[byte]('a') + cast[byte](item.aliasTarget))
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterOutputError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
of yamlStartSequence:
|
|
|
|
var nextState: DumperState
|
|
|
|
case style
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsDefault:
|
2015-12-27 15:36:32 +00:00
|
|
|
var length = 0
|
|
|
|
while true:
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
let next = s()
|
|
|
|
assert (not finished(s))
|
|
|
|
cached.enqueue(next)
|
|
|
|
case next.kind
|
|
|
|
of yamlScalar:
|
|
|
|
length += 2 + next.scalarContent.len
|
|
|
|
of yamlAlias:
|
|
|
|
length += 6
|
|
|
|
of yamlEndSequence:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
length = int.high
|
|
|
|
break
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterStreamError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
nextState = if length <= 60: dFlowSequenceStart else:
|
|
|
|
dBlockSequenceItem
|
2016-01-05 18:06:55 +00:00
|
|
|
of ypsJson:
|
2016-01-07 10:58:33 +00:00
|
|
|
if levels.len > 0 and levels[levels.high] in
|
2016-01-11 18:12:55 +00:00
|
|
|
[dFlowMapStart, dFlowMapValue]:
|
2016-01-05 18:58:46 +00:00
|
|
|
raise newException(YamlPresenterJsonError,
|
2016-01-05 18:06:55 +00:00
|
|
|
"Cannot have sequence as map key in JSON output!")
|
|
|
|
nextState = dFlowSequenceStart
|
|
|
|
of ypsMinimal, ypsCanonical:
|
2015-12-27 15:36:32 +00:00
|
|
|
nextState = dFlowSequenceStart
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsBlockOnly:
|
2015-12-27 15:36:32 +00:00
|
|
|
nextState = dBlockSequenceItem
|
|
|
|
|
|
|
|
if levels.len == 0:
|
|
|
|
if nextState == dBlockSequenceItem:
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2015-12-27 15:36:32 +00:00
|
|
|
writeTagAndAnchor(target,
|
|
|
|
item.seqTag, tagLib, item.seqAnchor)
|
|
|
|
else:
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2015-12-27 15:36:32 +00:00
|
|
|
writeTagAndAnchor(target,
|
|
|
|
item.seqTag, tagLib, item.seqAnchor)
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite('\x0A')
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation += indentationStep
|
|
|
|
else:
|
2016-01-11 18:12:55 +00:00
|
|
|
startItem(target, style, indentation, levels[levels.high], true)
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2015-12-29 17:22:55 +00:00
|
|
|
writeTagAndAnchor(target,
|
|
|
|
item.seqTag, tagLib, item.seqAnchor)
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation += indentationStep
|
|
|
|
|
|
|
|
if nextState == dFlowSequenceStart:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite('[')
|
2016-01-04 20:46:33 +00:00
|
|
|
if levels.len > 0 and style in [ypsJson, ypsCanonical] and
|
2015-12-27 15:36:32 +00:00
|
|
|
levels[levels.high] in
|
2016-01-11 18:12:55 +00:00
|
|
|
[dBlockExplicitMapKey, dBlockMapValue,
|
|
|
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation += indentationStep
|
|
|
|
levels.add(nextState)
|
|
|
|
of yamlStartMap:
|
|
|
|
var nextState: DumperState
|
|
|
|
case style
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsDefault:
|
2016-01-11 18:53:19 +00:00
|
|
|
type mapParseState = enum
|
|
|
|
mpInitial, mpKey, mpValue, mpNeedBlock
|
|
|
|
var mps = mpInitial
|
|
|
|
while mps != mpNeedBlock:
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
let next = s()
|
|
|
|
assert (not finished(s))
|
|
|
|
cached.enqueue(next)
|
|
|
|
case next.kind
|
2016-01-11 18:53:19 +00:00
|
|
|
of yamlScalar, yamlAlias:
|
|
|
|
case mps
|
|
|
|
of mpInitial: mps = mpKey
|
|
|
|
of mpKey: mps = mpValue
|
|
|
|
else: mps = mpNeedBlock
|
2016-01-05 18:58:46 +00:00
|
|
|
of yamlEndMap:
|
|
|
|
break
|
|
|
|
else:
|
2016-01-11 18:53:19 +00:00
|
|
|
mps = mpNeedBlock
|
2016-01-05 18:58:46 +00:00
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterStreamError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2016-01-11 18:53:19 +00:00
|
|
|
nextState = if mps == mpNeedBlock: dBlockMapValue else:
|
|
|
|
dBlockInlineMap
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsMinimal:
|
2016-01-11 18:12:55 +00:00
|
|
|
nextState = dFlowMapStart
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsCanonical:
|
2016-01-11 18:12:55 +00:00
|
|
|
nextState = dFlowMapStart
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsJson:
|
2016-01-05 20:34:07 +00:00
|
|
|
if levels.len > 0 and levels[levels.high] in
|
2016-01-11 18:12:55 +00:00
|
|
|
[dFlowMapStart, dFlowMapValue]:
|
2016-01-05 18:58:46 +00:00
|
|
|
raise newException(YamlPresenterJsonError,
|
2016-01-05 18:06:55 +00:00
|
|
|
"Cannot have map as map key in JSON output!")
|
2016-01-11 18:12:55 +00:00
|
|
|
nextState = dFlowMapStart
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsBlockOnly:
|
2016-01-11 18:12:55 +00:00
|
|
|
nextState = dBlockMapValue
|
2015-12-27 15:36:32 +00:00
|
|
|
if levels.len == 0:
|
2016-01-11 18:12:55 +00:00
|
|
|
if nextState == dBlockMapValue:
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2015-12-27 15:36:32 +00:00
|
|
|
writeTagAndAnchor(target,
|
|
|
|
item.mapTag, tagLib, item.mapAnchor)
|
|
|
|
else:
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite('\x0A')
|
2015-12-27 15:36:32 +00:00
|
|
|
writeTagAndAnchor(target,
|
|
|
|
item.mapTag, tagLib, item.mapAnchor)
|
|
|
|
indentation += indentationStep
|
|
|
|
else:
|
2016-01-11 18:12:55 +00:00
|
|
|
if nextState in [dBlockMapValue, dBlockImplicitMapKey]:
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2015-12-27 15:36:32 +00:00
|
|
|
writeTagAndAnchor(target,
|
|
|
|
item.mapTag, tagLib, item.mapAnchor)
|
2016-01-11 18:12:55 +00:00
|
|
|
startItem(target, style, indentation, levels[levels.high],
|
|
|
|
true)
|
2015-12-27 15:36:32 +00:00
|
|
|
else:
|
2016-01-11 18:12:55 +00:00
|
|
|
startItem(target, style, indentation, levels[levels.high],
|
|
|
|
true)
|
2016-01-04 20:46:33 +00:00
|
|
|
if style != ypsJson:
|
2015-12-27 15:36:32 +00:00
|
|
|
writeTagAndAnchor(target,
|
|
|
|
item.mapTag, tagLib, item.mapAnchor)
|
|
|
|
indentation += indentationStep
|
|
|
|
|
2016-01-11 18:12:55 +00:00
|
|
|
if nextState == dFlowMapStart:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite('{')
|
2016-01-04 20:46:33 +00:00
|
|
|
if levels.len > 0 and style in [ypsJson, ypsCanonical] and
|
2015-12-27 15:36:32 +00:00
|
|
|
levels[levels.high] in
|
2016-01-11 18:12:55 +00:00
|
|
|
[dBlockExplicitMapKey, dBlockMapValue,
|
|
|
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation += indentationStep
|
|
|
|
levels.add(nextState)
|
|
|
|
|
|
|
|
of yamlEndSequence:
|
2016-01-05 18:06:55 +00:00
|
|
|
assert levels.len > 0
|
2015-12-27 15:36:32 +00:00
|
|
|
case levels.pop()
|
|
|
|
of dFlowSequenceItem:
|
|
|
|
case style
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsDefault, ypsMinimal, ypsBlockOnly:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite(']')
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsJson, ypsCanonical:
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation -= indentationStep
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
target.write('\x0A')
|
|
|
|
target.write(repeat(' ', indentation))
|
|
|
|
target.write(']')
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterOutputError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
if levels.len == 0 or levels[levels.high] notin
|
2016-01-11 18:12:55 +00:00
|
|
|
[dBlockExplicitMapKey, dBlockMapValue,
|
|
|
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
2015-12-27 15:36:32 +00:00
|
|
|
continue
|
|
|
|
of dFlowSequenceStart:
|
2016-01-04 20:46:33 +00:00
|
|
|
if levels.len > 0 and style in [ypsJson, ypsCanonical] and
|
2015-12-27 15:36:32 +00:00
|
|
|
levels[levels.high] in
|
2016-01-11 18:12:55 +00:00
|
|
|
[dBlockExplicitMapKey, dBlockMapValue,
|
|
|
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation -= indentationStep
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite(']')
|
2015-12-27 15:36:32 +00:00
|
|
|
of dBlockSequenceItem:
|
|
|
|
discard
|
|
|
|
else:
|
2016-01-05 18:06:55 +00:00
|
|
|
assert false
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation -= indentationStep
|
|
|
|
of yamlEndMap:
|
2016-01-05 18:06:55 +00:00
|
|
|
assert levels.len > 0
|
2016-01-11 20:10:30 +00:00
|
|
|
let level = levels.pop()
|
|
|
|
case level
|
2016-01-11 18:12:55 +00:00
|
|
|
of dFlowMapValue:
|
2015-12-27 15:36:32 +00:00
|
|
|
case style
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsDefault, ypsMinimal, ypsBlockOnly:
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite('}')
|
2016-01-04 20:46:33 +00:00
|
|
|
of ypsJson, ypsCanonical:
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation -= indentationStep
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
target.write('\x0A')
|
|
|
|
target.write(repeat(' ', indentation))
|
|
|
|
target.write('}')
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterOutputError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
2015-12-27 15:36:32 +00:00
|
|
|
if levels.len == 0 or levels[levels.high] notin
|
2016-01-11 18:12:55 +00:00
|
|
|
[dBlockExplicitMapKey, dBlockMapValue,
|
|
|
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
2015-12-27 15:36:32 +00:00
|
|
|
continue
|
2016-01-11 18:12:55 +00:00
|
|
|
of dFlowMapStart:
|
2016-01-04 20:46:33 +00:00
|
|
|
if levels.len > 0 and style in [ypsJson, ypsCanonical] and
|
2015-12-27 15:36:32 +00:00
|
|
|
levels[levels.high] in
|
2016-01-11 18:12:55 +00:00
|
|
|
[dBlockExplicitMapKey, dBlockMapValue,
|
|
|
|
dBlockImplicitMapKey, dBlockSequenceItem]:
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation -= indentationStep
|
2016-01-05 18:58:46 +00:00
|
|
|
safeWrite('}')
|
2016-01-11 20:08:57 +00:00
|
|
|
of dBlockMapValue, dBlockInlineMap, dBlockImplicitMapKey,
|
|
|
|
dBlockExplicitMapKey:
|
2015-12-27 15:36:32 +00:00
|
|
|
discard
|
|
|
|
else:
|
2016-01-11 20:10:30 +00:00
|
|
|
echo "Unexpected level: ", level
|
2016-01-05 18:06:55 +00:00
|
|
|
assert false
|
2015-12-27 15:36:32 +00:00
|
|
|
indentation -= indentationStep
|
|
|
|
of yamlEndDocument:
|
2016-01-05 18:58:46 +00:00
|
|
|
try:
|
|
|
|
let next = s()
|
|
|
|
if finished(s):
|
|
|
|
break
|
|
|
|
cached.enqueue(next)
|
|
|
|
except:
|
|
|
|
var e = newException(YamlPresenterStreamError, "")
|
|
|
|
e.cause = getCurrentException()
|
|
|
|
raise e
|
|
|
|
safeWrite("...\x0A")
|
2015-12-27 15:36:32 +00:00
|
|
|
|
2016-01-04 20:46:33 +00:00
|
|
|
proc transform*(input: Stream, output: Stream, style: YamlPresentationStyle,
|
2015-12-27 15:36:32 +00:00
|
|
|
indentationStep: int = 2) =
|
|
|
|
var
|
|
|
|
tagLib = extendedTagLibrary()
|
|
|
|
parser = newParser(tagLib)
|
2016-01-11 19:54:06 +00:00
|
|
|
events = parser.parse(input)
|
|
|
|
if style == ypsCanonical:
|
|
|
|
var specificTagEvents = iterator(): YamlStreamEvent =
|
|
|
|
for e in events():
|
|
|
|
var event = e
|
|
|
|
case event.kind
|
|
|
|
of yamlStartDocument, yamlEndDocument, yamlEndMap, yamlAlias,
|
|
|
|
yamlEndSequence:
|
|
|
|
discard
|
|
|
|
of yamlStartMap:
|
|
|
|
if event.mapTag in [yTagQuestionMark, yTagExclamationMark]:
|
|
|
|
event.mapTag = yTagMap
|
|
|
|
of yamlStartSequence:
|
|
|
|
if event.seqTag in [yTagQuestionMark, yTagExclamationMark]:
|
|
|
|
event.seqTag = yTagSequence
|
|
|
|
of yamlScalar:
|
|
|
|
if event.scalarTag == yTagQuestionMark:
|
|
|
|
case event.scalarType
|
|
|
|
of yTypeInteger:
|
|
|
|
event.scalarTag = yTagInteger
|
|
|
|
of yTypeFloat, yTypeFloatInf, yTypeFloatNaN:
|
|
|
|
event.scalarTag = yTagFloat
|
|
|
|
of yTypeBoolTrue, yTypeBoolFalse:
|
|
|
|
event.scalarTag = yTagBoolean
|
|
|
|
of yTypeNull:
|
|
|
|
event.scalarTag = yTagNull
|
|
|
|
of yTypeString, yTypeUnknown:
|
|
|
|
event.scalarTag = yTagString
|
|
|
|
elif event.scalarTag == yTagExclamationMark:
|
|
|
|
event.scalarTag = yTagString
|
|
|
|
yield event
|
|
|
|
present(specificTagEvents, output, tagLib, style,
|
|
|
|
indentationStep)
|
|
|
|
else:
|
|
|
|
present(parser.parse(input), output, tagLib, style,
|
|
|
|
indentationStep)
|