diff --git a/private/dom.nim b/private/dom.nim index 9712557..c68e2d2 100644 --- a/private/dom.nim +++ b/private/dom.nim @@ -64,9 +64,11 @@ proc composeNode(s: var YamlStream, tagLib: TagLibrary, proc compose*(s: var YamlStream, tagLib: TagLibrary): YamlDocument {.raises: [YamlStreamError, YamlConstructionError].} = var context = newConstructionContext() - yAssert s.next().kind == yamlStartDoc + var n = s.next() + yAssert n.kind == yamlStartDoc result.root = composeNode(s, tagLib, context) - yAssert s.next().kind == yamlEndDoc + n = s.next() + yAssert n.kind == yamlEndDoc proc loadDOM*(s: Stream): YamlDocument {.raises: [IOError, YamlParserError, YamlConstructionError].} = diff --git a/private/streams.nim b/private/streams.nim index c9b1eac..7628514 100644 --- a/private/streams.nim +++ b/private/streams.nim @@ -4,18 +4,31 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. -proc initYamlStream*(backend: iterator(): YamlStreamEvent): YamlStream = - result.peeked = false - result.backend = backend +type IteratorYamlStream = ref object of YamlStream + backend: iterator(): YamlStreamEvent -proc next*(s: var YamlStream): YamlStreamEvent = +proc initYamlStream*(backend: iterator(): YamlStreamEvent): YamlStream = + result = new(IteratorYamlStream) + result.peeked = false + result.isFinished = false + IteratorYamlStream(result).backend = backend + result.nextImpl = proc(s: YamlStream, e: var YamlStreamEvent): bool = + e = IteratorYamlStream(s).backend() + if finished(IteratorYamlStream(s).backend): + s.isFinished = true + result = false + else: result = true + +proc next*(s: YamlStream): YamlStreamEvent = + yAssert(not s.isFinished) if s.peeked: s.peeked = false shallowCopy(result, s.cached) else: try: - shallowCopy(result, s.backend()) - yAssert(not finished(s.backend)) + while true: + if s.nextImpl(s, result): break + yAssert(not s.isFinished) except YamlStreamError: let cur = getCurrentException() var e = newException(YamlStreamError, cur.msg) @@ -27,25 +40,25 @@ proc next*(s: var YamlStream): YamlStreamEvent = e.parent = cur raise e -proc peek*(s: var YamlStream): YamlStreamEvent = +proc peek*(s: YamlStream): YamlStreamEvent = if not s.peeked: s.cached = s.next() s.peeked = true shallowCopy(result, s.cached) -proc `peek=`*(s: var YamlStream, value: YamlStreamEvent) = +proc `peek=`*(s: YamlStream, value: YamlStreamEvent) = s.cached = value s.peeked = true -proc finished*(s: var YamlStream): bool = +proc finished*(s: YamlStream): bool = if s.peeked: result = false else: try: - s.cached = s.backend() - if finished(s.backend): result = true - else: - s.peeked = true - result = false + while true: + if s.isFinished: return true + if s.nextImpl(s, s.cached): + s.peeked = true + return false except YamlStreamError: let cur = getCurrentException() var e = newException(YamlStreamError, cur.msg) diff --git a/yaml.nim b/yaml.nim index 837e9c6..d4211d5 100644 --- a/yaml.nim +++ b/yaml.nim @@ -99,7 +99,7 @@ type of yamlAlias: aliasTarget* : AnchorId - YamlStream* = object ## \ + YamlStream* = ref object of RootObj ## \ ## A ``YamlStream`` is an iterator-like object that yields a ## well-formed stream of ``YamlStreamEvents``. Well-formed means that ## every ``yamlStartMap`` is terminated by a ``yamlEndMap``, every @@ -112,9 +112,8 @@ type ## and is not required to check for it. The procs in this module will ## always yield a well-formed ``YamlStream`` and expect it to be ## well-formed if they take it as input parameter. - ## - ## - backend: iterator(): YamlStreamEvent + nextImpl: proc(s: YamlStream, e: var YamlStreamEvent): bool + isFinished: bool peeked: bool cached: YamlStreamEvent @@ -457,42 +456,25 @@ proc hash*(id: AnchorId): Hash {.borrow.} proc initYamlStream*(backend: iterator(): YamlStreamEvent): YamlStream {.raises: [].} ## Creates a new ``YamlStream`` that uses the given iterator as backend. -proc next*(s: var YamlStream): YamlStreamEvent {.raises: [YamlStreamError].} +proc next*(s: YamlStream): YamlStreamEvent {.raises: [YamlStreamError].} ## Get the next item of the stream. Requires ``finished(s) == true``. ## If the backend yields an exception, that exception will be encapsulated ## into a ``YamlStreamError``, which will be raised. -proc peek*(s: var YamlStream): YamlStreamEvent {.raises: [YamlStreamError].} +proc peek*(s: YamlStream): YamlStreamEvent {.raises: [YamlStreamError].} ## Get the next item of the stream without advancing the stream. ## Requires ``finished(s) == true``. Handles exceptions of the backend like ## ``next()``. -proc `peek=`*(s: var YamlStream, value: YamlStreamEvent) {.raises: [].} +proc `peek=`*(s: YamlStream, value: YamlStreamEvent) {.raises: [].} ## Set the next item of the stream. Will replace a previously peeked item, ## if one exists. -proc finished*(s: var YamlStream): bool {.raises: [YamlStreamError].} +proc finished*(s: YamlStream): bool {.raises: [YamlStreamError].} ## ``true`` if no more items are available in the stream. Handles exceptions ## of the backend like ``next()``. -iterator items*(s: var YamlStream): YamlStreamEvent +iterator items*(s: YamlStream): YamlStreamEvent {.raises: [YamlStreamError].} = ## Iterate over all items of the stream. You may not use ``peek()`` on the ## stream while iterating. - if s.peeked: - s.peeked = false - yield s.cached - while true: - var event: YamlStreamEvent - try: - event = s.backend() - if finished(s.backend): break - except YamlStreamError: - let cur = getCurrentException() - var e = newException(YamlStreamError, cur.msg) - e.parent = cur.parent - raise e - except Exception: - var e = newException(YamlStreamError, getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - yield event + while not s.finished(): yield s.next() proc initTagLibrary*(): TagLibrary {.raises: [].} ## initializes the ``tags`` table and sets ``nextCustomTagId`` to