From 2f3a8097387a80c4e9bebbb3f3e21676610e873c Mon Sep 17 00:00:00 2001 From: Felix Krause Date: Mon, 19 Sep 2016 19:33:29 +0200 Subject: [PATCH] Support JS string output in presenter --- private/dom.nim | 2 +- private/lex.nim | 6 +- private/parse.nim | 6 +- private/presenter.nim | 263 +++++++++++++++++++++----------------- private/serialization.nim | 9 +- private/stream.nim | 2 +- test/serializing.nim | 99 ++++++-------- yaml.nim | 19 ++- 8 files changed, 219 insertions(+), 187 deletions(-) diff --git a/private/dom.nim b/private/dom.nim index fe393a3..ae8ce9e 100644 --- a/private/dom.nim +++ b/private/dom.nim @@ -109,7 +109,7 @@ proc serializeNode(n: YamlNode, c: SerializationContext, a: AnchorStyle, of asNone: anchor = yAnchorNone of asTidy: anchor = cast[AnchorId](n) of asAlways: anchor = c.refs.getOrDefault(p) - + case n.kind of yScalar: c.put(scalarEvent(n.content, tagId, anchor)) of ySequence: diff --git a/private/lex.nim b/private/lex.nim index 2ad849d..edba682 100644 --- a/private/lex.nim +++ b/private/lex.nim @@ -907,7 +907,7 @@ proc blockScalar[T](lex: YamlLexer): bool = lex.buf.add(lex.c) lex.advance(T) if not blockScalarLineStart[T](lex, recentWasMoreIndented): break outer - + debug("lex: leaving block scalar at indentation " & $lex.indentation) case lex.chomp of ctStrip: discard @@ -935,7 +935,7 @@ proc dirEndAfterBlockScalar[T](lex: YamlLexer): bool = while lex.c in space: lex.advance(T) lex.nextState = lex.insideLineImpl result = true - + proc docEndAfterBlockScalar[T](lex: YamlLexer): bool = lex.cur = ltDocumentEnd lex.nextState = expectLineEnd[T] @@ -1183,4 +1183,4 @@ proc getTokenLine*(lex: YamlLexer, marker: bool = true): string = result = lex.tokenLineGetter(lex, marker) proc isImplicitKeyStart*(lex: YamlLexer): bool = - result = lex.searchColonImpl(lex) \ No newline at end of file + result = lex.searchColonImpl(lex) diff --git a/private/parse.nim b/private/parse.nim index 8ef4c98..fda5574 100644 --- a/private/parse.nim +++ b/private/parse.nim @@ -207,7 +207,7 @@ proc handleMapKeyIndicator(c: ParserContext, e: var YamlStreamEvent): bool = # ? - a # - b # and such. At the first `-`, the indentation must equal its level to be - # parsed properly. + # parsed properly. c.lex.indentation = c.lex.curStartPos.column - 1 proc handleBlockSequenceIndicator(c: ParserContext, e: var YamlStreamEvent): @@ -341,7 +341,7 @@ macro parserState(name: untyped, impl: untyped): typed = parserStates(initial, blockLineStart, blockObjectStart, blockAfterObject, scalarEnd, plainScalarEnd, objectEnd, expectDocEnd, startDoc, - afterDocument, closeStream, closeMoreIndentedLevels, + afterDocument, closeStream, closeMoreIndentedLevels, emitEmptyScalar, tagHandle, anchor, alias, flow, leaveFlowMap, leaveFlowSeq, flowAfterObject, leaveFlowSinglePairMap) @@ -969,7 +969,7 @@ proc init(c: ParserContext, p: YamlParser) = c.explicitFlowKey = false c.lastTokenContextImpl = lastTokenContext c.advance() - + proc parse*(p: YamlParser, s: Stream): YamlStream = let c = new(ParserContext) try: c.lex = newYamlLexer(s) diff --git a/private/presenter.nim b/private/presenter.nim index 03b5b40..1fee0e8 100644 --- a/private/presenter.nim +++ b/private/presenter.nim @@ -13,6 +13,8 @@ type ScalarStyle = enum sLiteral, sFolded, sPlain, sDoubleQuoted + PresenterTarget = Stream | ptr[string] + proc defineOptions*(style: PresentationStyle = psDefault, indentationStep: int = 2, newlines: NewLineStyle = nlOSDefault, @@ -95,109 +97,117 @@ proc inspect(scalar: string, indentation: int, elif canUsePlain: result = sPlain else: result = sDoubleQuoted -proc writeDoubleQuoted(scalar: string, s: Stream, indentation: int, +template append(target: Stream, val: string | char) = + target.write(val) + +template append(target: ptr[string], val: string | char) = + target[].add(val) + +proc writeDoubleQuoted(scalar: string, s: PresenterTarget, indentation: int, newline: string) {.raises: [YamlPresenterOutputError].} = var curPos = indentation try: - s.write('"') + s.append('"') curPos.inc() for c in scalar: if curPos == 79: - s.write('\\') - s.write(newline) - s.write(repeat(' ', indentation)) + s.append('\\') + s.append(newline) + s.append(repeat(' ', indentation)) curPos = indentation if c == ' ': - s.write('\\') + s.append('\\') curPos.inc() case c of '"': - s.write("\\\"") + s.append("\\\"") curPos.inc(2) of '\l': - s.write("\\n") + s.append("\\n") curPos.inc(2) of '\t': - s.write("\\t") + s.append("\\t") curPos.inc(2) of '\\': - s.write("\\\\") + s.append("\\\\") curPos.inc(2) else: if ord(c) < 32: - s.write("\\x" & toHex(ord(c), 2)) + s.append("\\x" & toHex(ord(c), 2)) curPos.inc(4) else: - s.write(c) + s.append(c) curPos.inc() - s.write('"') + s.append('"') except: var e = newException(YamlPresenterOutputError, "Error while writing to output stream") e.parent = getCurrentException() raise e -proc writeDoubleQuotedJson(scalar: string, s: Stream) +proc writeDoubleQuotedJson(scalar: string, s: PresenterTarget) {.raises: [YamlPresenterOutputError].} = try: - s.write('"') + s.append('"') for c in scalar: case c - of '"': s.write("\\\"") - of '\\': s.write("\\\\") - of '\l': s.write("\\n") - of '\t': s.write("\\t") - of '\f': s.write("\\f") - of '\b': s.write("\\b") + of '"': s.append("\\\"") + of '\\': s.append("\\\\") + of '\l': s.append("\\n") + of '\t': s.append("\\t") + of '\f': s.append("\\f") + of '\b': s.append("\\b") else: - if ord(c) < 32: s.write("\\u" & toHex(ord(c), 4)) else: s.write(c) - s.write('"') + if ord(c) < 32: s.append("\\u" & toHex(ord(c), 4)) else: s.append(c) + s.append('"') except: var e = newException(YamlPresenterOutputError, "Error while writing to output stream") e.parent = getCurrentException() raise e -proc writeLiteral(scalar: string, indentation, indentStep: int, s: Stream, - lines: seq[tuple[start, finish: int]], newline: string) +proc writeLiteral(scalar: string, indentation, indentStep: int, + s: PresenterTarget, lines: seq[tuple[start, finish: int]], + newline: string) {.raises: [YamlPresenterOutputError].} = try: - s.write('|') - if scalar[^1] != '\l': s.write('-') - if scalar[0] in [' ', '\t']: s.write($indentStep) + s.append('|') + if scalar[^1] != '\l': s.append('-') + if scalar[0] in [' ', '\t']: s.append($indentStep) for line in lines: - s.write(newline) - s.write(repeat(' ', indentation + indentStep)) + s.append(newline) + s.append(repeat(' ', indentation + indentStep)) if line.finish >= line.start: - s.write(scalar[line.start .. line.finish]) + s.append(scalar[line.start .. line.finish]) except: var e = newException(YamlPresenterOutputError, "Error while writing to output stream") e.parent = getCurrentException() raise e -proc writeFolded(scalar: string, indentation, indentStep: int, s: Stream, - words: seq[tuple[start, finish: int]], newline: string) +proc writeFolded(scalar: string, indentation, indentStep: int, + s: PresenterTarget, words: seq[tuple[start, finish: int]], + newline: string) {.raises: [YamlPresenterOutputError].} = try: - s.write(">") - if scalar[^1] != '\l': s.write('-') - if scalar[0] in [' ', '\t']: s.write($indentStep) + s.append(">") + if scalar[^1] != '\l': s.append('-') + if scalar[0] in [' ', '\t']: s.append($indentStep) var curPos = 80 for word in words: if word.start > 0 and scalar[word.start - 1] == '\l': - s.write(newline & newline) - s.write(repeat(' ', indentation + indentStep)) + s.append(newline & newline) + s.append(repeat(' ', indentation + indentStep)) curPos = indentation + indentStep elif curPos + (word.finish - word.start) > 80: - s.write(newline) - s.write(repeat(' ', indentation + indentStep)) + s.append(newline) + s.append(repeat(' ', indentation + indentStep)) curPos = indentation + indentStep else: - s.write(' ') + s.append(' ') curPos.inc() - s.write(scalar[word.start .. word.finish]) + s.append(scalar[word.start .. word.finish]) curPos += word.finish - word.start + 1 except: var e = newException(YamlPresenterOutputError, @@ -205,82 +215,82 @@ proc writeFolded(scalar: string, indentation, indentStep: int, s: Stream, e.parent = getCurrentException() raise e -template safeWrite(s: string or char) {.dirty.} = - try: target.write(s) +template safeWrite(target: PresenterTarget, s: string or char) = + try: target.append(s) except: var e = newException(YamlPresenterOutputError, "") e.parent = getCurrentException() raise e -proc startItem(target: Stream, style: PresentationStyle, indentation: int, - state: var DumperState, isObject: bool, newline: string) - {.raises: [YamlPresenterOutputError].} = +proc startItem(target: PresenterTarget, style: PresentationStyle, + indentation: int, state: var DumperState, isObject: bool, + newline: string) {.raises: [YamlPresenterOutputError].} = try: case state of dBlockMapValue: - target.write(newline) - target.write(repeat(' ', indentation)) + target.append(newline) + target.append(repeat(' ', indentation)) if isObject or style == psCanonical: - target.write("? ") + target.append("? ") state = dBlockExplicitMapKey else: state = dBlockImplicitMapKey of dBlockInlineMap: state = dBlockImplicitMapKey of dBlockExplicitMapKey: - target.write(newline) - target.write(repeat(' ', indentation)) - target.write(": ") + target.append(newline) + target.append(repeat(' ', indentation)) + target.append(": ") state = dBlockMapValue of dBlockImplicitMapKey: - target.write(": ") + target.append(": ") state = dBlockMapValue of dFlowExplicitMapKey: if style != psMinimal: - target.write(newline) - target.write(repeat(' ', indentation)) - target.write(": ") + target.append(newline) + target.append(repeat(' ', indentation)) + target.append(": ") state = dFlowMapValue of dFlowMapValue: if (isObject and style != psMinimal) or style in [psJson, psCanonical]: - target.write(',' & newline & repeat(' ', indentation)) + target.append(',' & newline & repeat(' ', indentation)) if style == psJson: state = dFlowImplicitMapKey else: - target.write("? ") + target.append("? ") state = dFlowExplicitMapKey elif isObject and style == psMinimal: - target.write(", ? ") + target.append(", ? ") state = dFlowExplicitMapKey else: - target.write(", ") + target.append(", ") state = dFlowImplicitMapKey of dFlowMapStart: if (isObject and style != psMinimal) or style in [psJson, psCanonical]: - target.write(newline & repeat(' ', indentation)) + target.append(newline & repeat(' ', indentation)) if style == psJson: state = dFlowImplicitMapKey else: - target.write("? ") + target.append("? ") state = dFlowExplicitMapKey else: state = dFlowImplicitMapKey of dFlowImplicitMapKey: - target.write(": ") + target.append(": ") state = dFlowMapValue of dBlockSequenceItem: - target.write(newline) - target.write(repeat(' ', indentation)) - target.write("- ") + target.append(newline) + target.append(repeat(' ', indentation)) + target.append("- ") of dFlowSequenceStart: case style of psMinimal, psDefault: discard of psCanonical, psJson: - target.write(newline) - target.write(repeat(' ', indentation)) + target.append(newline) + target.append(repeat(' ', indentation)) of psBlockOnly: discard # can never happen state = dFlowSequenceItem of dFlowSequenceItem: case style - of psMinimal, psDefault: target.write(", ") + of psMinimal, psDefault: target.append(", ") of psCanonical, psJson: - target.write(',' & newline) - target.write(repeat(' ', indentation)) + target.append(',' & newline) + target.append(repeat(' ', indentation)) of psBlockOnly: discard # can never happen except: var e = newException(YamlPresenterOutputError, "") @@ -296,26 +306,27 @@ proc anchorName(a: AnchorId): string {.raises: [].} = else: result.add(char(j + ord('0') - 26)) i -= 36 -proc writeTagAndAnchor(target: Stream, tag: TagId, tagLib: TagLibrary, +proc writeTagAndAnchor(target: PresenterTarget, tag: TagId, + tagLib: TagLibrary, 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..tagUri.high]) - target.write(' ') + target.append("!!") + target.append(tagUri[18..tagUri.high]) + target.append(' ') elif tagUri.startsWith("!"): - target.write(tagUri) - target.write(' ') + target.append(tagUri) + target.append(' ') else: - target.write("!<") - target.write(tagUri) - target.write("> ") + target.append("!<") + target.append(tagUri) + target.append("> ") if anchor != yAnchorNone: - target.write("&") - target.write(anchorName(anchor)) - target.write(' ') + target.append("&") + target.append(anchorName(anchor)) + target.append(' ') except: var e = newException(YamlPresenterOutputError, "") e.parent = getCurrentException() @@ -329,7 +340,8 @@ proc nextItem(c: var Queue, s: var YamlStream): else: result = s.next() -proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, +proc doPresent(s: var YamlStream, target: PresenterTarget, + tagLib: TagLibrary, options: PresentationOptions = defaultPresentationOptions) = var indentation = 0 @@ -345,19 +357,19 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, # TODO: tag directives try: case options.outputVersion - of ov1_2: target.write("%YAML 1.2" & newline) - of ov1_1: target.write("%YAML 1.1" & newLine) + of ov1_2: target.append("%YAML 1.2" & newline) + of ov1_1: target.append("%YAML 1.1" & newLine) of ovNone: discard if tagLib.secondaryPrefix != yamlTagRepositoryPrefix: - target.write("%TAG !! " & tagLib.secondaryPrefix & newline) - target.write("--- ") + target.append("%TAG !! " & tagLib.secondaryPrefix & newline) + target.append("--- ") except: var e = newException(YamlPresenterOutputError, "") e.parent = getCurrentException() raise e of yamlScalar: if levels.len == 0: - if options.style != psJson: safeWrite(newline) + if options.style != psJson: target.safeWrite(newline) else: startItem(target, options.style, indentation, levels[levels.high], false, newline) @@ -368,22 +380,22 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, let hint = guessType(item.scalarContent) if item.scalarTag in [yTagQuestionMark, yTagBoolean] and hint in {yTypeBoolTrue, yTypeBoolFalse}: - safeWrite(if hint == yTypeBoolTrue: "true" else: "false") + target.safeWrite(if hint == yTypeBoolTrue: "true" else: "false") elif item.scalarTag in [yTagQuestionMark, yTagNull] and hint == yTypeNull: - safeWrite("null") + target.safeWrite("null") elif item.scalarTag in [yTagQuestionMark, yTagInteger, yTagNimInt8, yTagNimInt16, yTagNimInt32, yTagNimInt64, yTagNimUInt8, yTagNimUInt16, yTagNimUInt32, yTagNimUInt64] and hint == yTypeInteger: - safeWrite(item.scalarContent) + target.safeWrite(item.scalarContent) elif item.scalarTag in [yTagQuestionMark, yTagFloat, yTagNimFloat32, yTagNimFloat64] and hint in {yTypeFloatInf, yTypeFloatNaN}: raise newException(YamlPresenterJsonError, "Infinity and not-a-number values cannot be presented as JSON!") elif item.scalarTag in [yTagQuestionMark, yTagFloat] and hint == yTypeFloat: - safeWrite(item.scalarContent) + target.safeWrite(item.scalarContent) else: writeDoubleQuotedJson(item.scalarContent, target) elif options.style == psCanonical: writeDoubleQuoted(item.scalarContent, target, @@ -396,7 +408,7 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, options.indentationStep, target, lines, newline) of sFolded: writeFolded(item.scalarContent, indentation, options.indentationStep, target, words, newline) - of sPlain: safeWrite(item.scalarContent) + of sPlain: target.safeWrite(item.scalarContent) of sDoubleQuoted: writeDoubleQuoted(item.scalarContent, target, indentation + options.indentationStep, newline) of yamlAlias: @@ -407,8 +419,8 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, startItem(target, options.style, indentation, levels[levels.high], false, newline) try: - target.write('*') - target.write(cast[byte]('a') + cast[byte](item.aliasTarget)) + target.append('*') + target.append(char(byte('a') + byte(item.aliasTarget))) except: var e = newException(YamlPresenterOutputError, "") e.parent = getCurrentException() @@ -445,7 +457,7 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, if options.style != psJson: writeTagAndAnchor(target, item.seqTag, tagLib, item.seqAnchor) of dFlowSequenceStart: - safeWrite(newline) + target.safeWrite(newline) if options.style != psJson: writeTagAndAnchor(target, item.seqTag, tagLib, item.seqAnchor) indentation += options.indentationStep @@ -457,7 +469,7 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, writeTagAndAnchor(target, item.seqTag, tagLib, item.seqAnchor) indentation += options.indentationStep - if nextState == dFlowSequenceStart: safeWrite('[') + if nextState == dFlowSequenceStart: target.safeWrite('[') if levels.len > 0 and options.style in [psJson, psCanonical] and levels[levels.high] in [dBlockExplicitMapKey, dBlockMapValue, dBlockImplicitMapKey, dBlockSequenceItem]: @@ -496,11 +508,11 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) else: if options.style != psJson: - safeWrite(newline) + target.safeWrite(newline) writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) indentation += options.indentationStep of dFlowMapStart: - safeWrite(newline) + target.safeWrite(newline) if options.style != psJson: writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) indentation += options.indentationStep @@ -519,7 +531,7 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) indentation += options.indentationStep - if nextState == dFlowMapStart: safeWrite('{') + if nextState == dFlowMapStart: target.safeWrite('{') if levels.len > 0 and options.style in [psJson, psCanonical] and levels[levels.high] in [dBlockExplicitMapKey, dBlockMapValue, @@ -532,13 +544,13 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, case levels.pop() of dFlowSequenceItem: case options.style - of psDefault, psMinimal, psBlockOnly: safeWrite(']') + of psDefault, psMinimal, psBlockOnly: target.safeWrite(']') of psJson, psCanonical: indentation -= options.indentationStep try: - target.write(newline) - target.write(repeat(' ', indentation)) - target.write(']') + target.append(newline) + target.append(repeat(' ', indentation)) + target.append(']') except: var e = newException(YamlPresenterOutputError, "") e.parent = getCurrentException() @@ -552,7 +564,7 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, levels[levels.high] in [dBlockExplicitMapKey, dBlockMapValue, dBlockImplicitMapKey, dBlockSequenceItem]: indentation -= options.indentationStep - safeWrite(']') + target.safeWrite(']') of dBlockSequenceItem: discard else: internalError("Invalid popped level") indentation -= options.indentationStep @@ -562,13 +574,13 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, case level of dFlowMapValue: case options.style - of psDefault, psMinimal, psBlockOnly: safeWrite('}') + of psDefault, psMinimal, psBlockOnly: target.safeWrite('}') of psJson, psCanonical: indentation -= options.indentationStep try: - target.write(newline) - target.write(repeat(' ', indentation)) - target.write('}') + target.append(newline) + target.append(repeat(' ', indentation)) + target.append('}') except: var e = newException(YamlPresenterOutputError, "") e.parent = getCurrentException() @@ -582,7 +594,7 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, levels[levels.high] in [dBlockExplicitMapKey, dBlockMapValue, dBlockImplicitMapKey, dBlockSequenceItem]: indentation -= options.indentationStep - safeWrite('}') + target.safeWrite('}') of dBlockMapValue, dBlockInlineMap: discard else: internalError("Invalid level: " & $level) indentation -= options.indentationStep @@ -591,10 +603,21 @@ proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, if options.style == psJson: raise newException(YamlPresenterJsonError, "Cannot output more than one document in JSON style") - safeWrite("..." & newline) + target.safeWrite("..." & newline) -proc transform*(input: Stream, output: Stream, - options: PresentationOptions = defaultPresentationOptions) = +proc present*(s: var YamlStream, target: Stream, + tagLib: TagLibrary, + options: PresentationOptions = defaultPresentationOptions) = + doPresent(s, target, tagLib, options) + +proc present*(s: var YamlStream, tagLib: TagLibrary, + options: PresentationOptions = defaultPresentationOptions): + string = + result = "" + doPresent(s, addr result, tagLib, options) + +proc doTransform(input: Stream | string, output: PresenterTarget, + options: PresentationOptions = defaultPresentationOptions) = var taglib = initExtendedTagLibrary() parser = newYamlParser(tagLib) @@ -633,3 +656,13 @@ proc transform*(input: Stream, output: Stream, if e.parent of IOError: raise (ref IOError)(e.parent) elif e.parent of YamlParserError: raise (ref YamlParserError)(e.parent) else: internalError("Unexpected exception: " & e.parent.repr) + +proc transform*(input: Stream | string, output: Stream, + options: PresentationOptions = defaultPresentationOptions) = + doTransform(input, output, options) + +proc transform*(input: Stream | string, + options: PresentationOptions = defaultPresentationOptions): + string = + result = "" + doTransform(input, addr result, options) diff --git a/private/serialization.nim b/private/serialization.nim index 4b1aac3..abbd06c 100644 --- a/private/serialization.nim +++ b/private/serialization.nim @@ -809,6 +809,9 @@ proc dump*[K](value: K, tagStyle: TagStyle = tsRootOnly, anchorStyle: AnchorStyle = asTidy, options: PresentationOptions = defaultPresentationOptions): string = - var s = newStringStream() - dump(value, s, tagStyle, anchorStyle, options) - shallowCopy(result, s.data) \ No newline at end of file + var events = represent(value, + if options.style == psCanonical: tsAll else: tagStyle, + if options.style == psJson: asNone else: anchorStyle) + try: result = present(events, serializationTagLibrary, options) + except YamlStreamError: + internalError("Unexpected exception: " & getCurrentException().repr) diff --git a/private/stream.nim b/private/stream.nim index 7170201..d5b8553 100644 --- a/private/stream.nim +++ b/private/stream.nim @@ -99,4 +99,4 @@ proc finished*(s: YamlStream): bool = proc getLastTokenContext*(s: YamlStream, line, column: var int, lineContent: var string): bool = - result = s.lastTokenContextImpl(s, line, column, lineContent) \ No newline at end of file + result = s.lastTokenContextImpl(s, line, column, lineContent) diff --git a/test/serializing.nim b/test/serializing.nim index 4b7a113..d48f968 100644 --- a/test/serializing.nim +++ b/test/serializing.nim @@ -91,14 +91,13 @@ suite "Serialization": test "Dump integer without fixed length": var input = -4247 - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) - assertStringEqual "%YAML 1.2\n--- \n\"-4247\"", output.data + var output = dump(input, tsNone, asTidy, blockOnly) + assertStringEqual "%YAML 1.2\n--- \n\"-4247\"", output when sizeof(int) == sizeof(int64): input = int(int32.high) + 1 var gotException = false - try: dump(input, output, tsNone, asTidy, blockOnly) + try: output = dump(input, tsNone, asTidy, blockOnly) except: gotException = true assert gotException, "Expected exception, got none." @@ -110,9 +109,8 @@ suite "Serialization": test "Dump nil string": let input: string = nil - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) - assertStringEqual "%YAML 1.2\n--- \n!nim:nil:string \"\"", output.data + var output = dump(input, tsNone, asTidy, blockOnly) + assertStringEqual "%YAML 1.2\n--- \n!nim:nil:string \"\"", output test "Load string sequence": let input = newStringStream(" - a\n - b") @@ -124,9 +122,8 @@ suite "Serialization": test "Dump string sequence": var input = @["a", "b"] - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) - assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output.data + var output = dump(input, tsNone, asTidy, blockOnly) + assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output test "Load nil seq": let input = newStringStream("!nim:nil:seq \"\"") @@ -136,9 +133,8 @@ suite "Serialization": test "Dump nil seq": let input: seq[int] = nil - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) - assertStringEqual "%YAML 1.2\n--- \n!nim:nil:seq \"\"", output.data + var output = dump(input, tsNone, asTidy, blockOnly) + assertStringEqual "%YAML 1.2\n--- \n!nim:nil:seq \"\"", output test "Load char set": let input = newStringStream("- a\n- b") @@ -150,10 +146,9 @@ suite "Serialization": test "Dump char set": var input = {'a', 'b'} - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) - assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output.data - + var output = dump(input, tsNone, asTidy, blockOnly) + assertStringEqual "%YAML 1.2\n--- \n- a\n- b", output + test "Load array": let input = newStringStream("- 23\n- 42\n- 47") var result: array[0..2, int32] @@ -164,9 +159,8 @@ suite "Serialization": test "Dump array": let input = [23'i32, 42'i32, 47'i32] - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) - assertStringEqual "%YAML 1.2\n--- \n- 23\n- 42\n- 47", output.data + var output = dump(input, tsNone, asTidy, blockOnly) + assertStringEqual "%YAML 1.2\n--- \n- 23\n- 42\n- 47", output test "Load Table[int, string]": let input = newStringStream("23: dreiundzwanzig\n42: zweiundvierzig") @@ -180,10 +174,9 @@ suite "Serialization": var input = initTable[int32, string]() input[23] = "dreiundzwanzig" input[42] = "zweiundvierzig" - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) + var output = dump(input, tsNone, asTidy, blockOnly) assertStringEqual("%YAML 1.2\n--- \n23: dreiundzwanzig\n42: zweiundvierzig", - output.data) + output) test "Load OrderedTable[tuple[int32, int32], string]": let input = newStringStream("- {a: 23, b: 42}: drzw\n- {a: 13, b: 47}: drsi") @@ -205,8 +198,7 @@ suite "Serialization": var input = initOrderedTable[tuple[a, b: int32], string]() input.add((a: 23'i32, b: 42'i32), "dreiundzwanzigzweiundvierzig") input.add((a: 13'i32, b: 47'i32), "dreizehnsiebenundvierzig") - var output = newStringStream() - dump(input, output, tsRootOnly, asTidy, blockOnly) + var output = dump(input, tsRootOnly, asTidy, blockOnly) assertStringEqual("""%YAML 1.2 --- !nim:tables:OrderedTable(nim:tuple(nim:system:int32,nim:system:int32),tag:yaml.org,2002:str) - @@ -218,7 +210,7 @@ suite "Serialization": ? a: 13 b: 47 - : dreizehnsiebenundvierzig""", output.data) + : dreizehnsiebenundvierzig""", output) test "Load Sequences in Sequence": let input = newStringStream(" - [1, 2, 3]\n - [4, 5]\n - [6]") @@ -231,13 +223,12 @@ suite "Serialization": test "Dump Sequences in Sequence": let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32], @[6.int32]] - var output = newStringStream() - dump(input, output, tsNone) - assertStringEqual "%YAML 1.2\n--- \n- [1, 2, 3]\n- [4, 5]\n- [6]", - output.data + var output = dump(input, tsNone) + assertStringEqual "%YAML 1.2\n--- \n- [1, 2, 3]\n- [4, 5]\n- [6]", output test "Load Enum": - let input = newStringStream("!nim:system:seq(tl)\n- !tl tlRed\n- tlGreen\n- tlYellow") + let input = + newStringStream("!nim:system:seq(tl)\n- !tl tlRed\n- tlGreen\n- tlYellow") var result: seq[TrafficLight] load(input, result) assert result.len == 3 @@ -247,10 +238,8 @@ suite "Serialization": test "Dump Enum": let input = @[tlRed, tlGreen, tlYellow] - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) - assertStringEqual "%YAML 1.2\n--- \n- tlRed\n- tlGreen\n- tlYellow", - output.data + var output = dump(input, tsNone, asTidy, blockOnly) + assertStringEqual "%YAML 1.2\n--- \n- tlRed\n- tlGreen\n- tlYellow", output test "Load Tuple": let input = newStringStream("str: value\ni: 42\nb: true") @@ -262,9 +251,8 @@ suite "Serialization": test "Dump Tuple": let input = (str: "value", i: 42.int32, b: true) - var output = newStringStream() - dump(input, output, tsNone) - assertStringEqual "%YAML 1.2\n--- \nstr: value\ni: 42\nb: y", output.data + var output = dump(input, tsNone) + assertStringEqual "%YAML 1.2\n--- \nstr: value\ni: 42\nb: y", output test "Load custom object": let input = newStringStream("firstnamechar: P\nsurname: Pan\nage: 12") @@ -276,10 +264,9 @@ suite "Serialization": test "Dump custom object": let input = Person(firstnamechar: 'P', surname: "Pan", age: 12) - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) + var output = dump(input, tsNone, asTidy, blockOnly) assertStringEqual( - "%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12", output.data) + "%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12", output) test "Serialization: Load sequence with explicit tags": let input = newStringStream("--- !nim:system:seq(" & @@ -291,10 +278,9 @@ suite "Serialization": test "Dump sequence with explicit tags": let input = @["one", "two"] - var output = newStringStream() - dump(input, output, tsAll, asTidy, blockOnly) + var output = dump(input, tsAll, asTidy, blockOnly) assertStringEqual("%YAML 1.2\n--- !nim:system:seq(" & - "tag:yaml.org,2002:str) \n- !!str one\n- !!str two", output.data) + "tag:yaml.org,2002:str) \n- !!str one\n- !!str two", output) test "Load custom object with explicit root tag": let input = newStringStream( @@ -307,11 +293,10 @@ suite "Serialization": test "Dump custom object with explicit root tag": let input = Person(firstnamechar: 'P', surname: "Pan", age: 12) - var output = newStringStream() - dump(input, output, tsRootOnly, asTidy, blockOnly) + var output = dump(input, tsRootOnly, asTidy, blockOnly) assertStringEqual("%YAML 1.2\n" & "--- !nim:custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12", - output.data) + output) test "Load custom variant object": let input = newStringStream( @@ -330,8 +315,7 @@ suite "Serialization": test "Dump custom variant object": let input = @[Animal(name: "Bastet", kind: akCat, purringIntensity: 7), Animal(name: "Anubis", kind: akDog, barkometer: 13)] - var output = newStringStream() - dump(input, output, tsNone, asTidy, blockOnly) + var output = dump(input, tsNone, asTidy, blockOnly) assertStringEqual """%YAML 1.2 --- - @@ -347,7 +331,7 @@ suite "Serialization": - kind: akDog - - barkometer: 13""", output.data + barkometer: 13""", output test "Dump cyclic data structure": var @@ -357,8 +341,7 @@ suite "Serialization": a.next = b b.next = c c.next = a - var output = newStringStream() - dump(a, output, tsRootOnly, asTidy, blockOnly) + var output = dump(a, tsRootOnly, asTidy, blockOnly) assertStringEqual """%YAML 1.2 --- !example.net:Node &a value: a @@ -366,7 +349,7 @@ next: value: b next: value: c - next: *a""", output.data + next: *a""", output test "Load cyclic data structure": let input = newStringStream("""%YAML 1.2 @@ -416,11 +399,10 @@ next: input.add(nil) input.add(new string) input[1][] = "~" - var output = newStringStream() - dump(input, output, tsRootOnly, asTidy, blockOnly) + var output = dump(input, tsRootOnly, asTidy, blockOnly) assertStringEqual( "%YAML 1.2\n--- !nim:system:seq(tag:yaml.org,2002:str) \n- !!null ~\n- !!str ~", - output.data) + output) test "Custom constructObject": let input = newStringStream("- 1\n- !test:BetterInt 2") @@ -432,10 +414,9 @@ next: test "Custom representObject": let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt] - var output = newStringStream() - dump(input, output, tsAll, asTidy, blockOnly) + var output = dump(input, tsAll, asTidy, blockOnly) assertStringEqual """%YAML 1.2 --- !nim:system:seq(test:BetterInt) - !test:BetterInt 1 - !test:BetterInt 9_998_887 -- !test:BetterInt 98_312""", output.data \ No newline at end of file +- !test:BetterInt 98_312""", output diff --git a/yaml.nim b/yaml.nim index 7f97bda..3bf4a87 100644 --- a/yaml.nim +++ b/yaml.nim @@ -554,13 +554,20 @@ proc loadToJson*(s: Stream): seq[JsonNode] {.raises: [YamlParserError].} ## `constructJson <#constructJson>`_ to construct an in-memory JSON tree ## from a YAML character stream. -proc present*(s: var YamlStream, target: Stream, tagLib: TagLibrary, +proc present*(s: var YamlStream, target: Stream, + tagLib: TagLibrary, options: PresentationOptions = defaultPresentationOptions) {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, YamlStreamError].} ## Convert ``s`` to a YAML character stream and write it to ``target``. -proc transform*(input: Stream, output: Stream, +proc present*(s: var YamlStream, tagLib: TagLibrary, + options: PresentationOptions = defaultPresentationOptions): + string {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, + YamlStreamError].} + ## Convert ``s`` to a YAML character stream and return it as string. + +proc transform*(input: Stream | string, output: Stream, options: PresentationOptions = defaultPresentationOptions) {.raises: [IOError, YamlParserError, YamlPresenterJsonError, YamlPresenterOutputError].} @@ -568,6 +575,14 @@ proc transform*(input: Stream, output: Stream, ## while resolving non-specific tags to the ones in the YAML core tag ## library. +proc transform*(input: Stream | string, + options: PresentationOptions = defaultPresentationOptions): + string {.raises: [IOError, YamlParserError, YamlPresenterJsonError, + YamlPresenterOutputError].} + ## Parser ``input`` as YAML character stream, resolves non-specific tags to + ## the ones in the YAML core tag library, and then returns a serialized + ## YAML string that represents the stream. + proc constructChild*[T](s: var YamlStream, c: ConstructionContext, result: var T) {.raises: [YamlConstructionError, YamlStreamError].}