diff --git a/doc/api.txt b/doc/api.txt index 296a0d9..d8ae049 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -84,3 +84,24 @@ You can choose from multiple presentation styles. ``psJson`` is not able to process some features of ``YamlStream`` s, the other styles support all features and are guaranteed to round-trip to the same ``YamlStream`` if you parse the generated YAML character stream again. + +The Document Object Model +========================= + +Much like XML, YAML also defines a *document object model*. If you cannot or do +not want to load a YAML character stream to native Nim types, you can instead +load it into a ``YamlDocument``. This ``YamlDocument`` can also be serialized +into a YAML character stream. All tags will be preserved exactly as they are +when transforming from and to a ``YamlDocument``. The only important thing to +remember is that when a value has no tag, it will get the non-specific tag +``"!"`` for quoted scalars and ``"?"`` for all other nodes. + +While tags are preserved, anchors will be resolved during loading and re-added +during serialization. It is allowed for a ``YamlNode`` to occur multiple times +within a ``YamlDocument``, in which case it will be serialized once and referred +to afterwards via aliases. + +The document object model is provided for completeness, but you are encouraged +to use native Nim types as start- or endpoint instead. That may be significantly +faster, as every ``YamlNode`` is allocated on the heap and subject to garbage +collection. \ No newline at end of file diff --git a/doc/processing.svg b/doc/processing.svg index 8b62802..734b5d1 100644 --- a/doc/processing.svg +++ b/doc/processing.svg @@ -1,6 +1,6 @@ @@ -47,6 +47,16 @@ + + + + + + + + + + @@ -59,11 +69,11 @@ - + Application YAML - + Native @@ -73,7 +83,9 @@ Representation - not implemented + + YamlDocument + @@ -93,7 +105,7 @@ - + represent @@ -101,7 +113,9 @@ - serialize + + serialize + @@ -118,7 +132,9 @@ - compose + + compose + @@ -129,7 +145,7 @@ - + @@ -151,7 +167,19 @@ dump - + + + + dumpDOM + + + + + + loadDOM + + + load diff --git a/nimdoc.cfg b/nimdoc.cfg index 0d8acd5..30f342a 100644 --- a/nimdoc.cfg +++ b/nimdoc.cfg @@ -103,7 +103,7 @@ doc.file = """ -Fork me on GitHub +Fork me on GitHub
NimYAML Home diff --git a/private/dom.nim b/private/dom.nim new file mode 100644 index 0000000..4a9f19a --- /dev/null +++ b/private/dom.nim @@ -0,0 +1,204 @@ +proc newYamlNode*(content: string, tag: string = "?"): YamlNode = + new(result) + result.kind = yScalar + result.content = content + result.tag = tag + +proc newYamlNode*(children: openarray[YamlNode], tag: string = "?"): + YamlNode = + new(result) + result.kind = ySequence + result.children = @children + result.tag = tag + +proc newYamlNode*(pairs: openarray[tuple[key, value: YamlNode]], + tag: string = "?"): YamlNode = + new(result) + result.kind = yMapping + result.pairs = @pairs + result.tag = tag + +proc initYamlDoc*(root: YamlNode): YamlDocument = + result.root = root + +proc composeNode(s: var YamlStream, tagLib: TagLibrary, + c: ConstructionContext): + YamlNode {.raises: [YamlStreamError, YamlConstructionError].} = + let start = s.next() + new(result) + try: + case start.kind + of yamlStartMap: + result.tag = tagLib.uri(start.mapTag) + result.kind = yMapping + result.pairs = newSeq[tuple[key, value: YamlNode]]() + while s.peek().kind != yamlEndMap: + let + key = composeNode(s, tagLib, c) + value = composeNode(s, tagLib, c) + result.pairs.add((key: key, value: value)) + discard s.next() + if start.mapAnchor != yAnchorNone: + assert(not c.refs.hasKey(start.mapAnchor)) + c.refs[start.mapAnchor] = cast[pointer](result) + of yamlStartSequence: + result.tag = tagLib.uri(start.seqTag) + result.kind = ySequence + result.children = newSeq[YamlNode]() + while s.peek().kind != yamlEndSequence: + result.children.add(composeNode(s, tagLib, c)) + if start.seqAnchor != yAnchorNone: + assert(not c.refs.hasKey(start.seqAnchor)) + c.refs[start.seqAnchor] = cast[pointer](result) + discard s.next() + of yamlScalar: + result.tag = tagLib.uri(start.scalarTag) + result.kind = yScalar + result.content = start.scalarContent + if start.scalarAnchor != yAnchorNone: + assert(not c.refs.hasKey(start.scalarAnchor)) + c.refs[start.scalarAnchor] = cast[pointer](result) + of yamlAlias: + result = cast[YamlNode](c.refs[start.aliasTarget]) + else: assert false, "Malformed YamlStream" + except KeyError: + raise newException(YamlConstructionError, + "Wrong tag library: TagId missing") + +proc compose*(s: var YamlStream, tagLib: TagLibrary): YamlDocument + {.raises: [YamlStreamError, YamlConstructionError].} = + var context = newConstructionContext() + assert s.next().kind == yamlStartDocument + result.root = composeNode(s, tagLib, context) + assert s.next().kind == yamlEndDocument + +proc loadDOM*(s: Stream): YamlDocument + {.raises: [IOError, YamlParserError, YamlConstructionError].} = + var + tagLib = initExtendedTagLibrary() + parser = newYamlParser(tagLib) + events = parser.parse(s) + try: + result = compose(events, tagLib) + except YamlStreamError: + let e = getCurrentException() + if e.parent of YamlParserError: + raise (ref YamlParserError)(e.parent) + elif e.parent of IOError: + raise (ref IOError)(e.parent) + else: assert false, "Never happens: " & e.parent.repr + +proc serializeNode(n: YamlNode, c: SerializationContext, a: AnchorStyle, + tagLib: TagLibrary): RawYamlStream {.raises: [].}= + let p = cast[pointer](n) + if a != asNone and c.refs.hasKey(p): + try: + if c.refs[p] == yAnchorNone: + c.refs[p] = c.nextAnchorId + c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) + except KeyError: assert false, "Can never happen" + result = iterator(): YamlStreamEvent {.raises: [].} = + var event: YamlStreamEvent + try: event = aliasEvent(c.refs[p]) + except KeyError: assert false, "Can never happen" + yield event + return + var + tagId: TagId + anchor: AnchorId + try: + if a == asAlways: + c.refs[p] = c.nextAnchorId + c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) + else: c.refs[p] = yAnchorNone + tagId = if tagLib.tags.hasKey(n.tag): tagLib.tags[n.tag] else: + tagLib.registerUri(n.tag) + case a + of asNone: anchor = yAnchorNone + of asTidy: anchor = cast[AnchorId](n) + of asAlways: anchor = c.refs[p] + except KeyError: assert false, "Can never happen" + result = iterator(): YamlStreamEvent = + case n.kind + of yScalar: + yield scalarEvent(n.content, tagId, anchor) + of ySequence: + yield startSeqEvent(tagId, anchor) + for item in n.children: + var events = serializeNode(item, c, a, tagLib) + while true: + let event = events() + if finished(events): break + yield event + yield endSeqEvent() + of yMapping: + yield startMapEvent(tagId, anchor) + for i in n.pairs: + var events = serializeNode(i.key, c, a, tagLib) + while true: + let event = events() + if finished(events): break + yield event + events = serializeNode(i.value, c, a, tagLib) + while true: + let event = events() + if finished(events): break + yield event + yield endMapEvent() + +template processAnchoredEvent(target: expr, c: SerializationContext): stmt = + try: + let anchorId = c.refs[cast[pointer](target)] + if anchorId != yAnchorNone: + target = anchorId + else: target = yAnchorNone + except KeyError: assert false, "Can never happen" + yield event + +proc serialize*(doc: YamlDocument, tagLib: TagLibrary, a: AnchorStyle = asTidy): + YamlStream {.raises: [].} = + var + context = newSerializationContext(a) + events = serializeNode(doc.root, context, a, tagLib) + if a == asTidy: + var backend = iterator(): YamlStreamEvent {.raises: [].} = + var output = newSeq[YamlStreamEvent]() + while true: + let event = events() + if finished(events): break + output.add(event) + yield startDocEvent() + for event in output.mitems(): + case event.kind + of yamlScalar: + processAnchoredEvent(event.scalarAnchor, context) + of yamlStartMap: processAnchoredEvent(event.mapAnchor, context) + of yamlStartSequence: + processAnchoredEvent(event.seqAnchor, context) + else: yield event + yield endDocEvent() + result = initYamlStream(backend) + else: + var backend = iterator(): YamlStreamEvent {.raises: [].} = + yield startDocEvent() + while true: + let event = events() + if finished(events): break + yield event + yield endDocEvent() + result = initYamlStream(backend) + +proc dumpDOM*(doc: YamlDocument, target: Stream, + style: PresentationStyle = psDefault, + anchorStyle: AnchorStyle = asTidy, indentationStep: int = 2) + {.raises: [YamlPresenterJsonError, YamlPresenterOutputError].} = + ## Dump a YamlDocument as YAML character stream. + var + tagLib = initExtendedTagLibrary() + events = serialize(doc, tagLib, + if style == psJson: asNone else: anchorStyle) + try: + present(events, target, tagLib, style, indentationStep) + except YamlStreamError: + # serializing object does not raise any errors, so we can ignore this + assert false, "Can never happen" \ No newline at end of file diff --git a/private/serialization.nim b/private/serialization.nim index 7c47436..dd6cbdb 100644 --- a/private/serialization.nim +++ b/private/serialization.nim @@ -9,8 +9,9 @@ proc newConstructionContext(): ConstructionContext = proc newSerializationContext(s: AnchorStyle): SerializationContext = new(result) - result.refsList = newSeq[RefNodeData]() + result.refs = initTable[pointer, AnchorId]() result.style = s + result.nextAnchorId = 0.AnchorId proc initSerializationTagLibrary(): TagLibrary {.raises: [].} = result = initTagLibrary() @@ -494,41 +495,49 @@ proc representObject*[O](value: ref O, ts: TagStyle, c: SerializationContext): elif c.style == asNone: result = representObject(value[], ts, c) else: - let - p = cast[pointer](value) - for i in countup(0, c.refsList.high): - if p == c.refsList[i].p: - c.refsList[i].count.inc() - result = iterator(): YamlStreamEvent = - yield aliasEvent(if c.style == asAlways: AnchorId(i) else: - cast[AnchorId](p)) - return - c.refsList.add(initRefNodeData(p)) - let - a = if c.style == asAlways: AnchorId(c.refsList.high) else: - cast[AnchorId](p) - childTagStyle = if ts == tsAll: tsAll else: tsRootOnly - result = iterator(): YamlStreamEvent = - var child = representObject(value[], childTagStyle, c) - var first = child() - assert(not finished(child)) - case first.kind - of yamlStartMap: - first.mapAnchor = a - if ts == tsNone: first.mapTag = yTagQuestionMark - of yamlStartSequence: - first.seqAnchor = a - if ts == tsNone: first.seqTag = yTagQuestionMark - of yamlScalar: - first.scalarAnchor = a - if ts == tsNone and guessType(first.scalarContent) != yTypeNull: - first.scalarTag = yTagQuestionMark - else: discard - yield first - while true: - let event = child() - if finished(child): break + let p = cast[pointer](value) + if c.refs.hasKey(p): + try: + if c.refs[p] == yAnchorNone: + c.refs[p] = c.nextAnchorId + c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) + except KeyError: assert false, "Can never happen" + result = iterator(): YamlStreamEvent {.raises: [].} = + var event: YamlStreamEvent + try: event = aliasEvent(c.refs[p]) + except KeyError: assert false, "Can never happen" yield event + return + try: + if c.style == asAlways: + c.refs[p] = c.nextAnchorId + c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) + else: c.refs[p] = yAnchorNone + let + a = if c.style == asAlways: c.refs[p] else: cast[AnchorId](p) + childTagStyle = if ts == tsAll: tsAll else: tsRootOnly + result = iterator(): YamlStreamEvent = + var child = representObject(value[], childTagStyle, c) + var first = child() + assert(not finished(child)) + case first.kind + of yamlStartMap: + first.mapAnchor = a + if ts == tsNone: first.mapTag = yTagQuestionMark + of yamlStartSequence: + first.seqAnchor = a + if ts == tsNone: first.seqTag = yTagQuestionMark + of yamlScalar: + first.scalarAnchor = a + if ts == tsNone and guessType(first.scalarContent) != yTypeNull: + first.scalarTag = yTagQuestionMark + else: discard + yield first + while true: + let event = child() + if finished(child): break + yield event + except KeyError: assert false, "Can never happen" proc construct*[T](s: var YamlStream, target: var T) {.raises: [YamlConstructionError, YamlStreamError].} = @@ -577,29 +586,11 @@ proc load*[K](input: Stream, target: var K) else: assert(false) -proc setAnchor(a: var AnchorId, q: var seq[RefNodeData], n: var AnchorId) +proc setAnchor(a: var AnchorId, q: var Table[pointer, AnchorId]) {.inline.} = if a != yAnchorNone: - let p = cast[pointer](a) - for i in countup(0, q.len - 1): - if p == q[i].p: - if q[i].count > 1: - assert(q[i].anchor == yAnchorNone) - q[i].anchor = n - a = n - n = AnchorId(int(n) + 1) - else: a = yAnchorNone - break - -proc setAliasAnchor(a: var AnchorId, q: var seq[RefNodeData]) {.inline.} = - let p = cast[pointer](a) - for i in countup(0, q.len - 1): - if p == q[i].p: - assert q[i].count > 1 - assert q[i].anchor != yAnchorNone - a = q[i].anchor - return - assert(false) + try:a = q[cast[pointer](a)] + except KeyError: assert false, "Can never happen" proc represent*[T](value: T, ts: TagStyle = tsRootOnly, a: AnchorStyle = asTidy): YamlStream {.raises: [].} = @@ -621,21 +612,17 @@ proc represent*[T](value: T, ts: TagStyle = tsRootOnly, objQueue.add(event) except Exception: assert(false) - var next = 0.AnchorId var backend = iterator(): YamlStreamEvent = for i in countup(0, objQueue.len - 1): var event = objQueue[i] case event.kind of yamlStartMap: - event.mapAnchor.setAnchor(context.refsList, next) + event.mapAnchor.setAnchor(context.refs) of yamlStartSequence: - event.seqAnchor.setAnchor(context.refsList, next) + event.seqAnchor.setAnchor(context.refs) of yamlScalar: - event.scalarAnchor.setAnchor(context.refsList, next) - of yamlAlias: - event.aliasTarget.setAliasAnchor(context.refsList) - else: - discard + event.scalarAnchor.setAnchor(context.refs) + else: discard yield event result = initYamlStream(backend) else: diff --git a/test/common.nim b/test/common.nim new file mode 100644 index 0000000..6ca92ab --- /dev/null +++ b/test/common.nim @@ -0,0 +1,73 @@ +import "../yaml" + +proc printDifference*(expected, actual: YamlStreamEvent) = + if expected.kind != actual.kind: + echo "expected " & $expected.kind & ", got " & $actual.kind + else: + case expected.kind + of yamlScalar: + if expected.scalarTag != actual.scalarTag: + echo "[\"", actual.scalarContent, "\".tag] expected tag ", + expected.scalarTag, ", got ", actual.scalarTag + elif expected.scalarAnchor != actual.scalarAnchor: + echo "[scalarEvent] expected anchor ", expected.scalarAnchor, + ", got ", actual.scalarAnchor + elif expected.scalarContent != actual.scalarContent: + let msg = "[scalarEvent] expected content \"" & + expected.scalarContent & "\", got \"" & + actual.scalarContent & "\" " + if expected.scalarContent.len != actual.scalarContent.len: + echo msg, "(length does not match)" + else: + for i in 0..expected.scalarContent.high: + if expected.scalarContent[i] != actual.scalarContent[i]: + echo msg, "(first different char at pos ", i, + ": expected ", + cast[int](expected.scalarContent[i]), + ", got ", + cast[int](actual.scalarContent[i]), ")" + break + else: + echo "[scalarEvent] Unknown difference" + of yamlStartMap: + if expected.mapTag != actual.mapTag: + echo "[map.tag] expected ", expected.mapTag, ", got ", + actual.mapTag + elif expected.mapAnchor != actual.mapAnchor: + echo "[map.anchor] expected ", expected.mapAnchor, ", got ", + actual.mapAnchor + else: + echo "[map.tag] Unknown difference" + of yamlStartSequence: + if expected.seqTag != actual.seqTag: + echo "[seq.tag] expected ", expected.seqTag, ", got ", + actual.seqTag + elif expected.seqAnchor != actual.seqAnchor: + echo "[seq.anchor] expected ", expected.seqAnchor, ", got ", + actual.seqAnchor + else: + echo "[seq] Unknown difference" + of yamlAlias: + if expected.aliasTarget != actual.aliasTarget: + echo "[alias] expected ", expected.aliasTarget, ", got ", + actual.aliasTarget + else: + echo "[alias] Unknown difference" + else: + echo "Unknown difference in event kind " & $expected.kind + +template ensure*(input: var YamlStream, + expected: varargs[YamlStreamEvent]) {.dirty.} = + var i = 0 + for token in input: + if i >= expected.len: + echo "received more tokens than expected (next token = ", + token.kind, ")" + fail() + break + if token != expected[i]: + echo "at token #" & $i & ":" + printDifference(expected[i], token) + fail() + break + i.inc() \ No newline at end of file diff --git a/test/dom.nim b/test/dom.nim new file mode 100644 index 0000000..d17f2e3 --- /dev/null +++ b/test/dom.nim @@ -0,0 +1,88 @@ +import "../yaml" +import unittest, common + +suite "DOM": + test "DOM: Composing simple Scalar": + let + input = newStringStream("scalar") + result = loadDOM(input) + assert result.root.kind == yScalar + assert result.root.content == "scalar" + assert result.root.tag == "?" + test "DOM: Serializing simple Scalar": + let input = initYamlDoc(newYamlNode("scalar")) + var result = serialize(input, initExtendedTagLibrary()) + ensure(result, startDocEvent(), scalarEvent("scalar"), endDocEvent()) + test "DOM: Composing sequence": + let + input = newStringStream("- !!str a\n- !!bool no") + result = loadDOM(input) + assert result.root.kind == ySequence + assert result.root.tag == "?" + assert result.root.children.len == 2 + assert result.root.children[0].kind == yScalar + assert result.root.children[0].tag == "tag:yaml.org,2002:str" + assert result.root.children[0].content == "a" + assert result.root.children[1].kind == yScalar + assert result.root.children[1].tag == "tag:yaml.org,2002:bool" + assert result.root.children[1].content == "no" + test "DOM: Serializing sequence": + let input = initYamlDoc(newYamlNode([ + newYamlNode("a", "tag:yaml.org,2002:str"), + newYamlNode("no", "tag:yaml.org,2002:bool")])) + var result = serialize(input, initExtendedTagLibrary()) + ensure(result, startDocEvent(), startSeqEvent(), + scalarEvent("a", yTagString), scalarEvent("no", yTagBoolean), + endSeqEvent(), endDocEvent()) + test "DOM: Composing mapping": + let + input = newStringStream("--- !!map\n!foo bar: [a, b]") + result = loadDOM(input) + assert result.root.kind == yMapping + assert result.root.tag == "tag:yaml.org,2002:map" + assert result.root.pairs.len == 1 + assert result.root.pairs[0].key.kind == yScalar + assert result.root.pairs[0].key.tag == "!foo" + assert result.root.pairs[0].key.content == "bar" + assert result.root.pairs[0].value.kind == ySequence + assert result.root.pairs[0].value.children.len == 2 + test "DOM: Serializing mapping": + let input = initYamlDoc(newYamlNode([ + (key: newYamlNode("bar"), value: newYamlNode([newYamlNode("a"), + newYamlNode("b")]))])) + var result = serialize(input, initExtendedTagLibrary()) + ensure(result, startDocEvent(), startMapEvent(), scalarEvent("bar"), + startSeqEvent(), scalarEvent("a"), scalarEvent("b"), + endSeqEvent(), endMapEvent(), endDocEvent()) + test "DOM: Composing with anchors": + let + input = newStringStream("- &a foo\n- &b bar\n- *a\n- *b") + result = loadDOM(input) + assert result.root.kind == ySequence + assert result.root.children.len == 4 + assert result.root.children[0].kind == yScalar + assert result.root.children[0].content == "foo" + assert result.root.children[1].kind == yScalar + assert result.root.children[1].content == "bar" + assert result.root.children[0] == result.root.children[2] + assert result.root.children[1] == result.root.children[3] + test "DOM: Serializing with anchors": + let + a = newYamlNode("a") + b = newYamlNode("b") + input = initYamlDoc(newYamlNode([a, b, newYamlNode("c"), a, b])) + var result = serialize(input, initExtendedTagLibrary()) + ensure(result, startDocEvent(), startSeqEvent(), + scalarEvent("a", anchor=0.AnchorId), + scalarEvent("b", anchor=1.AnchorId), scalarEvent("c"), + aliasEvent(0.AnchorId), aliasEvent(1.AnchorId), endSeqEvent(), + endDocEvent()) + test "DOM: Serializing with all anchors": + let + a = newYamlNode("a") + input = initYamlDoc(newYamlNode([a, newYamlNode("b"), a])) + var result = serialize(input, initExtendedTagLibrary(), asAlways) + ensure(result, startDocEvent(), startSeqEvent(anchor=0.AnchorId), + scalarEvent("a", anchor=1.AnchorId), + scalarEvent("b", anchor=2.AnchorId), aliasEvent(1.AnchorId), + endSeqEvent(), endDocEvent()) \ No newline at end of file diff --git a/test/parsing.nim b/test/parsing.nim index 0aa4618..8661996 100644 --- a/test/parsing.nim +++ b/test/parsing.nim @@ -1,73 +1,12 @@ import "../yaml" -import unittest - -proc printDifference(expected, actual: YamlStreamEvent) = - if expected.kind != actual.kind: - echo "expected " & $expected.kind & ", got " & $actual.kind - else: - case expected.kind - of yamlScalar: - if expected.scalarTag != actual.scalarTag: - echo "[\"", actual.scalarContent, "\".tag] expected tag ", - expected.scalarTag, ", got ", actual.scalarTag - elif expected.scalarAnchor != actual.scalarAnchor: - echo "[scalarEvent] expected anchor ", expected.scalarAnchor, - ", got ", actual.scalarAnchor - elif expected.scalarContent != actual.scalarContent: - let msg = "[scalarEvent] expected content \"" & - expected.scalarContent & "\", got \"" & - actual.scalarContent & "\" " - if expected.scalarContent.len != actual.scalarContent.len: - echo msg, "(length does not match)" - else: - for i in 0..expected.scalarContent.high: - if expected.scalarContent[i] != actual.scalarContent[i]: - echo msg, "(first different char at pos ", i, - ": expected ", - cast[int](expected.scalarContent[i]), - ", got ", - cast[int](actual.scalarContent[i]), ")" - break - else: - echo "[scalarEvent] Unknown difference" - of yamlStartMap: - if expected.mapTag != actual.mapTag: - echo "[map.tag] expected ", expected.mapTag, ", got ", - actual.mapTag - else: - echo "[map.tag] Unknown difference" - of yamlStartSequence: - if expected.seqTag != actual.seqTag: - echo "[seq.tag] expected ", expected.seqTag, ", got ", - actual.seqTag - of yamlAlias: - if expected.aliasTarget != actual.aliasTarget: - echo "[alias] expected ", expected.aliasTarget, ", got ", - actual.aliasTarget - else: - echo "[alias] Unknown difference" - else: - echo "Unknown difference in event kind " & $expected.kind +import unittest, common template ensure(input: string, expected: varargs[YamlStreamEvent]) {.dirty.} = var - i = 0 parser = newYamlParser(tagLib) events = parser.parse(newStringStream(input)) - try: - for token in events: - if i >= expected.len: - echo "received more tokens than expected (next token = ", - token.kind, ")" - fail() - break - if token != expected[i]: - echo "at token #" & $i & ":" - printDifference(expected[i], token) - fail() - break - i.inc() + try: ensure(events, expected) except YamlParserError: let e = cast[ref YamlParserError](getCurrentException()) echo "Parser error:", getCurrentExceptionMsg() diff --git a/test/tests.nim b/test/tests.nim index f2134d4..90ded06 100644 --- a/test/tests.nim +++ b/test/tests.nim @@ -1 +1 @@ -import parsing, constructingJson, serializing \ No newline at end of file +import parsing, constructingJson, serializing, dom \ No newline at end of file diff --git a/yaml.nim b/yaml.nim index 16aa050..33061ae 100644 --- a/yaml.nim +++ b/yaml.nim @@ -218,12 +218,30 @@ type SerializationContext* = ref object ## Context information for the process of serializing YAML from Nim ## values. - refsList: seq[RefNodeData] + refs: Table[pointer, AnchorId] style: AnchorStyle + nextAnchorId: AnchorId RawYamlStream* = iterator(): YamlStreamEvent {.raises: [].} ## \ ## Stream of ``YamlStreamEvent``s returned by ``representObject`` procs. + YamlNodeKind* = enum + yScalar, yMapping, ySequence + + YamlNode* = ref YamlNodeObj not nil + ## Represents a node in a ``YamlDocument``. + + YamlNodeObj* = object + tag*: string + case kind*: YamlNodeKind + of yScalar: content*: string + of ySequence: children*: seq[YamlNode] + of yMapping: pairs*: seq[tuple[key, value: YamlNode]] + + YamlDocument* = object + ## Represents a YAML document. + root*: YamlNode + YamlLoadingError* = object of Exception ## Base class for all exceptions that may be raised during the process ## of loading a YAML character stream. @@ -521,4 +539,5 @@ include private.presenter include private.hints include private.fastparse include private.streams -include private.serialization \ No newline at end of file +include private.serialization +include private.dom \ No newline at end of file