diff --git a/.github/workflows/build-linux.yaml b/.github/workflows/build-linux.yaml index 09fa62f..bb5d6ce 100644 --- a/.github/workflows/build-linux.yaml +++ b/.github/workflows/build-linux.yaml @@ -1,6 +1,6 @@ # Build workflow for Linux - updated to use modern Ubuntu name: "Build-Linux" -on: +on: # Triggers the workflow on push or pull request events but only for the "main" branch push: branches: [ "main" ] @@ -8,6 +8,9 @@ on: branches: [ "main" ] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: + # Trigger on release creation + release: + types: [created] jobs: build: @@ -16,7 +19,8 @@ jobs: matrix: os: [ubuntu-24.04] nimversion: - - 1.6.6 + - 2.0.10 + - 2.2.0 steps: # Checkout the repository code @@ -60,6 +64,7 @@ jobs: # Upload the built binary as an artifact - name: Upload binary artifact + if: github.event_name == 'release' && matrix.nimversion == '2.2.0' uses: actions/upload-artifact@v4 with: name: qax-linux diff --git a/.github/workflows/build-macos.yaml b/.github/workflows/build-macos.yaml index f855dd6..4945557 100644 --- a/.github/workflows/build-macos.yaml +++ b/.github/workflows/build-macos.yaml @@ -1,8 +1,10 @@ # copied from Daniel Cook's Seq collection name: "Build-Macos" -on: +on: workflow_dispatch + release: + types: [created] jobs: build: @@ -12,7 +14,7 @@ jobs: matrix: os: [ macos-12 ] nimversion: - - 1.6.6 + - 2.0.10 steps: @@ -51,6 +53,7 @@ jobs: - name: Upload binary artifact + if: github.event_name == 'release' uses: actions/upload-artifact@v4 with: name: qax-macos diff --git a/README.md b/README.md index 6b3cf22..ec6c1f2 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,22 @@ Alternatively, you can install _qax_ from BioConda, if you have _conda_ installe conda install -c conda-forge -c bioconda qax ``` +### Building from source + +**Version 1.0.0+ requires Nim 2.0.0 or later.** + +If you want to build from source, you need: +- [Nim](https://nim-lang.org/) >= 2.0.0 +- [Nimble](https://github.com/nim-lang/nimble) (Nim's package manager) + +```bash +git clone https://github.com/telatin/qax +cd qax +nimble build +``` + +For versions prior to 1.0.0, Nim 1.6.6 was used. + ## :book: Usage `qax` has four subprograms (general syntax is `qax [program] [program-arguments]`): diff --git a/lib/yaml-legacy/nimblemeta.json b/lib/yaml-legacy/nimblemeta.json deleted file mode 100644 index 3cb04b5..0000000 --- a/lib/yaml-legacy/nimblemeta.json +++ /dev/null @@ -1 +0,0 @@ -{"url":"https://github.com/flyx/NimYAML","vcsRevision":"aa64bac5ed68c519ecc0e101056aa934ef476438","files":["/yaml/stream.nim","/yaml/private/internal.nim","/yaml/taglib.nim","/yaml/annotations.nim","/yaml/parser.nim","/yaml.nim","/yaml/hints.nim","/yaml/private/lex.nim","/yaml/tojson.nim","/yaml/serialization.nim","/yaml.nimble","/yaml/dom.nim","/yaml/presenter.nim"],"binaries":[],"isLink":false} \ No newline at end of file diff --git a/lib/yaml-legacy/yaml.nim b/lib/yaml-legacy/yaml.nim deleted file mode 100644 index cbd3345..0000000 --- a/lib/yaml-legacy/yaml.nim +++ /dev/null @@ -1,45 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## This is the parent module of NimYAML, a package that provides facilities to -## generate and interpret `YAML `_ character streams. Importing -## this package will import everything from all subpackages. -## -## There are three high-level APIs which are probably most useful: -## -## * The serialization API in `serialization `_ enables -## you to load YAML data directly into native Nim types, and reversely dump -## native Nim types as YAML. -## * The DOM API in `dom `_ parses YAML files in a tree structure -## which you can navigate. -## * The JSON API in `tojson `_ parses YAML files into the -## Nim stdlib's JSON structure, which may be useful if you have other modules -## which expect JSON input. Note that the serialization API is able to write -## and load JSON; you do not need the JSON API for that. -## -## Apart from those high-level APIs, NimYAML implements a low-level API which -## enables you to process YAML input as data stream which does not need to be -## loaded into RAM completely at once. It consists of the following modules: -## -## * The stream API in `stream `_ defines the central type for -## stream processing, ``YamlStream``. It also contains definitions and -## constructor procs for stream events. -## * The parser API in `parser `_ gives you direct access to -## the YAML parser's output. -## * The presenter API in `presenter `_ gives you direct -## access to the presenter, i.e. the module that renders a YAML character -## stream. -## * The taglib API in `taglib `_ provides a data structure -## for keeping track of YAML tags that are generated by the parser or used in -## the presenter. -## * The hints API in `hints `_ provides a simple proc for -## guessing the type of a scalar value. - -import yaml / [dom, hints, parser, presenter, annotations, - serialization, stream, taglib, tojson] - -export dom, hints, parser, presenter, annotations, - serialization, stream, taglib, tojson diff --git a/lib/yaml-legacy/yaml.nimble b/lib/yaml-legacy/yaml.nimble deleted file mode 100644 index 07a4b50..0000000 --- a/lib/yaml-legacy/yaml.nimble +++ /dev/null @@ -1,11 +0,0 @@ -# Package - -version = "0.14.0" -author = "Felix Krause" -description = "YAML 1.2 implementation for Nim" -license = "MIT" -skipDirs = @["bench", "doc", "server", "test", "tools"] - -# Dependencies - -requires "nim >= 1.0.0" diff --git a/lib/yaml-legacy/yaml/annotations.nim b/lib/yaml-legacy/yaml/annotations.nim deleted file mode 100644 index 490775c..0000000 --- a/lib/yaml-legacy/yaml/annotations.nim +++ /dev/null @@ -1,85 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016-2020 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ======================= -## Module yaml.annotations -## ======================= -## -## This module provides annotations for object fields that customize -## (de)serialization behavior of those fields. - -template defaultVal*(value : typed) {.pragma.} - ## This annotation can be put on an object field. During deserialization, - ## if no value for this field is given, the ``value`` parameter of this - ## annotation is used as value. - ## - ## Example usage: - ## - ## .. code-block:: - ## type MyObject = object - ## a {.defaultVal: "foo".}: string - ## c {.defaultVal: (1,2).}: tuple[x, y: int] - -template sparse*() {.pragma.} - ## This annotation can be put on an object type. During deserialization, - ## the input may omit any field that has an ``Option[T]`` type (for any - ## concrete ``T``) and that field will be treated as if it had the annotation - ## ``{.defaultVal: none(T).}``. - ## - ## Example usage: - ## - ## .. code-block:: - ## type MyObject {.sparse.} = object - ## a: Option[string] - ## b: Option[int] - -template transient*() {.pragma.} - ## This annotation can be put on an object field. Any object field - ## carrying this annotation will not be serialized to YAML and cannot be given - ## a value when deserializing. Giving a value for this field during - ## deserialization is an error. - ## - ## Example usage: - ## - ## .. code-block:: - ## type MyObject = object - ## a, b: string - ## c: int - ## markAsTransient(MyObject, a) - ## markAsTransient(MyObject, c) - -template ignore*(keys : openarray[string]) {.pragma.} - ## This annotation can be put on an object type. All keys with the given - ## names in the input YAML mapping will be ignored when deserializing a value - ## of this type. This can be used to ignore parts of the YAML structure. - ## - ## You may use it with an empty list (``{.ignore: [].}``) to ignore *all* - ## unknown keys. - ## - ## Example usage: - ## - ## .. code-block:: - ## type MyObject {.ignore: ["c"].} = object - ## a, b: string - -template implicit*() {.pragma.} - ## This annotation declares a variant object type as implicit. - ## This requires the type to consist of nothing but a case expression and each - ## branch of the case expression containing exactly one field - with the - ## exception that one branch may contain zero fields. - ## - ## Example usage: - ## - ## .. code-block:: - ## ContainerKind = enum - ## ckString, ckInt - ## - ## type MyObject {.implicit.} = object - ## case kind: ContainerKind - ## of ckString: - ## strVal: string - ## of ckInt: - ## intVal: int \ No newline at end of file diff --git a/lib/yaml-legacy/yaml/dom.nim b/lib/yaml-legacy/yaml/dom.nim deleted file mode 100644 index 07cad96..0000000 --- a/lib/yaml-legacy/yaml/dom.nim +++ /dev/null @@ -1,377 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## =============== -## Module yaml.dom -## =============== -## -## This is the DOM API, which enables you to load YAML into a tree-like -## structure. It can also dump the structure back to YAML. Formally, it -## represents the *Representation Graph* as defined in the YAML specification. -## -## The main interface of this API are ``loadDom`` and ``dumpDom``. The other -## exposed procs are low-level and useful if you want to load or generate parts -## of a ``YamlStream``. -## -## The ``YamlNode`` objects in the DOM can be used similarly to the ``JsonNode`` -## objects of Nim's `json module `_. - -import tables, streams, hashes, sets, strutils -import stream, taglib, serialization, private/internal, parser, - presenter - -when defined(nimNoNil): - {.experimental: "notnil".} -type - 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: elems*: seq[YamlNode] - of yMapping: fields*: TableRef[YamlNode, YamlNode] - # compiler does not like Table[YamlNode, YamlNode] - - YamlDocument* = object - ## Represents a YAML document. - root*: YamlNode - -proc hash*(o: YamlNode): Hash = - result = o.tag.hash - case o.kind - of yScalar: result = result !& o.content.hash - of yMapping: - for key, value in o.fields.pairs: - result = result !& key.hash !& value.hash - of ySequence: - for item in o.elems: - result = result !& item.hash - result = !$result - -proc eqImpl(x, y: YamlNode, alreadyVisited: var HashSet[pointer]): bool = - template compare(a, b: YamlNode) {.dirty.} = - if cast[pointer](a) != cast[pointer](b): - if cast[pointer](a) in alreadyVisited and - cast[pointer](b) in alreadyVisited: - # prevent infinite loop! - return false - elif a != b: return false - - if x.kind != y.kind or x.tag != y.tag: return false - alreadyVisited.incl(cast[pointer](x)) - alreadyVisited.incl(cast[pointer](y)) - case x.kind - of yScalar: result = x.content == y.content - of ySequence: - if x.elems.len != y.elems.len: return false - for i in 0.. " - case n.kind - of yScalar: result.add(escape(n.content)) - of ySequence: - result.add('[') - for item in n.elems: - result.add($item) - result.add(", ") - result.setLen(result.len - 1) - result[^1] = ']' - of yMapping: - result.add('{') - for key, value in n.fields.pairs: - result.add($key) - result.add(": ") - result.add($value) - result.add(", ") - result.setLen(result.len - 1) - result[^1] = '}' - -proc newYamlNode*(content: string, tag: string = "?"): YamlNode = - YamlNode(kind: yScalar, content: content, tag: tag) - -proc newYamlNode*(elems: openarray[YamlNode], tag: string = "?"): - YamlNode = - YamlNode(kind: ySequence, elems: @elems, tag: tag) - -proc newYamlNode*(fields: openarray[(YamlNode, YamlNode)], - tag: string = "?"): YamlNode = - YamlNode(kind: yMapping, fields: newTable(fields), tag: tag) - -proc initYamlDoc*(root: YamlNode): YamlDocument = result.root = root - -proc composeNode(s: var YamlStream, tagLib: TagLibrary, - c: ConstructionContext): - YamlNode {.raises: [YamlStreamError, YamlConstructionError].} = - template addAnchor(c: ConstructionContext, target: AnchorId) = - if target != yAnchorNone: - when defined(JS): - {.emit: [c, """.refs.set(""", target, ", ", result, ");"].} - else: - yAssert(not c.refs.hasKey(target)) - c.refs[target] = cast[pointer](result) - - var start: YamlStreamEvent - shallowCopy(start, s.next()) - new(result) - try: - case start.kind - of yamlStartMap: - result = YamlNode(tag: tagLib.uri(start.mapTag), - kind: yMapping, - fields: newTable[YamlNode, YamlNode]()) - while s.peek().kind != yamlEndMap: - let - key = composeNode(s, tagLib, c) - value = composeNode(s, tagLib, c) - if result.fields.hasKeyOrPut(key, value): - raise newException(YamlConstructionError, - "Duplicate key: " & $key) - discard s.next() - addAnchor(c, start.mapAnchor) - of yamlStartSeq: - result = YamlNode(tag: tagLib.uri(start.seqTag), - kind: ySequence, - elems: newSeq[YamlNode]()) - while s.peek().kind != yamlEndSeq: - result.elems.add(composeNode(s, tagLib, c)) - addAnchor(c, start.seqAnchor) - discard s.next() - of yamlScalar: - result = YamlNode(tag: tagLib.uri(start.scalarTag), - kind: yScalar) - shallowCopy(result.content, start.scalarContent) - addAnchor(c, start.scalarAnchor) - of yamlAlias: - when defined(JS): - {.emit: [result, " = ", c, ".refs.get(", start.aliasTarget, ");"].} - else: - result = cast[YamlNode](c.refs[start.aliasTarget]) - else: internalError("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() - var n: YamlStreamEvent - shallowCopy(n, s.next()) - yAssert n.kind == yamlStartDoc - result.root = composeNode(s, tagLib, context) - n = s.next() - yAssert n.kind == yamlEndDoc - -proc loadDom*(s: Stream | string): 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: internalError("Unexpected exception: " & e.parent.repr) - -proc serializeNode(n: YamlNode, c: SerializationContext, a: AnchorStyle, - tagLib: TagLibrary) {.raises: [].}= - var val = yAnchorNone - when defined(JS): - {.emit: [""" - if (""", a, " != ", asNone, " && ", c, ".refs.has(", n, """) { - """, val, " = ", c, ".refs.get(", n, """); - if (""", c, ".refs.get(", n, ") == ", yAnchorNone, ") {"].} - val = c.nextAnchorId - {.emit: [c, """.refs.set(""", n, """, """, val, """);"""].} - c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) - {.emit: "}".} - c.put(aliasEvent(val)) - return - {.emit: "}".} - else: - let p = cast[pointer](n) - if a != asNone and c.refs.hasKey(p): - val = c.refs.getOrDefault(p) - if val == yAnchorNone: - val = c.nextAnchorId - c.refs[p] = val - c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) - c.put(aliasEvent(val)) - return - var - tagId: TagId - anchor: AnchorId - if a == asAlways: - val = c.nextAnchorId - when defined(JS): - {.emit: [c, ".refs.set(", n, ", ", val, ");"].} - else: - c.refs[p] = c.nextAnchorId - c.nextAnchorId = AnchorId(int(val) + 1) - else: - when defined(JS): - {.emit: [c, ".refs.set(", n, ", ", yAnchorNone, ");"].} - else: - c.refs[p] = yAnchorNone - tagId = if tagLib.tags.hasKey(n.tag): tagLib.tags.getOrDefault(n.tag) else: - tagLib.registerUri(n.tag) - case a - of asNone: anchor = yAnchorNone - of asTidy: anchor = cast[AnchorId](n) - of asAlways: anchor = val - - case n.kind - of yScalar: c.put(scalarEvent(n.content, tagId, anchor)) - of ySequence: - c.put(startSeqEvent(tagId, anchor)) - for item in n.elems: - serializeNode(item, c, a, tagLib) - c.put(endSeqEvent()) - of yMapping: - c.put(startMapEvent(tagId, anchor)) - for key, value in n.fields.pairs: - serializeNode(key, c, a, tagLib) - serializeNode(value, c, a, tagLib) - c.put(endMapEvent()) - -template processAnchoredEvent(target: untyped, c: SerializationContext) = - var anchorId: AnchorId - when defined(JS): - {.emit: [anchorId, " = ", c, ".refs.get(", target, ");"].} - else: - anchorId = c.refs.getOrDefault(cast[pointer](target)) - if anchorId != yAnchorNone: target = anchorId - else: target = yAnchorNone - -proc serialize*(doc: YamlDocument, tagLib: TagLibrary, a: AnchorStyle = asTidy): - YamlStream {.raises: [].} = - var - bys = newBufferYamlStream() - c = newSerializationContext(a, proc(e: YamlStreamEvent) {.raises: [].} = - bys.put(e) - ) - c.put(startDocEvent()) - serializeNode(doc.root, c, a, tagLib) - c.put(endDocEvent()) - if a == asTidy: - for event in bys.mitems(): - case event.kind - of yamlScalar: processAnchoredEvent(event.scalarAnchor, c) - of yamlStartMap: processAnchoredEvent(event.mapAnchor, c) - of yamlStartSeq: processAnchoredEvent(event.seqAnchor, c) - else: discard - result = bys - -proc dumpDom*(doc: YamlDocument, target: Stream, - anchorStyle: AnchorStyle = asTidy, - options: PresentationOptions = defaultPresentationOptions) - {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, - YamlStreamError].} = - ## Dump a YamlDocument as YAML character stream. - var - tagLib = initExtendedTagLibrary() - events = serialize(doc, tagLib, - if options.style == psJson: asNone else: anchorStyle) - present(events, target, tagLib, options) - -proc `[]`*(node: YamlNode, i: int): YamlNode = - ## Get the node at index *i* from a sequence. *node* must be a *ySequence*. - assert node.kind == ySequence - node.elems[i] - -proc `[]=`*(node: var YamlNode, i: int, val: YamlNode) = - ## Set the node at index *i* of a sequence. *node* must be a *ySequence*. - assert node.kind == ySequence - node.elems[i] = val - -proc `[]`*(node: YamlNode, key: YamlNode): YamlNode = - ## Get the value for a key in a mapping. *node* must be a *yMapping*. - assert node.kind == yMapping - node.fields[key] - -proc `[]=`*(node: YamlNode, key: YamlNode, value: YamlNode) = - ## Set the value for a key in a mapping. *node* must be a *yMapping*. - node.fields[key] = value - -proc `[]`*(node: YamlNode, key: string): YamlNode = - ## Get the value for a string key in a mapping. *node* must be a *yMapping*. - ## This searches for a scalar key with content *key* and either no explicit - ## tag or the explicit tag ``!!str``. - assert node.kind == yMapping - var keyNode = YamlNode(kind: yScalar, tag: "!", content: key) - result = node.fields.getOrDefault(keyNode) - if isNil(result): - keyNode.tag = "?" - result = node.fields.getOrDefault(keyNode) - if isNil(result): - keyNode.tag = nimTag(yamlTagRepositoryPrefix & "str") - result = node.fields.getOrDefault(keyNode) - if isNil(result): - raise newException(KeyError, "No key " & escape(key) & " exists!") - -proc len*(node: YamlNode): int = - ## If *node* is a *yMapping*, return the number of key-value pairs. If *node* - ## is a *ySequence*, return the number of elements. Else, return ``0`` - case node.kind - of yMapping: result = node.fields.len - of ySequence: result = node.elems.len - of yScalar: result = 0 - -iterator items*(node: YamlNode): YamlNode = - ## Iterates over all items of a sequence. *node* must be a *ySequence*. - assert node.kind == ySequence - for item in node.elems: yield item - -iterator mitems*(node: var YamlNode): YamlNode = - ## Iterates over all items of a sequence. *node* must be a *ySequence*. - ## Values can be modified. - assert node.kind == ySequence - for item in node.elems.mitems: yield item - -iterator pairs*(node: YamlNode): tuple[key, value: YamlNode] = - ## Iterates over all key-value pairs of a mapping. *node* must be a - ## *yMapping*. - assert node.kind == yMapping - for key, value in node.fields: yield (key, value) - -iterator mpairs*(node: var YamlNode): - tuple[key: YamlNode, value: var YamlNode] = - ## Iterates over all key-value pairs of a mapping. *node* must be a - ## *yMapping*. Values can be modified. - doAssert node.kind == yMapping - for key, value in node.fields.mpairs: yield (key, value) \ No newline at end of file diff --git a/lib/yaml-legacy/yaml/hints.nim b/lib/yaml-legacy/yaml/hints.nim deleted file mode 100644 index 296e556..0000000 --- a/lib/yaml-legacy/yaml/hints.nim +++ /dev/null @@ -1,279 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================= -## Module yaml.hints -## ================= -## -## The hints API enables you to guess the type of YAML scalars. - -import macros -import private/internal - -type - TypeHint* = enum - ## A type hint can be computed from scalar content and tells you what - ## NimYAML thinks the scalar's type is. It is generated by - ## `guessType <#guessType,string>`_ The first matching RegEx - ## in the following table will be the type hint of a scalar string. - ## - ## You can use it to determine the type of YAML scalars that have a '?' - ## non-specific tag, but using this feature is completely optional. - ## - ## ================== ========================= - ## Name RegEx - ## ================== ========================= - ## ``yTypeInteger`` ``0 | -? [1-9] [0-9]*`` - ## ``yTypeFloat`` ``-? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )?`` - ## ``yTypeFloatInf`` ``-? \. (inf | Inf | INF)`` - ## ``yTypeFloatNaN`` ``-? \. (nan | NaN | NAN)`` - ## ``yTypeBoolTrue`` ``y|Y|yes|Yes|YES|true|True|TRUE|on|On|ON`` - ## ``yTypeBoolFalse`` ``n|N|no|No|NO|false|False|FALSE|off|Off|OFF`` - ## ``yTypeNull`` ``~ | null | Null | NULL`` - ## ``yTypeTimestamp`` see `here `_. - ## ``yTypeUnknown`` ``*`` - ## ================== ========================= - yTypeInteger, yTypeFloat, yTypeFloatInf, yTypeFloatNaN, yTypeBoolTrue, - yTypeBoolFalse, yTypeNull, yTypeUnknown, yTypeTimestamp - - YamlTypeHintState = enum - ythInitial, - ythF, ythFA, ythFAL, ythFALS, ythFALSE, - ythN, ythNU, ythNUL, ythNULL, - ythNO, - ythO, ythON, - ythOF, ythOFF, - ythT, ythTR, ythTRU, ythTRUE, - ythY, ythYE, ythYES, - - ythPoint, ythPointI, ythPointIN, ythPointINF, - ythPointN, ythPointNA, ythPointNAN, - - ythLowerFA, ythLowerFAL, ythLowerFALS, - ythLowerNU, ythLowerNUL, - ythLowerOF, - ythLowerTR, ythLowerTRU, - ythLowerYE, - - ythPointLowerIN, ythPointLowerN, ythPointLowerNA, - - ythMinus, yth0, ythInt1, ythInt1Zero, ythInt2, ythInt2Zero, ythInt3, - ythInt3Zero, ythInt4, ythInt4Zero, ythInt, - ythDecimal, ythNumE, ythNumEPlusMinus, ythExponent, - - ythYearMinus, ythMonth1, ythMonth2, ythMonthMinus, ythMonthMinusNoYmd, - ythDay1, ythDay1NoYmd, ythDay2, ythDay2NoYmd, - ythAfterDayT, ythAfterDaySpace, ythHour1, ythHour2, ythHourColon, - ythMinute1, ythMinute2, ythMinuteColon, ythSecond1, ythSecond2, ythFraction, - ythAfterTimeSpace, ythAfterTimeZ, ythAfterTimePlusMinus, ythTzHour1, - ythTzHour2, ythTzHourColon, ythTzMinute1, ythTzMinute2 - -macro typeHintStateMachine(c: untyped, content: varargs[untyped]) = - yAssert content.kind == nnkArgList - result = newNimNode(nnkCaseStmt, content).add(copyNimNode(c)) - for branch in content.children: - yAssert branch.kind == nnkOfBranch - var - charBranch = newNimNode(nnkOfBranch, branch) - i = 0 - stateBranches = newNimNode(nnkCaseStmt, branch).add( - newIdentNode("typeHintState")) - while branch[i].kind != nnkStmtList: - charBranch.add(copyNimTree(branch[i])) - inc(i) - for rule in branch[i].children: - yAssert rule.kind == nnkInfix - yAssert rule[0].strVal == "=>" - var stateBranch = newNimNode(nnkOfBranch, rule) - case rule[1].kind - of nnkBracket: - for item in rule[1].children: stateBranch.add(item) - of nnkIdent: stateBranch.add(rule[1]) - else: internalError("Invalid rule kind: " & $rule[1].kind) - if rule[2].kind == nnkNilLit: - stateBranch.add(newStmtList(newNimNode(nnkDiscardStmt).add( - newEmptyNode()))) - else: - stateBranch.add(newStmtList(newAssignment( - newIdentNode("typeHintState"), copyNimTree(rule[2])))) - stateBranches.add(stateBranch) - stateBranches.add(newNimNode(nnkElse).add(newStmtList( - newNimNode(nnkReturnStmt).add(newIdentNode("yTypeUnknown"))))) - charBranch.add(newStmtList(stateBranches)) - result.add(charBranch) - result.add(newNimNode(nnkElse).add(newStmtList( - newNimNode(nnkReturnStmt).add(newIdentNode("yTypeUnknown"))))) - -template advanceTypeHint(ch: char) {.dirty.} = - typeHintStateMachine ch: - of '~': ythInitial => ythNULL - of '.': - [yth0, ythInt1Zero, ythInt1, ythInt2, ythInt3, ythInt4, ythInt] => ythDecimal - [ythInitial, ythMinus] => ythPoint - ythSecond2 => ythFraction - of '+': - ythNumE => ythNumEPlusMinus - [ythFraction, ythSecond2] => ythAfterTimePlusMinus - of '-': - ythInitial => ythMinus - ythNumE => ythNumEPlusMinus - [ythInt4, ythInt4Zero] => ythYearMinus - ythMonth1 => ythMonthMinusNoYmd - ythMonth2 => ythMonthMinus - [ythFraction, ythSecond2] => ythAfterTimePlusMinus - of '_': - [ythInt1, ythInt2, ythInt3, ythInt4] => ythInt - [ythInt, ythDecimal] => nil - of ':': - [ythHour1, ythHour2] => ythHourColon - ythMinute2 => ythMinuteColon - [ythTzHour1, ythTzHour2] => ythTzHourColon - of '0': - ythInitial => ythInt1Zero - ythMinus => yth0 - [ythNumE, ythNumEPlusMinus] => ythExponent - ythInt1 => ythInt2 - ythInt1Zero => ythInt2Zero - ythInt2 => ythInt3 - ythInt2Zero => ythInt3Zero - ythInt3 => ythInt4 - ythInt3Zero => ythInt4Zero - ythInt4 => ythInt - ythYearMinus => ythMonth1 - ythMonth1 => ythMonth2 - ythMonthMinus => ythDay1 - ythMonthMinusNoYmd => ythDay1NoYmd - ythDay1 => ythDay2 - ythDay1NoYmd => ythDay2NoYmd - [ythAfterDaySpace, ythAfterDayT] => ythHour1 - ythHour1 => ythHour2 - ythHourColon => ythMinute1 - ythMinute1 => ythMinute2 - ythMinuteColon => ythSecond1 - ythSecond1 => ythSecond2 - ythAfterTimePlusMinus => ythTzHour1 - ythTzHour1 => ythTzHour2 - ythTzHourColon => ythTzMinute1 - ythTzMinute1 => ythTzMinute2 - [ythInt, ythDecimal, ythExponent, ythFraction] => nil - of '1'..'9': - ythInitial => ythInt1 - ythInt1 => ythInt2 - ythInt1Zero => ythInt2Zero - ythInt2 => ythInt3 - ythInt2Zero => ythInt3Zero - ythInt3 => ythInt4 - ythInt3Zero => ythInt4Zero - [ythInt4, ythMinus] => ythInt - [ythNumE, ythNumEPlusMinus] => ythExponent - ythYearMinus => ythMonth1 - ythMonth1 => ythMonth2 - ythMonthMinus => ythDay1 - ythMonthMinusNoYmd => ythDay1NoYmd - ythDay1 => ythDay2 - ythDay1NoYmd => ythDay2NoYmd - [ythAfterDaySpace, ythAfterDayT] => ythHour1 - ythHour1 => ythHour2 - ythHourColon => ythMinute1 - ythMinute1 => ythMinute2 - ythMinuteColon => ythSecond1 - ythSecond1 => ythSecond2 - ythAfterTimePlusMinus => ythTzHour1 - ythTzHour1 => ythTzHour2 - ythTzHourColon => ythTzMinute1 - ythTzMinute1 => ythTzMinute2 - [ythInt, ythDecimal, ythExponent, ythFraction] => nil - of 'a': - ythF => ythLowerFA - ythPointN => ythPointNA - ythPointLowerN => ythPointLowerNA - of 'A': - ythF => ythFA - ythPointN => ythPointNA - of 'e': - [yth0, ythInt, ythDecimal] => ythNumE - ythLowerFALS => ythFALSE - ythLowerTRU => ythTRUE - ythY => ythLowerYE - of 'E': - [yth0, ythInt, ythDecimal] => ythNumE - ythFALS => ythFALSE - ythTRU => ythTRUE - ythY => ythYE - of 'f': - ythInitial => ythF - ythO => ythLowerOF - ythLowerOF => ythOFF - ythPointLowerIN => ythPointINF - of 'F': - ythInitial => ythF - ythO => ythOF - ythOF => ythOFF - ythPointIN => ythPointINF - of 'i', 'I': ythPoint => ythPointI - of 'l': - ythLowerNU => ythLowerNUL - ythLowerNUL => ythNULL - ythLowerFA => ythLowerFAL - of 'L': - ythNU => ythNUL - ythNUL => ythNULL - ythFA => ythFAL - of 'n': - ythInitial => ythN - ythO => ythON - ythPoint => ythPointLowerN - ythPointI => ythPointLowerIN - ythPointLowerNA => ythPointNAN - of 'N': - ythInitial => ythN - ythO => ythON - ythPoint => ythPointN - ythPointI => ythPointIN - ythPointNA => ythPointNAN - of 'o', 'O': - ythInitial => ythO - ythN => ythNO - of 'r': ythT => ythLowerTR - of 'R': ythT => ythTR - of 's': - ythLowerFAL => ythLowerFALS - ythLowerYE => ythYES - of 'S': - ythFAL => ythFALS - ythYE => ythYES - of 't', 'T': - ythInitial => ythT - [ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDayT - of 'u': - ythN => ythLowerNU - ythLowerTR => ythLowerTRU - of 'U': - ythN => ythNU - ythTR => ythTRU - of 'y', 'Y': ythInitial => ythY - of 'Z': [ythSecond2, ythFraction, ythAfterTimeSpace] => ythAfterTimeZ - of ' ', '\t': - [ythSecond2, ythFraction] => ythAfterTimeSpace - [ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDaySpace - [ythAfterTimeSpace, ythAfterDaySpace] => nil - -proc guessType*(scalar: string): TypeHint {.raises: [].} = - ## Parse scalar string according to the RegEx table documented at - ## `TypeHint <#TypeHind>`_. - var typeHintState: YamlTypeHintState = ythInitial - for c in scalar: advanceTypeHint(c) - case typeHintState - of ythNULL, ythInitial: result = yTypeNull - of ythTRUE, ythON, ythYES, ythY: result = yTypeBoolTrue - of ythFALSE, ythOFF, ythNO, ythN: result = yTypeBoolFalse - of ythInt1, ythInt2, ythInt3, ythInt4, ythInt, yth0, ythInt1Zero: result = yTypeInteger - of ythDecimal, ythExponent: result = yTypeFloat - of ythPointINF: result = yTypeFloatInf - of ythPointNAN: result = yTypeFloatNaN - of ythDay2, ythSecond2, ythFraction, ythAfterTimeZ, ythTzHour1, ythTzHour2, - ythTzMinute1, ythTzMinute2: result = yTypeTimestamp - else: result = yTypeUnknown diff --git a/lib/yaml-legacy/yaml/parser.nim b/lib/yaml-legacy/yaml/parser.nim deleted file mode 100644 index 947a407..0000000 --- a/lib/yaml-legacy/yaml/parser.nim +++ /dev/null @@ -1,1161 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================== -## Module yaml.parser -## ================== -## -## This is the low-level parser API. A ``YamlParser`` enables you to parse any -## non-nil string or Stream object as YAML character stream. - -import tables, strutils, macros, streams -import taglib, stream, private/lex, private/internal - -when defined(nimNoNil): - {.experimental: "notnil".} - -type - WarningCallback* = proc(line, column: int, lineContent: string, - message: string) - ## Callback for parser warnings. Currently, this callback may be called - ## on two occasions while parsing a YAML document stream: - ## - ## - If the version number in the ``%YAML`` directive does not match - ## ``1.2``. - ## - If there is an unknown directive encountered. - - YamlParser* = ref object - ## 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). - tagLib: TagLibrary - callback: WarningCallback - anchors: Table[string, AnchorId] - - FastParseLevelKind = enum - fplUnknown, fplSequence, fplMapKey, fplMapValue, fplSinglePairKey, - fplSinglePairValue, fplDocument - - FastParseLevel = object - kind: FastParseLevelKind - indentation: int - - ParserContext = ref object of YamlStream - p: YamlParser - lex: YamlLexer - storedState: proc(s: YamlStream, e: var YamlStreamEvent): bool - atSequenceItem: bool - flowdepth: int - ancestry: seq[FastParseLevel] - level: FastParseLevel - tag: TagId - anchor: AnchorId - shorthands: Table[string, string] - nextAnchorId: AnchorId - newlines: int - explicitFlowKey: bool - plainScalarStart: tuple[line, column: int] - - LevelEndResult = enum - lerNothing, lerOne, lerAdditionalMapEnd - - YamlLoadingError* = object of Exception - ## Base class for all exceptions that may be raised during the process - ## of loading a YAML character stream. - line*: int ## line number (1-based) where the error was encountered - column*: int ## column number (1-based) where the error was encountered - 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. - -proc newYamlParser*(tagLib: TagLibrary = initExtendedTagLibrary(), - callback: WarningCallback = nil): YamlParser = - ## Creates a YAML parser. if ``callback`` is not ``nil``, it will be called - ## whenever the parser yields a warning. - new(result) - result.tagLib = tagLib - result.callback = callback - -template debug(message: string) {.dirty.} = - when defined(yamlDebug): - try: styledWriteLine(stdout, fgBlue, message) - except IOError: discard - -proc generateError(c: ParserContext, message: string): - ref YamlParserError {.raises: [].} = - result = newException(YamlParserError, message) - (result.line, result.column) = c.lex.curStartPos - result.lineContent = c.lex.getTokenLine() - -proc illegalToken(c: ParserContext, expected: string = ""): - ref YamlParserError {.raises: [].} = - var msg = "Illegal token" - if expected.len > 0: msg.add(" (expected " & expected & ")") - msg.add(": " & $c.lex.cur) - result = c.generateError(msg) - -proc callCallback(c: ParserContext, msg: string) {.raises: [YamlParserError].} = - try: - if not isNil(c.p.callback): - c.p.callback(c.lex.curStartPos.line, c.lex.curStartPos.column, - c.lex.getTokenLine(), msg) - except: - var e = newException(YamlParserError, - "Warning callback raised exception: " & getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -proc initLevel(k: FastParseLevelKind): FastParseLevel {.raises: [], inline.} = - FastParseLevel(kind: k, indentation: UnknownIndentation) - -proc emptyScalar(c: ParserContext): YamlStreamEvent {.raises: [], inline.} = - when defined(yamlScalarRepInd): - result = scalarEvent("", c.tag, c.anchor, srPlain) - else: - result = scalarEvent("", c.tag, c.anchor) - c.tag = yTagQuestionMark - c.anchor = yAnchorNone - -proc currentScalar(c: ParserContext, e: var YamlStreamEvent) - {.raises: [], inline.} = - e = YamlStreamEvent(kind: yamlScalar, scalarTag: c.tag, - scalarAnchor: c.anchor) - shallowCopy(e.scalarContent, c.lex.buf) - c.lex.buf = newStringOfCap(256) - c.tag = yTagQuestionMark - c.anchor = yAnchorNone - -proc objectStart(c: ParserContext, k: static[YamlStreamEventKind], - single: bool = false): YamlStreamEvent {.raises: [].} = - yAssert(c.level.kind == fplUnknown) - when k == yamlStartMap: - result = startMapEvent(c.tag, c.anchor) - if single: - debug("started single-pair map at " & - (if c.level.indentation == UnknownIndentation: - $c.lex.indentation else: $c.level.indentation)) - c.level.kind = fplSinglePairKey - else: - debug("started map at " & - (if c.level.indentation == UnknownIndentation: - $c.lex.indentation else: $c.level.indentation)) - c.level.kind = fplMapKey - else: - result = startSeqEvent(c.tag, c.anchor) - debug("started sequence at " & - (if c.level.indentation == UnknownIndentation: $c.lex.indentation else: - $c.level.indentation)) - c.level.kind = fplSequence - c.tag = yTagQuestionMark - c.anchor = yAnchorNone - if c.level.indentation == UnknownIndentation: - c.level.indentation = c.lex.indentation - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - -proc initDocValues(c: ParserContext) {.raises: [].} = - c.shorthands = initTable[string, string]() - c.p.anchors = initTable[string, AnchorId]() - c.shorthands["!"] = "!" - c.shorthands["!!"] = "tag:yaml.org,2002:" - c.nextAnchorId = 0.AnchorId - c.level = initLevel(fplUnknown) - c.tag = yTagQuestionMark - c.anchor = yAnchorNone - c.ancestry.add(FastParseLevel(kind: fplDocument, indentation: -1)) - -proc advance(c: ParserContext) {.inline, raises: [YamlParserError].} = - try: c.lex.next() - except YamlLexerError: - let e = (ref YamlLexerError)(getCurrentException()) - let pe = newException(YamlParserError, e.msg) - pe.line = e.line - pe.column = e.column - pe.lineContent = e.lineContent - raise pe - -proc handleAnchor(c: ParserContext) {.raises: [YamlParserError].} = - if c.level.kind != fplUnknown: raise c.generateError("Unexpected token") - if c.anchor != yAnchorNone: - raise c.generateError("Only one anchor is allowed per node") - c.anchor = c.nextAnchorId - c.p.anchors[c.lex.buf] = c.anchor - c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) - c.lex.buf.setLen(0) - c.advance() - -proc handleTagHandle(c: ParserContext) {.raises: [YamlParserError].} = - if c.level.kind != fplUnknown: raise c.generateError("Unexpected tag handle") - if c.tag != yTagQuestionMark: - raise c.generateError("Only one tag handle is allowed per node") - if c.lex.cur == ltTagHandle: - var tagUri = "" - try: - tagUri.add(c.shorthands[c.lex.buf[0..c.lex.shorthandEnd]]) - tagUri.add(c.lex.buf[c.lex.shorthandEnd + 1 .. ^1]) - except KeyError: - raise c.generateError( - "Undefined tag shorthand: " & c.lex.buf[0..c.lex.shorthandEnd]) - try: c.tag = c.p.tagLib.tags[tagUri] - except KeyError: c.tag = c.p.tagLib.registerUri(tagUri) - else: - try: c.tag = c.p.tagLib.tags[c.lex.buf] - except KeyError: c.tag = c.p.tagLib.registerUri(c.lex.buf) - c.lex.buf.setLen(0) - c.advance() - -proc handlePossibleMapStart(c: ParserContext, e: var YamlStreamEvent, - flow: bool = false, single: bool = false): bool = - result = false - if c.level.indentation == UnknownIndentation: - if c.lex.isImplicitKeyStart(): - e = c.objectStart(yamlStartMap, single) - result = true - c.level.indentation = c.lex.indentation - -template implicitScalar(): YamlStreamEvent = - when defined(yamlScalarRepInd): - scalarEvent("", yTagQuestionMark, yAnchorNone, srPlain) - else: - scalarEvent("", yTagQuestionMark, yAnchorNone) - -proc handleMapKeyIndicator(c: ParserContext, e: var YamlStreamEvent): bool = - result = false - case c.level.kind - of fplUnknown: - e = c.objectStart(yamlStartMap) - result = true - of fplMapValue: - if c.level.indentation != c.lex.indentation: - raise c.generateError("Invalid p.indentation of map key indicator " & - "(expected" & $c.level.indentation & ", got " & $c.lex.indentation & - ")") - e = implicitScalar() - result = true - c.level.kind = fplMapKey - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - of fplMapKey: - if c.level.indentation != c.lex.indentation: - raise c.generateError("Invalid p.indentation of map key indicator") - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - of fplSequence: - raise c.generateError("Unexpected map key indicator (expected '- ')") - of fplSinglePairKey, fplSinglePairValue, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - c.advance() - if c.lex.cur != ltIndentation: - # this enables the parser to properly parse compact structures, like - # ? - a - # - b - # and such. At the first `-`, the indentation must equal its level to be - # parsed properly. - c.lex.indentation = c.lex.curStartPos.column - 1 - -proc handleBlockSequenceIndicator(c: ParserContext, e: var YamlStreamEvent): - bool = - result = false - case c.level.kind - of fplUnknown: - e = c.objectStart(yamlStartSeq) - result = true - of fplSequence: - if c.level.indentation != c.lex.indentation: - raise c.generateError( - "Invalid p.indentation of block sequence indicator (expected " & - $c.level.indentation & ", got " & $c.lex.indentation & ")") - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - else: raise c.generateError("Illegal sequence item in map") - c.advance() - if c.lex.cur != ltIndentation: - # see comment in previous proc, this time with structures like - # - - a - # - b - c.lex.indentation = c.lex.curStartPos.column - 1 - -proc handleBlockItemStart(c: ParserContext, e: var YamlStreamEvent): bool = - result = false - case c.level.kind - of fplUnknown: - result = c.handlePossibleMapStart(e) - of fplSequence: - raise c.generateError( - "Unexpected token (expected block sequence indicator)") - of fplMapKey: - c.ancestry.add(c.level) - c.level = FastParseLevel(kind: fplUnknown, indentation: c.lex.indentation) - of fplMapValue: - e = emptyScalar(c) - result = true - c.level.kind = fplMapKey - c.ancestry.add(c.level) - c.level = FastParseLevel(kind: fplUnknown, indentation: c.lex.indentation) - of fplSinglePairKey, fplSinglePairValue, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - -proc handleFlowItemStart(c: ParserContext, e: var YamlStreamEvent): bool = - if c.level.kind == fplUnknown and - c.ancestry[c.ancestry.high].kind == fplSequence: - result = c.handlePossibleMapStart(e, true, true) - else: result = false - -proc handleFlowPlainScalar(c: ParserContext) = - while c.lex.cur in {ltScalarPart, ltEmptyLine}: - c.lex.newlines.inc() - c.advance() - c.lex.newlines = 0 - -proc lastTokenContext(s: YamlStream, line, column: var int, - lineContent: var string): bool = - let c = ParserContext(s) - line = c.lex.curStartPos.line - column = c.lex.curStartPos.column - lineContent = c.lex.getTokenLine(true) - result = true - -# --- macros for defining parser states --- - -template capitalize(s: string): string = - when declared(strutils.capitalizeAscii): strutils.capitalizeAscii(s) - else: strutils.capitalize(s) - -macro parserStates(names: varargs[untyped]) = - ## generates proc declaration for each state in list like this: - ## - ## proc name(s: YamlStream, e: var YamlStreamEvent): - ## bool {.raises: [YamlParserError].} - result = newStmtList() - for name in names: - let nameId = newIdentNode("state" & capitalize(name.strVal)) - result.add(newProc(nameId, [ident("bool"), newIdentDefs(ident("s"), - ident("YamlStream")), newIdentDefs(ident("e"), newNimNode(nnkVarTy).add( - ident("YamlStreamEvent")))], newEmptyNode())) - result[0][4] = newNimNode(nnkPragma).add(newNimNode(nnkExprColonExpr).add( - ident("raises"), newNimNode(nnkBracket).add(ident("YamlParserError"), - ident("YamlLexerError")))) - -proc processStateAsgns(source, target: NimNode) {.compileTime.} = - ## copies children of source to target and replaces all assignments - ## `state = [name]` with the appropriate code for changing states. - for child in source.children: - if child.kind == nnkAsgn and child[0].kind == nnkIdent: - if child[0].strVal == "state": - assert child[1].kind == nnkIdent - var newNameId: NimNode - if child[1].kind == nnkIdent and child[1].strVal == "stored": - newNameId = newDotExpr(ident("c"), ident("storedState")) - else: - newNameId = - newIdentNode("state" & capitalize(child[1].strVal)) - target.add(newAssignment(newDotExpr( - newIdentNode("s"), newIdentNode("nextImpl")), newNameId)) - continue - elif child[0].strVal == "stored": - assert child[1].kind == nnkIdent - let newNameId = - newIdentNode("state" & capitalize(child[1].strVal)) - target.add(newAssignment(newDotExpr(newIdentNode("c"), - newIdentNode("storedState")), newNameId)) - continue - var processed = copyNimNode(child) - processStateAsgns(child, processed) - target.add(processed) - -macro parserState(name: untyped, impl: untyped) = - ## Creates a parser state. Every parser state is a proc with the signature - ## - ## proc(s: YamlStream, e: var YamlStreamEvent): - ## bool {.raises: [YamlParserError].} - ## - ## The proc name will be prefixed with "state" and the original name will be - ## capitalized, so a state "foo" will yield a proc named "stateFoo". - ## - ## Inside the proc, you have access to the ParserContext with the let variable - ## `c`. You can change the parser state by a assignment `state = [newState]`. - ## The [newState] must have been declared with states(...) previously. - let - nameStr = name.strVal - nameId = newIdentNode("state" & capitalize(nameStr)) - var procImpl = quote do: - debug("state: " & `nameStr`) - if procImpl.kind == nnkStmtList and procImpl.len == 1: procImpl = procImpl[0] - procImpl = newStmtList(procImpl) - procImpl.add(newLetStmt(ident("c"), newCall("ParserContext", ident("s")))) - procImpl.add(newAssignment(newIdentNode("result"), newLit(false))) - assert impl.kind == nnkStmtList - processStateAsgns(impl, procImpl) - result = newProc(nameId, [ident("bool"), - newIdentDefs(ident("s"), ident("YamlStream")), newIdentDefs(ident("e"), - newNimNode(nnkVarTy).add(ident("YamlStreamEvent")))], procImpl) - -# --- parser states --- - -parserStates(initial, blockLineStart, blockObjectStart, blockAfterObject, - scalarEnd, plainScalarEnd, objectEnd, expectDocEnd, startDoc, - afterDocument, closeMoreIndentedLevels, afterPlainScalarYield, - emitEmptyScalar, tagHandle, anchor, alias, flow, leaveFlowMap, - leaveFlowSeq, flowAfterObject, leaveFlowSinglePairMap) - -proc closeEverything(c: ParserContext) = - c.lex.indentation = -1 - c.nextImpl = stateCloseMoreIndentedLevels - -proc endLevel(c: ParserContext, e: var YamlStreamEvent): - LevelEndResult = - result = lerOne - case c.level.kind - of fplSequence: e = endSeqEvent() - of fplMapKey: e = endMapEvent() - of fplMapValue, fplSinglePairValue: - e = emptyScalar(c) - c.level.kind = fplMapKey - result = lerAdditionalMapEnd - of fplUnknown: e = emptyScalar(c) - of fplDocument: - when defined(yamlScalarRepInd): - e = endDocEvent(c.lex.cur == ltDocumentEnd) - else: e = endDocEvent() - if c.lex.cur == ltDocumentEnd: c.advance() - of fplSinglePairKey: - internalError("Unexpected level kind: " & $c.level.kind) - -proc handleMapValueIndicator(c: ParserContext, e: var YamlStreamEvent): bool = - result = false - case c.level.kind - of fplUnknown: - if c.level.indentation == UnknownIndentation: - e = c.objectStart(yamlStartMap) - result = true - c.storedState = c.nextImpl - c.nextImpl = stateEmitEmptyScalar - else: - e = emptyScalar(c) - result = true - c.ancestry[c.ancestry.high].kind = fplMapValue - of fplMapKey: - if c.level.indentation != c.lex.indentation: - raise c.generateError("Invalid p.indentation of map key indicator") - e = implicitScalar() - result = true - c.level.kind = fplMapValue - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - of fplMapValue: - if c.level.indentation != c.lex.indentation: - raise c.generateError("Invalid p.indentation of map key indicator") - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - of fplSequence: - raise c.generateError("Unexpected map value indicator (expected '- ')") - of fplSinglePairKey, fplSinglePairValue, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - c.advance() - if c.lex.cur != ltIndentation: - # see comment in handleMapKeyIndicator, this time with structures like - # a: - a - # - b - c.lex.indentation = c.lex.curStartPos.column - 1 - -template handleObjectEnd(c: ParserContext, mayHaveEmptyValue: bool = false): - bool = - var result = false - c.level = c.ancestry.pop() - when mayHaveEmptyValue: - if c.level.kind == fplSinglePairValue: - result = true - c.level = c.ancestry.pop() - case c.level.kind - of fplMapKey: c.level.kind = fplMapValue - of fplSinglePairKey: c.level.kind = fplSinglePairValue - of fplMapValue: c.level.kind = fplMapKey - of fplSequence, fplDocument: discard - of fplUnknown, fplSinglePairValue: - internalError("Unexpected level kind: " & $c.level.kind) - result - -proc leaveFlowLevel(c: ParserContext, e: var YamlStreamEvent): bool = - c.flowdepth.dec() - result = (c.endLevel(e) == lerOne) # lerAdditionalMapEnd cannot happen - if c.flowdepth == 0: - c.lex.setFlow(false) - c.storedState = stateBlockAfterObject - else: - c.storedState = stateFlowAfterObject - c.nextImpl = stateObjectEnd - c.advance() - -parserState initial: - case c.lex.cur - of ltYamlDirective: - c.advance() - assert c.lex.cur == ltYamlVersion, $c.lex.cur - if c.lex.buf != "1.2": - c.callCallback("Version is not 1.2, but " & c.lex.buf) - c.lex.buf.setLen(0) - c.advance() - of ltTagDirective: - c.advance() - assert c.lex.cur == ltTagShorthand - var tagShorthand: string - shallowCopy(tagShorthand, c.lex.buf) - c.lex.buf = "" - c.advance() - assert c.lex.cur == ltTagUri - c.shorthands[tagShorthand] = c.lex.buf - c.lex.buf.setLen(0) - c.advance() - of ltUnknownDirective: - c.callCallback("Unknown directive: " & c.lex.buf) - c.lex.buf.setLen(0) - c.advance() - if c.lex.cur == ltUnknownDirectiveParams: - c.lex.buf.setLen(0) - c.advance() - of ltIndentation: - e = startDocEvent() - result = true - state = blockObjectStart - of ltStreamEnd: c.isFinished = true - of ltDirectivesEnd: - when defined(yamlScalarRepInd): e = startDocEvent(true) - else: e = startDocEvent() - result = true - c.advance() - state = blockObjectStart - of ltDocumentEnd: - c.advance() - state = afterDocument - else: internalError("Unexpected lexer token: " & $c.lex.cur) - -parserState blockLineStart: - case c.lex.cur - of ltIndentation: c.advance() - of ltEmptyLine: c.advance() - of ltStreamEnd: - c.closeEverything() - stored = afterDocument - else: - if c.lex.indentation <= c.ancestry[^1].indentation: - state = closeMoreIndentedLevels - stored = blockObjectStart - else: - state = blockObjectStart - -parserState blockObjectStart: - case c.lex.cur - of ltEmptyLine: c.advance() - of ltIndentation: - c.advance() - c.level.indentation = UnknownIndentation - state = blockLineStart - of ltDirectivesEnd: - c.closeEverything() - stored = startDoc - of ltDocumentEnd: - c.closeEverything() - stored = afterDocument - of ltMapKeyInd: - result = c.handleMapKeyIndicator(e) - of ltMapValInd: - result = c.handleMapValueIndicator(e) - of ltQuotedScalar: - result = c.handleBlockItemStart(e) - c.advance() - state = scalarEnd - of ltBlockScalarHeader: - c.lex.indentation = c.ancestry[^1].indentation - c.advance() - assert c.lex.cur in {ltBlockScalar, ltStreamEnd} - if c.level.indentation == UnknownIndentation: - c.level.indentation = c.lex.indentation - c.advance() - state = scalarEnd - of ltScalarPart: - let needsValueIndicator = c.level.kind == fplMapKey - result = c.handleBlockItemStart(e) - c.plainScalarStart = c.lex.curStartPos - while true: - c.advance() - case c.lex.cur - of ltIndentation: - if c.lex.indentation <= c.ancestry[^1].indentation: - if needsValueIndicator and - c.lex.indentation == c.ancestry[^1].indentation: - raise c.generateError("Illegal multiline implicit key") - break - c.lex.newlines.inc() - of ltScalarPart: discard - of ltEmptyLine: c.lex.newlines.inc() - else: break - if needsValueIndicator and c.lex.cur != ltMapValInd: - raise c.generateError("Missing mapping value indicator (`:`)") - c.lex.newlines = 0 - state = plainScalarEnd - stored = blockAfterObject - of ltSeqItemInd: - result = c.handleBlockSequenceIndicator(e) - of ltTagHandle, ltLiteralTag: - result = c.handleBlockItemStart(e) - state = tagHandle - stored = blockObjectStart - of ltAnchor: - result = c.handleBlockItemStart(e) - state = anchor - stored = blockObjectStart - of ltAlias: - result = c.handleBlockItemStart(e) - state = alias - stored = blockAfterObject - of ltBraceOpen, ltBracketOpen: - result = c.handleBlockItemStart(e) - c.lex.setFlow(true) - state = flow - of ltStreamEnd: - c.closeEverything() - stored = afterDocument - else: - raise c.generateError("Unexpected token: " & $c.lex.cur) - -parserState scalarEnd: - if c.tag == yTagQuestionMark: c.tag = yTagExclamationMark - c.currentScalar(e) - when defined(yamlScalarRepInd): - case c.lex.scalarKind - of skSingleQuoted: e.scalarRep = srSingleQuoted - of skDoubleQuoted: e.scalarRep = srDoubleQuoted - of skLiteral: e.scalarRep = srLiteral - of skFolded: e.scalarRep = srFolded - result = true - state = objectEnd - stored = blockAfterObject - -parserState plainScalarEnd: - c.currentScalar(e) - result = true - c.lastTokenContextImpl = proc(s: YamlStream, line, column: var int, - lineContent: var string): bool {.raises: [].} = - let c = ParserContext(s) - (line, column) = c.plainScalarStart - lineContent = c.lex.getTokenLine(c.plainScalarStart, true) - result = true - state = afterPlainScalarYield - stored = blockAfterObject - -parserState afterPlainScalarYield: - c.lastTokenContextImpl = lastTokenContext - state = objectEnd - -parserState blockAfterObject: - case c.lex.cur - of ltIndentation, ltEmptyLine: - c.advance() - state = blockLineStart - of ltMapValInd: - case c.level.kind - of fplUnknown: - e = c.objectStart(yamlStartMap) - result = true - of fplMapKey: - e = implicitScalar() - result = true - c.level.kind = fplMapValue - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - of fplMapValue: - c.level.kind = fplMapValue - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - of fplSequence: raise c.illegalToken("sequence item") - of fplSinglePairKey, fplSinglePairValue, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - c.advance() - state = blockObjectStart - of ltDirectivesEnd: - c.closeEverything() - stored = startDoc - of ltStreamEnd: - c.closeEverything() - stored = afterDocument - else: raise c.illegalToken("':', comment or line end") - -parserState objectEnd: - if c.handleObjectEnd(true): - e = endMapEvent() - result = true - if c.level.kind == fplDocument: state = expectDocEnd - else: state = stored - -parserState expectDocEnd: - case c.lex.cur - of ltIndentation, ltEmptyLine: c.advance() - of ltDirectivesEnd: - e = endDocEvent() - result = true - state = startDoc - c.ancestry.setLen(0) - of ltDocumentEnd: - when defined(yamlScalarRepInd): e = endDocEvent(true) - else: e = endDocEvent() - result = true - state = afterDocument - c.advance() - of ltStreamEnd: - e = endDocEvent() - result = true - c.isFinished = true - else: - raise c.generateError("Unexpected token (expected document end): " & - $c.lex.cur) - -parserState startDoc: - c.initDocValues() - when defined(yamlScalarRepInd): - e = startDocEvent(c.lex.cur == ltDirectivesEnd) - else: e = startDocEvent() - result = true - c.advance() - state = blockObjectStart - -parserState afterDocument: - case c.lex.cur - of ltStreamEnd: c.isFinished = true - of ltEmptyLine: c.advance() - else: - c.initDocValues() - state = initial - -parserState closeMoreIndentedLevels: - if c.ancestry.len > 0: - let parent = c.ancestry[c.ancestry.high] - if parent.indentation >= c.lex.indentation: - if c.lex.cur == ltSeqItemInd: - if (c.lex.indentation == c.level.indentation and - c.level.kind == fplSequence) or - (c.lex.indentation == parent.indentation and - c.level.kind == fplUnknown and parent.kind != fplSequence): - state = stored - debug("Not closing because sequence indicator") - return false - debug("Closing because parent.indentation (" & $parent.indentation & - ") >= indentation(" & $c.lex.indentation & ")") - case c.endLevel(e) - of lerNothing: discard - of lerOne: result = true - of lerAdditionalMapEnd: return true - discard c.handleObjectEnd(false) - return result - debug("Not closing level because parent.indentation (" & - $parent.indentation & ") < indentation(" & $c.lex.indentation & - ")") - if c.level.kind == fplDocument: state = expectDocEnd - else: state = stored - elif c.lex.indentation == c.level.indentation: - debug("Closing document") - let res = c.endLevel(e) - yAssert(res == lerOne) - result = true - state = stored - else: - state = stored - -parserState emitEmptyScalar: - e = implicitScalar() - result = true - state = stored - -parserState tagHandle: - c.handleTagHandle() - state = stored - -parserState anchor: - c.handleAnchor() - state = stored - -parserState alias: - if c.level.kind != fplUnknown: raise c.generateError("Unexpected token") - if c.anchor != yAnchorNone or c.tag != yTagQuestionMark: - raise c.generateError("Alias may not have anchor or tag") - var id: AnchorId - try: id = c.p.anchors[c.lex.buf] - except KeyError: raise c.generateError("Unknown anchor") - c.lex.buf.setLen(0) - e = aliasEvent(id) - c.advance() - result = true - state = objectEnd - -parserState flow: - case c.lex.cur - of ltBraceOpen: - if c.handleFlowItemStart(e): return true - e = c.objectStart(yamlStartMap) - result = true - c.flowdepth.inc() - c.explicitFlowKey = false - c.advance() - of ltBracketOpen: - if c.handleFlowItemStart(e): return true - e = c.objectStart(yamlStartSeq) - result = true - c.flowdepth.inc() - c.advance() - of ltBraceClose: - yAssert(c.level.kind == fplUnknown) - c.level = c.ancestry.pop() - state = leaveFlowMap - of ltBracketClose: - yAssert(c.level.kind == fplUnknown) - c.level = c.ancestry.pop() - state = leaveFlowSeq - of ltComma: - yAssert(c.level.kind == fplUnknown) - c.level = c.ancestry.pop() - case c.level.kind - of fplSequence: - e = c.emptyScalar() - result = true - of fplMapValue: - e = c.emptyScalar() - result = true - c.level.kind = fplMapKey - c.explicitFlowKey = false - of fplMapKey: - e = c.emptyScalar() - c.level.kind = fplMapValue - return true - of fplSinglePairValue: - e = c.emptyScalar() - result = true - c.level = c.ancestry.pop() - state = leaveFlowSinglePairMap - stored = flow - of fplUnknown, fplSinglePairKey, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - c.advance() - of ltMapValInd: - c.level = c.ancestry.pop() - case c.level.kind - of fplSequence: - e = startMapEvent(c.tag, c.anchor) - result = true - debug("started single-pair map at " & - (if c.level.indentation == UnknownIndentation: - $c.lex.indentation else: $c.level.indentation)) - c.tag = yTagQuestionMark - c.anchor = yAnchorNone - if c.level.indentation == UnknownIndentation: - c.level.indentation = c.lex.indentation - c.ancestry.add(c.level) - c.level = initLevel(fplSinglePairKey) - of fplMapValue, fplSinglePairValue: - raise c.generateError("Unexpected token (expected ',')") - of fplMapKey: - e = c.emptyScalar() - result = true - c.level.kind = fplMapValue - of fplSinglePairKey: - e = c.emptyScalar() - result = true - c.level.kind = fplSinglePairValue - of fplUnknown, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - if c.level.kind != fplSinglePairKey: c.advance() - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - of ltQuotedScalar: - if c.handleFlowItemStart(e): return true - if c.tag == yTagQuestionMark: c.tag = yTagExclamationMark - c.currentScalar(e) - when defined(yamlScalarRepInd): - case c.lex.scalarKind - of skSingleQuoted: e.scalarRep = srSingleQuoted - of skDoubleQuoted: e.scalarRep = srDoubleQuoted - of skLiteral: e.scalarRep = srLiteral - of skFolded: e.scalarRep = srFolded - result = true - state = objectEnd - stored = flowAfterObject - c.advance() - of ltTagHandle, ltLiteralTag: - if c.handleFlowItemStart(e): return true - c.handleTagHandle() - of ltAnchor: - if c.handleFlowItemStart(e): return true - c.handleAnchor() - of ltAlias: - state = alias - stored = flowAfterObject - of ltMapKeyInd: - if c.explicitFlowKey: - raise c.generateError("Duplicate '?' in flow mapping") - elif c.level.kind == fplUnknown: - case c.ancestry[c.ancestry.high].kind - of fplMapKey, fplMapValue, fplDocument: discard - of fplSequence: - e = c.objectStart(yamlStartMap, true) - result = true - else: - raise c.generateError("Unexpected token") - c.explicitFlowKey = true - c.advance() - of ltScalarPart: - if c.handleFlowItemStart(e): return true - c.handleFlowPlainScalar() - c.currentScalar(e) - result = true - state = objectEnd - stored = flowAfterObject - else: - raise c.generateError("Unexpected toked: " & $c.lex.cur) - -parserState leaveFlowMap: - case c.level.kind - of fplMapValue: - e = c.emptyScalar() - c.level.kind = fplMapKey - return true - of fplMapKey: - if c.tag != yTagQuestionMark or c.anchor != yAnchorNone or - c.explicitFlowKey: - e = c.emptyScalar() - c.level.kind = fplMapValue - c.explicitFlowKey = false - return true - of fplSequence: - raise c.generateError("Unexpected token (expected ']')") - of fplSinglePairValue: - raise c.generateError("Unexpected token (expected ']')") - of fplUnknown, fplSinglePairKey, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - result = c.leaveFlowLevel(e) - -parserState leaveFlowSeq: - case c.level.kind - of fplSequence: - if c.tag != yTagQuestionMark or c.anchor != yAnchorNone: - e = c.emptyScalar() - return true - of fplSinglePairValue: - e = c.emptyScalar() - c.level = c.ancestry.pop() - state = leaveFlowSinglePairMap - stored = leaveFlowSeq - return true - of fplMapKey, fplMapValue: - raise c.generateError("Unexpected token (expected '}')") - of fplUnknown, fplSinglePairKey, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - result = c.leaveFlowLevel(e) - -parserState leaveFlowSinglePairMap: - e = endMapEvent() - result = true - state = stored - -parserState flowAfterObject: - case c.lex.cur - of ltBracketClose: - case c.level.kind - of fplSequence: discard - of fplMapKey, fplMapValue: - raise c.generateError("Unexpected token (expected '}')") - of fplSinglePairValue: - c.level = c.ancestry.pop() - yAssert(c.level.kind == fplSequence) - e = endMapEvent() - return true - of fplUnknown, fplSinglePairKey, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - result = c.leaveFlowLevel(e) - of ltBraceClose: - case c.level.kind - of fplMapKey, fplMapValue: discard - of fplSequence, fplSinglePairValue: - raise c.generateError("Unexpected token (expected ']')") - of fplUnknown, fplSinglePairKey, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - # we need the extra state for possibly emitting an additional empty value. - state = leaveFlowMap - return false - of ltComma: - case c.level.kind - of fplSequence: discard - of fplMapValue: - e = implicitScalar() - result = true - c.level.kind = fplMapKey - c.explicitFlowKey = false - of fplSinglePairValue: - c.level = c.ancestry.pop() - yAssert(c.level.kind == fplSequence) - e = endMapEvent() - result = true - of fplMapKey: c.explicitFlowKey = false - of fplUnknown, fplSinglePairKey, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - state = flow - c.advance() - of ltMapValInd: - c.explicitFlowKey = false - case c.level.kind - of fplSequence, fplMapKey: - raise c.generateError("Unexpected token (expected ',')") - of fplMapValue, fplSinglePairValue: discard - of fplUnknown, fplSinglePairKey, fplDocument: - internalError("Unexpected level kind: " & $c.level.kind) - c.ancestry.add(c.level) - c.level = initLevel(fplUnknown) - state = flow - c.advance() - of ltStreamEnd: - raise c.generateError("Unclosed flow content") - else: - raise c.generateError("Unexpected content (expected flow indicator)") - -# --- parser initialization --- - -proc init(c: ParserContext, p: YamlParser) {.raises: [YamlParserError].} = - # this try/except should not be necessary because basicInit cannot raise - # anything. however, compiling to JS does not work without it. - try: c.basicInit(lastTokenContext) - except: discard - c.p = p - c.ancestry = newSeq[FastParseLevel]() - c.initDocValues() - c.flowdepth = 0 - c.nextImpl = stateInitial - c.explicitFlowKey = false - c.advance() - -when not defined(JS): - proc parse*(p: YamlParser, s: Stream): YamlStream - {.raises: [YamlParserError].} = - ## Parse the given stream as YAML character stream. - let c = new(ParserContext) - try: c.lex = newYamlLexer(s) - except: - let e = newException(YamlParserError, - "Error while opening stream: " & getCurrentExceptionMsg()) - e.parent = getCurrentException() - e.line = 1 - e.column = 1 - e.lineContent = "" - raise e - c.init(p) - result = c - -proc parse*(p: YamlParser, str: string): YamlStream - {.raises: [YamlParserError].} = - ## Parse the given string as YAML character stream. - let c = new(ParserContext) - c.lex = newYamlLexer(str) - c.init(p) - result = c - -proc anchorName*(p: YamlParser, anchor: AnchorId): string {.raises: [].} = - ## Retrieve the textual representation of the given anchor as it occurred in - ## the input (without the leading `&`). Returns the empty string for unknown - ## anchors. - for representation, value in p.anchors: - if value == anchor: return representation - return "" - -proc renderAttrs(p: YamlParser, tag: TagId, anchor: AnchorId, - isPlain: bool): string = - result = "" - if anchor != yAnchorNone: result &= " &" & p.anchorName(anchor) - case tag - of yTagQuestionmark: discard - of yTagExclamationmark: - when defined(yamlScalarRepInd): - if isPlain: result &= " " - else: - result &= " <" & p.taglib.uri(tag) & ">" - -proc display*(p: YamlParser, event: YamlStreamEvent): string - {.raises: [KeyError].} = - ## 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 - of yamlEndMap: result = "-MAP" - of yamlEndSeq: result = "-SEQ" - of yamlStartDoc: - result = "+DOC" - when defined(yamlScalarRepInd): - if event.explicitDirectivesEnd: result &= " ---" - of yamlEndDoc: - result = "-DOC" - when defined(yamlScalarRepInd): - if event.explicitDocumentEnd: result &= " ..." - of yamlStartMap: - result = "+MAP" & p.renderAttrs(event.mapTag, event.mapAnchor, true) - of yamlStartSeq: - result = "+SEQ" & p.renderAttrs(event.seqTag, event.seqAnchor, true) - of yamlScalar: - when defined(yamlScalarRepInd): - result = "=VAL" & p.renderAttrs(event.scalarTag, event.scalarAnchor, - event.scalarRep == srPlain) - case event.scalarRep - of srPlain: result &= " :" - of srSingleQuoted: result &= " \'" - of srDoubleQuoted: result &= " \"" - of srLiteral: result &= " |" - of srFolded: result &= " >" - else: - let isPlain = event.scalarTag == yTagExclamationmark - result = "=VAL" & p.renderAttrs(event.scalarTag, event.scalarAnchor, - isPlain) - if isPlain: result &= " :" - else: result &= " \"" - result &= yamlTestSuiteEscape(event.scalarContent) - of yamlAlias: result = "=ALI *" & p.anchorName(event.aliasTarget) \ No newline at end of file diff --git a/lib/yaml-legacy/yaml/presenter.nim b/lib/yaml-legacy/yaml/presenter.nim deleted file mode 100644 index af621fe..0000000 --- a/lib/yaml-legacy/yaml/presenter.nim +++ /dev/null @@ -1,805 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ===================== -## Module yaml.presenter -## ===================== -## -## This is the presenter API, used for generating YAML character streams. - -import streams, deques, strutils -import taglib, stream, private/internal, hints, parser, stream - -type - PresentationStyle* = enum - ## Different styles for YAML character stream output. - ## - ## - ``ypsMinimal``: Single-line flow-only output which tries to - ## use as few characters as possible. - ## - ``ypsCanonical``: Canonical YAML output. Writes all tags except - ## for the non-specific tags ``?`` and ``!``, uses flow style, quotes - ## all string scalars. - ## - ``ypsDefault``: Tries to be as human-readable as possible. Uses - ## block style by default, but tries to condense mappings and - ## sequences which only contain scalar nodes into a single line using - ## flow style. - ## - ``ypsJson``: Omits the ``%YAML`` directive and the ``---`` - ## marker. Uses flow style. Flattens anchors and aliases, omits tags. - ## Output will be parseable as JSON. ``YamlStream`` to dump may only - ## contain one document. - ## - ``ypsBlockOnly``: Formats all output in block style, does not use - ## flow style at all. - psMinimal, psCanonical, psDefault, psJson, psBlockOnly - - TagStyle* = enum - ## Whether object should be serialized with explicit tags. - ## - ## - ``tsNone``: No tags will be outputted unless necessary. - ## - ``tsRootOnly``: A tag will only be outputted for the root tag and - ## where necessary. - ## - ``tsAll``: Tags will be outputted for every object. - tsNone, tsRootOnly, tsAll - - AnchorStyle* = enum - ## How ref object should be serialized. - ## - ## - ``asNone``: No anchors will be outputted. Values present at - ## multiple places in the content that should be serialized will be - ## fully serialized at every occurence. If the content is cyclic, this - ## will lead to an endless loop! - ## - ``asTidy``: Anchors will only be generated for objects that - ## actually occur more than once in the content to be serialized. - ## This is a bit slower and needs more memory than ``asAlways``. - ## - ``asAlways``: Achors will be generated for every ref object in the - ## content to be serialized, regardless of whether the object is - ## referenced again afterwards - asNone, asTidy, asAlways - - NewLineStyle* = enum - ## What kind of newline sequence is used when presenting. - ## - ## - ``nlLF``: Use a single linefeed char as newline. - ## - ``nlCRLF``: Use a sequence of carriage return and linefeed as - ## newline. - ## - ``nlOSDefault``: Use the target operation system's default newline - ## sequence (CRLF on Windows, LF everywhere else). - nlLF, nlCRLF, nlOSDefault - - OutputYamlVersion* = enum - ## Specify which YAML version number the presenter shall emit. The - ## presenter will always emit content that is valid YAML 1.1, but by - ## default will write a directive ``%YAML 1.2``. For compatibility with - ## other YAML implementations, it is possible to change this here. - ## - ## It is also possible to specify that the presenter shall not emit any - ## YAML version. The generated content is then guaranteed to be valid - ## YAML 1.1 and 1.2 (but not 1.0 or any newer YAML version). - ov1_2, ov1_1, ovNone - - PresentationOptions* = object - ## Options for generating a YAML character stream - style*: PresentationStyle - indentationStep*: int - newlines*: NewLineStyle - outputVersion*: OutputYamlVersion - - YamlPresenterJsonError* = object of Exception - ## Exception that may be raised by the YAML presenter when it is - ## instructed to output JSON, but is unable to do so. This may occur if: - ## - ## - The given `YamlStream <#YamlStream>`_ contains a map which has any - ## non-scalar type as key. - ## - Any float scalar bears a ``NaN`` or positive/negative infinity value - - YamlPresenterOutputError* = object of Exception - ## Exception that may be raised by the YAML presenter. This occurs if - ## writing character data to the output stream raises any exception. - ## The error that has occurred is available from ``parent``. - - DumperState = enum - dBlockExplicitMapKey, dBlockImplicitMapKey, dBlockMapValue, - dBlockInlineMap, dBlockSequenceItem, dFlowImplicitMapKey, dFlowMapValue, - dFlowExplicitMapKey, dFlowSequenceItem, dFlowMapStart, dFlowSequenceStart - - ScalarStyle = enum - sLiteral, sFolded, sPlain, sDoubleQuoted - - PresenterTarget = Stream | ptr[string] - -const - defaultPresentationOptions* = - PresentationOptions(style: psDefault, indentationStep: 2, - newlines: nlOSDefault) - -proc defineOptions*(style: PresentationStyle = psDefault, - indentationStep: int = 2, - newlines: NewLineStyle = nlOSDefault, - outputVersion: OutputYamlVersion = ov1_2): - PresentationOptions {.raises: [].} = - ## Define a set of options for presentation. Convenience proc that requires - ## you to only set those values that should not equal the default. - PresentationOptions(style: style, indentationStep: indentationStep, - newlines: newlines, outputVersion: outputVersion) - -proc inspect(scalar: string, indentation: int, - words, lines: var seq[tuple[start, finish: int]]): - ScalarStyle {.raises: [].} = - var - inLine = false - inWord = false - multipleSpaces = true - curWord, curLine: tuple[start, finish: int] - canUseFolded = true - canUseLiteral = true - canUsePlain = scalar.len > 0 and - scalar[0] notin {'@', '`', '|', '>', '&', '*', '!', ' ', '\t'} - for i, c in scalar: - case c - of ' ': - if inWord: - if not multipleSpaces: - curWord.finish = i - 1 - inWord = false - else: - multipleSpaces = true - inWord = true - if not inLine: - inLine = true - curLine.start = i - # space at beginning of line will preserve previous and next - # linebreak. that is currently too complex to handle. - canUseFolded = false - of '\l': - canUsePlain = false # we don't use multiline plain scalars - curWord.finish = i - 1 - if curWord.finish - curWord.start + 1 > 80 - indentation: - return if canUsePlain: sPlain else: sDoubleQuoted - words.add(curWord) - inWord = false - curWord.start = i + 1 - multipleSpaces = true - if not inLine: curLine.start = i - inLine = false - curLine.finish = i - 1 - if curLine.finish - curLine.start + 1 > 80 - indentation: - canUseLiteral = false - lines.add(curLine) - else: - if c in {'{', '}', '[', ']', ',', '#', '-', ':', '?', '%', '"', '\''} or - c.ord < 32: canUsePlain = false - if not inLine: - curLine.start = i - inLine = true - if not inWord: - if not multipleSpaces: - if curWord.finish - curWord.start + 1 > 80 - indentation: - return if canUsePlain: sPlain else: sDoubleQuoted - words.add(curWord) - curWord.start = i - inWord = true - multipleSpaces = false - if inWord: - curWord.finish = scalar.len - 1 - if curWord.finish - curWord.start + 1 > 80 - indentation: - return if canUsePlain: sPlain else: sDoubleQuoted - words.add(curWord) - if inLine: - curLine.finish = scalar.len - 1 - if curLine.finish - curLine.start + 1 > 80 - indentation: - canUseLiteral = false - lines.add(curLine) - if scalar.len <= 80 - indentation: - result = if canUsePlain: sPlain else: sDoubleQuoted - elif canUseLiteral: result = sLiteral - elif canUseFolded: result = sFolded - elif canUsePlain: result = sPlain - else: result = sDoubleQuoted - -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.append('"') - curPos.inc() - for c in scalar: - if curPos == 79: - s.append('\\') - s.append(newline) - s.append(repeat(' ', indentation)) - curPos = indentation - if c == ' ': - s.append('\\') - curPos.inc() - case c - of '"': - s.append("\\\"") - curPos.inc(2) - of '\l': - s.append("\\n") - curPos.inc(2) - of '\t': - s.append("\\t") - curPos.inc(2) - of '\\': - s.append("\\\\") - curPos.inc(2) - else: - if ord(c) < 32: - s.append("\\x" & toHex(ord(c), 2)) - curPos.inc(4) - else: - s.append(c) - curPos.inc() - s.append('"') - except: - var e = newException(YamlPresenterOutputError, - "Error while writing to output stream") - e.parent = getCurrentException() - raise e - -proc writeDoubleQuotedJson(scalar: string, s: PresenterTarget) - {.raises: [YamlPresenterOutputError].} = - try: - s.append('"') - for c in scalar: - case c - 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.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: PresenterTarget, lines: seq[tuple[start, finish: int]], - newline: string) - {.raises: [YamlPresenterOutputError].} = - try: - s.append('|') - if scalar[^1] != '\l': s.append('-') - if scalar[0] in [' ', '\t']: s.append($indentStep) - for line in lines: - s.append(newline) - s.append(repeat(' ', indentation + indentStep)) - if line.finish >= line.start: - 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: PresenterTarget, words: seq[tuple[start, finish: int]], - newline: string) - {.raises: [YamlPresenterOutputError].} = - try: - 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.append(newline & newline) - s.append(repeat(' ', indentation + indentStep)) - curPos = indentation + indentStep - elif curPos + (word.finish - word.start) > 80: - s.append(newline) - s.append(repeat(' ', indentation + indentStep)) - curPos = indentation + indentStep - else: - s.append(' ') - curPos.inc() - s.append(scalar[word.start .. word.finish]) - curPos += word.finish - word.start + 1 - except: - var e = newException(YamlPresenterOutputError, - "Error while writing to output stream") - e.parent = getCurrentException() - raise e - -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: PresenterTarget, style: PresentationStyle, - indentation: int, state: var DumperState, isObject: bool, - newline: string) {.raises: [YamlPresenterOutputError].} = - try: - case state - of dBlockMapValue: - target.append(newline) - target.append(repeat(' ', indentation)) - if isObject or style == psCanonical: - target.append("? ") - state = dBlockExplicitMapKey - else: state = dBlockImplicitMapKey - of dBlockInlineMap: state = dBlockImplicitMapKey - of dBlockExplicitMapKey: - target.append(newline) - target.append(repeat(' ', indentation)) - target.append(": ") - state = dBlockMapValue - of dBlockImplicitMapKey: - target.append(": ") - state = dBlockMapValue - of dFlowExplicitMapKey: - if style != psMinimal: - target.append(newline) - target.append(repeat(' ', indentation)) - target.append(": ") - state = dFlowMapValue - of dFlowMapValue: - if (isObject and style != psMinimal) or style in [psJson, psCanonical]: - target.append(',' & newline & repeat(' ', indentation)) - if style == psJson: state = dFlowImplicitMapKey - else: - target.append("? ") - state = dFlowExplicitMapKey - elif isObject and style == psMinimal: - target.append(", ? ") - state = dFlowExplicitMapKey - else: - target.append(", ") - state = dFlowImplicitMapKey - of dFlowMapStart: - if (isObject and style != psMinimal) or style in [psJson, psCanonical]: - target.append(newline & repeat(' ', indentation)) - if style == psJson: state = dFlowImplicitMapKey - else: - target.append("? ") - state = dFlowExplicitMapKey - else: state = dFlowImplicitMapKey - of dFlowImplicitMapKey: - target.append(": ") - state = dFlowMapValue - of dBlockSequenceItem: - target.append(newline) - target.append(repeat(' ', indentation)) - target.append("- ") - of dFlowSequenceStart: - case style - of psMinimal, psDefault: discard - of psCanonical, psJson: - target.append(newline) - target.append(repeat(' ', indentation)) - of psBlockOnly: discard # can never happen - state = dFlowSequenceItem - of dFlowSequenceItem: - case style - of psMinimal, psDefault: target.append(", ") - of psCanonical, psJson: - target.append(',' & newline) - target.append(repeat(' ', indentation)) - of psBlockOnly: discard # can never happen - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - -proc anchorName(a: AnchorId): string {.raises: [].} = - result = "" - var i = int(a) - while i >= 0: - let j = i mod 36 - if j < 26: result.add(char(j + ord('a'))) - else: result.add(char(j + ord('0') - 26)) - i -= 36 - -proc writeTagAndAnchor(target: PresenterTarget, tag: TagId, - tagLib: TagLibrary, - anchor: AnchorId) {.raises: [YamlPresenterOutputError].} = - try: - if tag notin [yTagQuestionMark, yTagExclamationMark]: - let tagUri = tagLib.uri(tag) - let (handle, length) = tagLib.searchHandle(tagUri) - if length > 0: - target.append(handle) - target.append(tagUri[length..tagUri.high]) - target.append(' ') - else: - target.append("!<") - target.append(tagUri) - target.append("> ") - if anchor != yAnchorNone: - target.append("&") - target.append(anchorName(anchor)) - target.append(' ') - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - -proc nextItem(c: var Deque, s: var YamlStream): - YamlStreamEvent {.raises: [YamlStreamError].} = - if c.len > 0: - try: result = c.popFirst - except IndexError: internalError("Unexpected IndexError") - else: - result = s.next() - -proc doPresent(s: var YamlStream, target: PresenterTarget, - tagLib: TagLibrary, - options: PresentationOptions = defaultPresentationOptions) = - var - indentation = 0 - levels = newSeq[DumperState]() - cached = initDeQue[YamlStreamEvent]() - let newline = if options.newlines == nlLF: "\l" - elif options.newlines == nlCRLF: "\c\l" else: "\n" - while cached.len > 0 or not s.finished(): - let item = nextItem(cached, s) - case item.kind - of yamlStartDoc: - if options.style != psJson: - try: - case options.outputVersion - of ov1_2: target.append("%YAML 1.2" & newline) - of ov1_1: target.append("%YAML 1.1" & newLine) - of ovNone: discard - for prefix, handle in tagLib.handles(): - if handle == "!": - if prefix != "!": - target.append("%TAG ! " & prefix & newline) - elif handle == "!!": - if prefix != yamlTagRepositoryPrefix: - target.append("%TAG !! " & prefix & newline) - else: - target.append("%TAG " & handle & ' ' & prefix & newline) - target.append("--- ") - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - of yamlScalar: - if levels.len == 0: - if options.style != psJson: target.safeWrite(newline) - else: - startItem(target, options.style, indentation, - levels[levels.high], false, newline) - if options.style != psJson: - writeTagAndAnchor(target, item.scalarTag, tagLib, item.scalarAnchor) - - if options.style == psJson: - let hint = guessType(item.scalarContent) - if item.scalarTag in [yTagQuestionMark, yTagBoolean] and - hint in {yTypeBoolTrue, yTypeBoolFalse}: - target.safeWrite(if hint == yTypeBoolTrue: "true" else: "false") - elif item.scalarTag in [yTagQuestionMark, yTagNull] and - hint == yTypeNull: - target.safeWrite("null") - elif item.scalarTag in [yTagQuestionMark, yTagInteger, - yTagNimInt8, yTagNimInt16, yTagNimInt32, yTagNimInt64, - yTagNimUInt8, yTagNimUInt16, yTagNimUInt32, yTagNimUInt64] and - hint == yTypeInteger: - 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: - target.safeWrite(item.scalarContent) - else: writeDoubleQuotedJson(item.scalarContent, target) - elif options.style == psCanonical: - writeDoubleQuoted(item.scalarContent, target, - indentation + options.indentationStep, newline) - else: - var words, lines = newSeq[tuple[start, finish: int]]() - case item.scalarContent.inspect( - indentation + options.indentationStep, words, lines) - of sLiteral: writeLiteral(item.scalarContent, indentation, - options.indentationStep, target, lines, newline) - of sFolded: writeFolded(item.scalarContent, indentation, - options.indentationStep, target, words, newline) - of sPlain: target.safeWrite(item.scalarContent) - of sDoubleQuoted: writeDoubleQuoted(item.scalarContent, target, - indentation + options.indentationStep, newline) - of yamlAlias: - if options.style == psJson: - raise newException(YamlPresenterJsonError, - "Alias not allowed in JSON output") - yAssert levels.len > 0 - startItem(target, options.style, indentation, levels[levels.high], - false, newline) - try: - target.append('*') - target.append(char(byte('a') + byte(item.aliasTarget))) - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - of yamlStartSeq: - var nextState: DumperState - case options.style - of psDefault: - var length = 0 - while true: - yAssert(not s.finished()) - let next = s.next() - cached.addLast(next) - case next.kind - of yamlScalar: length += 2 + next.scalarContent.len - of yamlAlias: length += 6 - of yamlEndSeq: break - else: - length = high(int) - break - nextState = if length <= 60: dFlowSequenceStart else: dBlockSequenceItem - of psJson: - if levels.len > 0 and levels[levels.high] in - [dFlowMapStart, dFlowMapValue]: - raise newException(YamlPresenterJsonError, "Cannot have sequence as map key in JSON output!") - nextState = dFlowSequenceStart - of psMinimal, psCanonical: nextState = dFlowSequenceStart - of psBlockOnly: - yAssert(not s.finished()) - let next = s.peek() - if next.kind == yamlEndSeq: nextState = dFlowSequenceStart - else: nextState = dBlockSequenceItem - - if levels.len == 0: - case nextState - of dBlockSequenceItem: - if options.style != psJson: - writeTagAndAnchor(target, item.seqTag, tagLib, item.seqAnchor) - of dFlowSequenceStart: - target.safeWrite(newline) - if options.style != psJson: - writeTagAndAnchor(target, item.seqTag, tagLib, item.seqAnchor) - indentation += options.indentationStep - else: internalError("Invalid nextState: " & $nextState) - else: - startItem(target, options.style, indentation, - levels[levels.high], true, newline) - if options.style != psJson: - writeTagAndAnchor(target, item.seqTag, tagLib, item.seqAnchor) - indentation += options.indentationStep - - if nextState == dFlowSequenceStart: target.safeWrite('[') - if levels.len > 0 and options.style in [psJson, psCanonical] and - levels[levels.high] in [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - indentation += options.indentationStep - levels.add(nextState) - of yamlStartMap: - var nextState: DumperState - case options.style - of psDefault: - type MapParseState = enum - mpInitial, mpKey, mpValue, mpNeedBlock - var mps: MapParseState = mpInitial - while mps != mpNeedBlock: - case s.peek().kind - of yamlScalar, yamlAlias: - case mps - of mpInitial: mps = mpKey - of mpKey: mps = mpValue - else: mps = mpNeedBlock - of yamlEndMap: break - else: mps = mpNeedBlock - nextState = if mps == mpNeedBlock: dBlockMapValue else: dBlockInlineMap - of psMinimal: nextState = dFlowMapStart - of psCanonical: nextState = dFlowMapStart - of psJson: - if levels.len > 0 and levels[levels.high] in - [dFlowMapStart, dFlowMapValue]: - raise newException(YamlPresenterJsonError, - "Cannot have map as map key in JSON output!") - nextState = dFlowMapStart - of psBlockOnly: - yAssert(not s.finished()) - let next = s.peek() - if next.kind == yamlEndMap: nextState = dFlowMapStart - else: nextState = dBlockMapValue - if levels.len == 0: - case nextState - of dBlockMapValue: - if options.style != psJson: - writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) - else: - if options.style != psJson: - target.safeWrite(newline) - writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) - indentation += options.indentationStep - of dFlowMapStart: - target.safeWrite(newline) - if options.style != psJson: - writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) - indentation += options.indentationStep - of dBlockInlineMap: discard - else: internalError("Invalid nextState: " & $nextState) - else: - if nextState in [dBlockMapValue, dBlockImplicitMapKey]: - startItem(target, options.style, indentation, - levels[levels.high], true, newline) - if options.style != psJson: - writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) - else: - startItem(target, options.style, indentation, - levels[levels.high], true, newline) - if options.style != psJson: - writeTagAndAnchor(target, item.mapTag, tagLib, item.mapAnchor) - indentation += options.indentationStep - - if nextState == dFlowMapStart: target.safeWrite('{') - if levels.len > 0 and options.style in [psJson, psCanonical] and - levels[levels.high] in - [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - indentation += options.indentationStep - levels.add(nextState) - - of yamlEndSeq: - yAssert levels.len > 0 - case levels.pop() - of dFlowSequenceItem: - case options.style - of psDefault, psMinimal, psBlockOnly: target.safeWrite(']') - of psJson, psCanonical: - indentation -= options.indentationStep - try: - target.append(newline) - target.append(repeat(' ', indentation)) - target.append(']') - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - if levels.len == 0 or levels[levels.high] notin - [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - continue - of dFlowSequenceStart: - if levels.len > 0 and options.style in [psJson, psCanonical] and - levels[levels.high] in [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - indentation -= options.indentationStep - target.safeWrite(']') - of dBlockSequenceItem: discard - else: internalError("Invalid popped level") - indentation -= options.indentationStep - of yamlEndMap: - yAssert levels.len > 0 - let level = levels.pop() - case level - of dFlowMapValue: - case options.style - of psDefault, psMinimal, psBlockOnly: target.safeWrite('}') - of psJson, psCanonical: - indentation -= options.indentationStep - try: - target.append(newline) - target.append(repeat(' ', indentation)) - target.append('}') - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - if levels.len == 0 or levels[levels.high] notin - [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - continue - of dFlowMapStart: - if levels.len > 0 and options.style in [psJson, psCanonical] and - levels[levels.high] in [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - indentation -= options.indentationStep - target.safeWrite('}') - of dBlockMapValue, dBlockInlineMap: discard - else: internalError("Invalid level: " & $level) - indentation -= options.indentationStep - of yamlEndDoc: - if finished(s): break - if options.style == psJson: - raise newException(YamlPresenterJsonError, - "Cannot output more than one document in JSON style") - target.safeWrite("..." & newline) - -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``. - doPresent(s, target, tagLib, options) - -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. - result = "" - doPresent(s, addr result, tagLib, options) - -proc doTransform(input: Stream | string, output: PresenterTarget, - options: PresentationOptions, resolveToCoreYamlTags: bool) = - var - taglib = initExtendedTagLibrary() - parser = newYamlParser(tagLib) - events = parser.parse(input) - try: - if options.style == psCanonical: - var bys: YamlStream = newBufferYamlStream() - for e in events: - if resolveToCoreYamlTags: - var event = e - case event.kind - of yamlStartDoc, yamlEndDoc, yamlEndMap, yamlAlias, yamlEndSeq: - discard - of yamlStartMap: - if event.mapTag in [yTagQuestionMark, yTagExclamationMark]: - event.mapTag = yTagMapping - of yamlStartSeq: - if event.seqTag in [yTagQuestionMark, yTagExclamationMark]: - event.seqTag = yTagSequence - of yamlScalar: - if event.scalarTag == yTagQuestionMark: - case guessType(event.scalarContent) - of yTypeInteger: event.scalarTag = yTagInteger - of yTypeFloat, yTypeFloatInf, yTypeFloatNaN: - event.scalarTag = yTagFloat - of yTypeBoolTrue, yTypeBoolFalse: event.scalarTag = yTagBoolean - of yTypeNull: event.scalarTag = yTagNull - of yTypeTimestamp: event.scalarTag = yTagTimestamp - of yTypeUnknown: event.scalarTag = yTagString - elif event.scalarTag == yTagExclamationMark: - event.scalarTag = yTagString - BufferYamlStream(bys).put(event) - else: BufferYamlStream(bys).put(e) - when output is ptr[string]: output[] = present(bys, tagLib, options) - else: present(bys, output, tagLib, options) - else: - when output is ptr[string]: output[] = present(events, tagLib, options) - else: present(events, output, tagLib, options) - except YamlStreamError: - var e = getCurrentException() - while e.parent of YamlStreamError: e = e.parent - 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, - resolveToCoreYamlTags: bool = false) - {.raises: [IOError, YamlParserError, YamlPresenterJsonError, - YamlPresenterOutputError].} = - ## Parser ``input`` as YAML character stream and then dump it to ``output`` - ## while resolving non-specific tags to the ones in the YAML core tag - ## library. If ``resolveToCoreYamlTags`` is ``true``, non-specific tags will - ## be replaced by specific tags according to the YAML core schema. - doTransform(input, output, options, resolveToCoreYamlTags) - -proc transform*(input: Stream | string, - options: PresentationOptions = defaultPresentationOptions, - resolveToCoreYamlTags: bool = false): - 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. If ``resolveToCoreYamlTags`` is - ## ``true``, non-specific tags will be replaced by specific tags according to - ## the YAML core schema. - result = "" - doTransform(input, addr result, options, resolveToCoreYamlTags) diff --git a/lib/yaml-legacy/yaml/private/internal.nim b/lib/yaml-legacy/yaml/private/internal.nim deleted file mode 100644 index bb003d8..0000000 --- a/lib/yaml-legacy/yaml/private/internal.nim +++ /dev/null @@ -1,53 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -template internalError*(s: string) = - # Note: to get the internal stacktrace that caused the error - # compile with the `d:debug` flag. - when not defined(release): - let ii = instantiationInfo() - echo "[NimYAML] Error in file ", ii.filename, " at line ", ii.line, ":" - echo s - when not defined(JS): - echo "[NimYAML] Stacktrace:" - try: - writeStackTrace() - let exc = getCurrentException() - if not isNil(exc.parent): - echo "Internal stacktrace:" - echo getStackTrace(exc.parent) - except: discard - echo "[NimYAML] Please report this bug." - quit 1 - -template yAssert*(e: typed) = - when not defined(release): - if not e: - let ii = instantiationInfo() - echo "[NimYAML] Error in file ", ii.filename, " at line ", ii.line, ":" - echo "assertion failed!" - when not defined(JS): - echo "[NimYAML] Stacktrace:" - try: - writeStackTrace() - let exc = getCurrentException() - if not isNil(exc.parent): - echo "Internal stacktrace:" - echo getStackTrace(exc.parent) - except: discard - echo "[NimYAML] Please report this bug." - quit 1 - -proc yamlTestSuiteEscape*(s: string): string = - result = "" - for c in s: - case c - of '\l': result.add("\\n") - of '\c': result.add("\\r") - of '\\': result.add("\\\\") - of '\b': result.add("\\b") - of '\t': result.add("\\t") - else: result.add(c) \ No newline at end of file diff --git a/lib/yaml-legacy/yaml/private/lex.nim b/lib/yaml-legacy/yaml/private/lex.nim deleted file mode 100644 index 3240ced..0000000 --- a/lib/yaml-legacy/yaml/private/lex.nim +++ /dev/null @@ -1,1213 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2015 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import lexbase, streams, strutils, unicode -when defined(yamlDebug): - import terminal - export terminal - -when defined(yamlScalarRepInd): - type ScalarKind* = enum - skSingleQuoted, skDoubleQuoted, skLiteral, skFolded - -type - StringSource* = object - src: string - pos: int - line, lineStart: int - - SourceProvider* = concept c - advance(c) is char - lexCR(c) - lexLF(c) - - YamlLexerObj* = object - cur*: LexerToken - curStartPos*: tuple[line, column: int] - # ltScalarPart, ltQuotedScalar, ltYamlVersion, ltTagShorthand, ltTagUri, - # ltLiteralTag, ltTagHandle, ltAnchor, ltAlias - buf*: string - # ltIndentation - indentation*: int - # ltTagHandle - shorthandEnd*: int - when defined(yamlScalarRepInd): - # ltQuotedScalar, ltBlockScalarHeader - scalarKind*: ScalarKind - - # may be modified from outside; will be consumed at plain scalar starts - newlines*: int - - # internals - when defined(JS): sSource: StringSource - else: source: pointer - inFlow: bool - literalEndIndent: int - nextState, lineStartState, inlineState, insideLineImpl, insideDocImpl, - insideFlowImpl, outsideDocImpl: LexerState - blockScalarIndent: int - folded: bool - chomp: ChompType - c: char - tokenLineGetter: proc(lex: YamlLexer, pos: tuple[line, column: int], - marker: bool): string {.raises: [].} - searchColonImpl: proc(lex: YamlLexer): bool - - YamlLexer* = ref YamlLexerObj - - YamlLexerError* = object of Exception - line*, column*: int - lineContent*: string - - LexerState = proc(lex: YamlLexer): bool {.raises: YamlLexerError, locks: 0, - gcSafe.} - - LexerToken* = enum - ltYamlDirective, ltYamlVersion, ltTagDirective, ltTagShorthand, - ltTagUri, ltUnknownDirective, ltUnknownDirectiveParams, ltEmptyLine, - ltDirectivesEnd, ltDocumentEnd, ltStreamEnd, ltIndentation, ltQuotedScalar, - ltScalarPart, ltBlockScalarHeader, ltBlockScalar, ltSeqItemInd, ltMapKeyInd, - ltMapValInd, ltBraceOpen, ltBraceClose, ltBracketOpen, ltBracketClose, - ltComma, ltLiteralTag, ltTagHandle, ltAnchor, ltAlias - - ChompType* = enum - ctKeep, ctClip, ctStrip - -# consts - -const - space = {' ', '\t'} - lineEnd = {'\l', '\c', EndOfFile} - spaceOrLineEnd = {' ', '\t', '\l', '\c', EndOfFile} - digits = {'0'..'9'} - flowIndicators = {'[', ']', '{', '}', ','} - uriChars = {'a' .. 'z', 'A' .. 'Z', '0' .. '9', '#', ';', '/', '?', ':', - '@', '&', '-', '=', '+', '$', '_', '.', '~', '*', '\'', '(', ')'} - - UTF8NextLine = toUTF8(0x85.Rune) - UTF8NonBreakingSpace = toUTF8(0xA0.Rune) - UTF8LineSeparator = toUTF8(0x2028.Rune) - UTF8ParagraphSeparator = toUTF8(0x2029.Rune) - - UnknownIndentation* = int.low - -# lexer backend implementations - -template blSource(lex: YamlLexer): var BaseLexer = - (cast[ptr BaseLexer](lex.source))[] -template sSource(lex: YamlLexer): var StringSource = - (cast[ptr StringSource](lex.source))[] - -proc advance(lex: YamlLexer, t: typedesc[BaseLexer], step: int = 1) {.inline.} = - lex.blSource.bufpos.inc(step) - lex.c = lex.blSource.buf[lex.blSource.bufpos] - -proc advance(lex: YamlLexer, t: typedesc[StringSource], step: int = 1) - {.inline.} = - lex.sSource.pos.inc(step) - if lex.sSource.pos >= lex.sSource.src.len: lex.c = EndOfFile - else: lex.c = lex.sSource.src[lex.sSource.pos] - -template lexCR(lex: YamlLexer, t: typedesc[BaseLexer]) = - try: lex.blSource.bufpos = lex.blSource.handleCR(lex.blSource.bufpos) - except: - var e = generateError[T](lex, "Encountered stream error: " & - getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - lex.c = lex.blSource.buf[lex.blSource.bufpos] - -template lexCR(lex: YamlLexer, t: typedesc[StringSource]) = - lex.sSource.pos.inc() - if lex.sSource.src[lex.sSource.pos] == '\l': lex.sSource.pos.inc() - lex.sSource.lineStart = lex.sSource.pos - lex.sSource.line.inc() - lex.c = lex.sSource.src[lex.sSource.pos] - -template lexLF(lex: YamlLexer, t: typedesc[BaseLexer]) = - try: lex.blSource.bufpos = lex.blSource.handleLF(lex.blSource.bufpos) - except: - var e = generateError[T](lex, "Encountered stream error: " & - getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - lex.c = lex.blSource.buf[lex.blSource.bufpos] - -template lexLF(lex: YamlLexer, t: typedesc[StringSource]) = - lex.sSource.pos.inc() - lex.sSource.lineStart = lex.sSource.pos - lex.sSource.line.inc() - lex.c = lex.sSource.src[lex.sSource.pos] - -template lineNumber(lex: YamlLexer, t: typedesc[BaseLexer]): int = - lex.blSource.lineNumber - -template lineNumber(lex: YamlLexer, t: typedesc[StringSource]): int = - lex.sSource.line - -template columnNumber(lex: YamlLexer, t: typedesc[BaseLexer]): int = - lex.blSource.getColNumber(lex.blSource.bufpos) + 1 - -template columnNumber(lex: YamlLexer, t: typedesc[StringSource]): int = - lex.sSource.pos - lex.sSource.lineStart + 1 - -template currentLine(lex: YamlLexer, t: typedesc[BaseLexer]): string = - lex.blSource.getCurrentLine(true) - -template currentLine(lex: YamlLexer, t: typedesc[StringSource]): string = - var result = "" - var i = lex.sSource.lineStart - while lex.sSource.src[i] notin lineEnd: - result.add(lex.sSource.src[i]) - inc(i) - result.add("\n" & spaces(lex.columnNumber(t) - 1) & "^\n") - result - -proc nextIsPlainSafe(lex: YamlLexer, t: typedesc[BaseLexer], inFlow: bool): - bool {.inline.} = - case lex.blSource.buf[lex.blSource.bufpos + 1] - of spaceOrLineEnd: result = false - of flowIndicators: result = not inFlow - else: result = true - -proc nextIsPlainSafe(lex: YamlLexer, t: typedesc[StringSource], - inFlow: bool): bool {.inline.} = - case lex.sSource.src[lex.sSource.pos + 1] - of spaceOrLineEnd: result = false - of flowIndicators: result = not inFlow - else: result = true - -proc getPos(lex: YamlLexer, t: typedesc[BaseLexer]): int = lex.blSource.bufpos -proc getPos(lex: YamlLexer, t: typedesc[StringSource]): int = lex.sSource.pos - -proc at(lex: YamlLexer, t: typedesc[BaseLexer], pos: int): char {.inline.} = - lex.blSource.buf[pos] - -proc at(lex: YamlLexer, t: typedesc[StringSource], pos: int): char {.inline.} = - lex.sSource.src[pos] - -proc mark(lex: YamlLexer, t: typedesc[BaseLexer]): int = lex.blSource.bufpos -proc mark(lex: YamlLexer, t: typedesc[StringSource]): int = lex.sSource.pos - -proc afterMark(lex: YamlLexer, t: typedesc[BaseLexer], m: int): int {.inline.} = - lex.blSource.bufpos - m - -proc afterMark(lex: YamlLexer, t: typedesc[StringSource], m: int): - int {.inline.} = - lex.sSource.pos - m - -proc lineWithMarker(lex: YamlLexer, pos: tuple[line, column: int], - t: typedesc[BaseLexer], marker: bool): string = - if pos.line == lex.blSource.lineNumber: - result = lex.blSource.getCurrentLine(false) - if marker: result.add(spaces(pos.column - 1) & "^\n") - else: result = "" - -proc lineWithMarker(lex: YamlLexer, pos: tuple[line, column: int], - t: typedesc[StringSource], marker: bool): string = - var - lineStartIndex = lex.sSource.pos - lineEndIndex: int - curLine = lex.sSource.line - if pos.line == curLine: - lineEndIndex = lex.sSource.pos - while lex.sSource.src[lineEndIndex] notin lineEnd: inc(lineEndIndex) - while true: - while lineStartIndex >= 0 and lex.sSource.src[lineStartIndex] notin lineEnd: - dec(lineStartIndex) - if curLine == pos.line: - inc(lineStartIndex) - break - let wasLF = lex.sSource.src[lineStartIndex] == '\l' - lineEndIndex = lineStartIndex - dec(lineStartIndex) - if lex.sSource.src[lineStartIndex] == '\c' and wasLF: - dec(lineStartIndex) - dec(lineEndIndex) - dec(curLine) - result = lex.sSource.src.substr(lineStartIndex, lineEndIndex - 1) & "\n" - if marker: result.add(spaces(pos.column - 1) & "^\n") - -# lexer states - -{.push gcSafe, locks: 0.} -# `raises` cannot be pushed. -proc outsideDoc[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc yamlVersion[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc tagShorthand[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc tagUri[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc unknownDirParams[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc expectLineEnd[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc possibleDirectivesEnd[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc possibleDocumentEnd[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc afterSeqInd[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc insideDoc[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc insideFlow[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc insideLine[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc plainScalarPart[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc blockScalarHeader[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc blockScalar[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc indentationAfterBlockScalar[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc dirEndAfterBlockScalar[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc docEndAfterBlockScalar[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc tagHandle[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc anchor[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc alias[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -proc streamEnd[T](lex: YamlLexer): bool {.raises: YamlLexerError.} -{.pop.} - -# implementation - -template debug(message: string) {.dirty.} = - when defined(yamlDebug): - try: styledWriteLine(stdout, fgBlue, message) - except IOError: discard - -proc generateError[T](lex: YamlLexer, message: string): - ref YamlLexerError {.raises: [].} = - result = newException(YamlLexerError, message) - result.line = lex.lineNumber(T) - result.column = lex.columnNumber(T) - result.lineContent = lex.currentLine(T) - -proc startToken[T](lex: YamlLexer) {.inline.} = - lex.curStartPos = (lex.lineNumber(T), lex.columnNumber(T)) - -proc directiveName[T](lex: YamlLexer) = - while lex.c notin spaceOrLineEnd: - lex.buf.add(lex.c) - lex.advance(T) - -proc consumeNewlines(lex: YamlLexer) {.inline, raises: [].} = - case lex.newlines - of 0: return - of 1: lex.buf.add(' ') - else: lex.buf.add(repeat('\l', lex.newlines - 1)) - lex.newlines = 0 - -proc yamlVersion[T](lex: YamlLexer): bool = - debug("lex: yamlVersion") - while lex.c in space: lex.advance(T) - if lex.c notin digits: - raise generateError[T](lex, "Invalid YAML version number") - startToken[T](lex) - lex.buf.add(lex.c) - lex.advance(T) - while lex.c in digits: - lex.buf.add(lex.c) - lex.advance(T) - if lex.c != '.': raise generateError[T](lex, "Invalid YAML version number") - lex.buf.add('.') - lex.advance(T) - if lex.c notin digits: - raise generateError[T](lex, "Invalid YAML version number") - lex.buf.add(lex.c) - lex.advance(T) - while lex.c in digits: - lex.buf.add(lex.c) - lex.advance(T) - if lex.c notin spaceOrLineEnd: - raise generateError[T](lex, "Invalid YAML version number") - lex.cur = ltYamlVersion - result = true - lex.nextState = expectLineEnd[T] - -proc tagShorthand[T](lex: YamlLexer): bool = - debug("lex: tagShorthand") - while lex.c in space: lex.advance(T) - if lex.c != '!': - raise generateError[T](lex, "Tag shorthand must start with a '!'") - startToken[T](lex) - lex.buf.add(lex.c) - lex.advance(T) - - if lex.c in spaceOrLineEnd: discard - else: - while lex.c != '!': - case lex.c - of 'a' .. 'z', 'A' .. 'Z', '0' .. '9', '-': - lex.buf.add(lex.c) - lex.advance(T) - else: raise generateError[T](lex, "Illegal character in tag shorthand") - lex.buf.add(lex.c) - lex.advance(T) - if lex.c notin spaceOrLineEnd: - raise generateError[T](lex, "Missing space after tag shorthand") - lex.cur = ltTagShorthand - result = true - lex.nextState = tagUri[T] - -proc tagUri[T](lex: YamlLexer): bool = - debug("lex: tagUri") - while lex.c in space: lex.advance(T) - startToken[T](lex) - if lex.c == '!': - lex.buf.add(lex.c) - lex.advance(T) - while true: - case lex.c - of spaceOrLineEnd: break - of 'a' .. 'z', 'A' .. 'Z', '0' .. '9', '#', ';', '/', '?', ':', '@', '&', - '-', '=', '+', '$', ',', '_', '.', '~', '*', '\'', '(', ')': - lex.buf.add(lex.c) - lex.advance(T) - else: raise generateError[T](lex, "Invalid character in tag uri: " & - escape("" & lex.c)) - lex.cur = ltTagUri - result = true - lex.nextState = expectLineEnd[T] - -proc unknownDirParams[T](lex: YamlLexer): bool = - debug("lex: unknownDirParams") - while lex.c in space: lex.advance(T) - startToken[T](lex) - while lex.c notin lineEnd + {'#'}: - lex.buf.add(lex.c) - lex.advance(T) - lex.cur = ltUnknownDirectiveParams - result = true - lex.nextState = expectLineEnd[T] - -proc expectLineEnd[T](lex: YamlLexer): bool = - debug("lex: expectLineEnd") - result = false - while lex.c in space: lex.advance(T) - while true: - case lex.c - of '#': - lex.advance(T) - while lex.c notin lineEnd: lex.advance(T) - of EndOfFile: - lex.nextState = streamEnd[T] - break - of '\l': - lex.lexLF(T) - lex.nextState = lex.lineStartState - break - of '\c': - lex.lexCR(T) - lex.nextState = lex.lineStartState - break - else: - raise generateError[T](lex, - "Unexpected character (expected line end): " & escape("" & lex.c)) - -proc possibleDirectivesEnd[T](lex: YamlLexer): bool = - debug("lex: possibleDirectivesEnd") - lex.indentation = 0 - lex.lineStartState = lex.insideDocImpl # could be insideDoc[T] - lex.advance(T) - if lex.c == '-': - lex.advance(T) - if lex.c == '-': - lex.advance(T) - if lex.c in spaceOrLineEnd: - lex.cur = ltDirectivesEnd - while lex.c in space: lex.advance(T) - lex.nextState = lex.insideLineImpl - return true - lex.consumeNewlines() - lex.buf.add('-') - else: lex.consumeNewlines() - lex.buf.add('-') - elif lex.c in spaceOrLineEnd: - lex.cur = ltIndentation - lex.nextState = afterSeqInd[T] - return true - else: lex.consumeNewlines() - lex.buf.add('-') - lex.cur = ltIndentation - lex.nextState = plainScalarPart[T] - result = true - -proc afterSeqInd[T](lex: YamlLexer): bool = - result = true - lex.cur = ltSeqItemInd - if lex.c notin lineEnd: - lex.advance(T) - while lex.c in space: lex.advance(T) - lex.nextState = lex.insideLineImpl - -proc possibleDocumentEnd[T](lex: YamlLexer): bool = - debug("lex: possibleDocumentEnd") - lex.advance(T) - if lex.c == '.': - lex.advance(T) - if lex.c == '.': - lex.advance(T) - if lex.c in spaceOrLineEnd: - lex.cur = ltDocumentEnd - lex.nextState = expectLineEnd[T] - lex.lineStartState = lex.outsideDocImpl - return true - lex.consumeNewlines() - lex.buf.add('.') - else: lex.consumeNewlines() - lex.buf.add('.') - else: lex.consumeNewlines() - lex.buf.add('.') - lex.nextState = plainScalarPart[T] - result = false - -proc outsideDoc[T](lex: YamlLexer): bool = - debug("lex: outsideDoc") - startToken[T](lex) - case lex.c - of '%': - lex.advance(T) - directiveName[T](lex) - case lex.buf - of "YAML": - lex.cur = ltYamlDirective - lex.buf.setLen(0) - lex.nextState = yamlVersion[T] - of "TAG": - lex.buf.setLen(0) - lex.cur = ltTagDirective - lex.nextState = tagShorthand[T] - else: - lex.cur = ltUnknownDirective - lex.nextState = unknownDirParams[T] - return true - of '-': - lex.nextState = possibleDirectivesEnd[T] - return false - of '.': - lex.indentation = 0 - if possibleDocumentEnd[T](lex): return true - of spaceOrLineEnd + {'#'}: - lex.indentation = 0 - while lex.c == ' ': - lex.indentation.inc() - lex.advance(T) - if lex.c in spaceOrLineEnd + {'#'}: - lex.nextState = expectLineEnd[T] - return false - lex.nextState = insideLine[T] - else: - lex.indentation = 0 - lex.nextState = insideLine[T] - lex.lineStartState = insideDoc[T] - lex.cur = ltIndentation - result = true - -proc insideDoc[T](lex: YamlLexer): bool = - debug("lex: insideDoc") - startToken[T](lex) - lex.indentation = 0 - case lex.c - of '-': - lex.nextState = possibleDirectivesEnd[T] - return false - of '.': lex.nextState = possibleDocumentEnd[T] - of spaceOrLineEnd: - while lex.c == ' ': - lex.indentation.inc() - lex.advance(T) - while lex.c in space: lex.advance(T) - case lex.c - of lineEnd: - lex.cur = ltEmptyLine - lex.nextState = expectLineEnd[T] - return true - else: - lex.nextState = lex.inlineState - else: lex.nextState = lex.inlineState - lex.cur = ltIndentation - result = true - -proc insideFlow[T](lex: YamlLexer): bool = - debug("lex: insideFlow") - startToken[T](lex) - while lex.c in space: lex.advance(T) - if lex.c in lineEnd + {'#'}: - lex.cur = ltEmptyLine - lex.nextState = expectLineEnd[T] - return true - lex.nextState = insideLine[T] - result = false - -proc possibleIndicatorChar[T](lex: YamlLexer, indicator: LexerToken, - jsonContext: bool = false): bool = - startToken[T](lex) - if not(jsonContext) and lex.nextIsPlainSafe(T, lex.inFlow): - lex.consumeNewlines() - lex.nextState = plainScalarPart[T] - result = false - else: - lex.cur = indicator - result = true - lex.advance(T) - while lex.c in space: lex.advance(T) - if lex.c in lineEnd: - lex.nextState = expectLineEnd[T] - -proc flowIndicator[T](lex: YamlLexer, indicator: LexerToken): bool {.inline.} = - startToken[T](lex) - lex.cur = indicator - lex.advance(T) - while lex.c in space: lex.advance(T) - if lex.c in lineEnd + {'#'}: - lex.nextState = expectLineEnd[T] - result = true - -proc addMultiple(s: var string, c: char, num: int) {.raises: [], inline.} = - for i in 1..num: s.add(c) - -proc processQuotedWhitespace[T](lex: YamlLexer, newlines: var int) = - block outer: - let beforeSpace = lex.buf.len - while true: - case lex.c - of ' ', '\t': lex.buf.add(lex.c) - of '\l': - lex.lexLF(T) - break - of '\c': - lex.lexCR(T) - break - else: break outer - lex.advance(T) - lex.buf.setLen(beforeSpace) - while true: - case lex.c - of ' ', '\t': discard - of '\l': - lex.lexLF(T) - newlines.inc() - continue - of '\c': - lex.lexCR(T) - newlines.inc() - continue - else: - if newlines == 0: discard - elif newlines == 1: lex.buf.add(' ') - else: lex.buf.addMultiple('\l', newlines - 1) - break - lex.advance(T) - -proc singleQuotedScalar[T](lex: YamlLexer) = - debug("lex: singleQuotedScalar") - startToken[T](lex) - when defined(yamlScalarRepInd): lex.scalarKind = skSingleQuoted - lex.advance(T) - while true: - case lex.c - of '\'': - lex.advance(T) - if lex.c == '\'': lex.buf.add('\'') - else: break - of EndOfFile: raise generateError[T](lex, "Unfinished single quoted string") - of '\l', '\c', '\t', ' ': - var newlines = 1 - processQuotedWhitespace[T](lex, newlines) - continue - else: lex.buf.add(lex.c) - lex.advance(T) - while lex.c in space: lex.advance(T) - if lex.c in lineEnd + {'#'}: - lex.nextState = expectLineEnd[T] - -proc unicodeSequence[T](lex: YamlLexer, length: int) = - debug("lex: unicodeSequence") - var unicodeChar = 0.int - for i in countup(0, length - 1): - lex.advance(T) - let digitPosition = length - i - 1 - case lex.c - of EndOFFile, '\l', '\c': - raise generateError[T](lex, "Unfinished unicode escape sequence") - of '0' .. '9': - unicodeChar = unicodechar or (int(lex.c) - 0x30) shl (digitPosition * 4) - of 'A' .. 'F': - unicodeChar = unicodechar or (int(lex.c) - 0x37) shl (digitPosition * 4) - of 'a' .. 'f': - unicodeChar = unicodechar or (int(lex.c) - 0x57) shl (digitPosition * 4) - else: - raise generateError[T](lex, - "Invalid character in unicode escape sequence: " & - escape("" & lex.c)) - lex.buf.add(toUTF8(Rune(unicodeChar))) - -proc doubleQuotedScalar[T](lex: YamlLexer) = - debug("lex: doubleQuotedScalar") - startToken[T](lex) - when defined(yamlScalarRepInd): lex.scalarKind = skDoubleQuoted - lex.advance(T) - while true: - case lex.c - of EndOfFile: - raise generateError[T](lex, "Unfinished double quoted string") - of '\\': - lex.advance(T) - case lex.c - of EndOfFile: - raise generateError[T](lex, "Unfinished escape sequence") - of '0': lex.buf.add('\0') - of 'a': lex.buf.add('\x07') - of 'b': lex.buf.add('\x08') - of '\t', 't': lex.buf.add('\t') - of 'n': lex.buf.add('\l') - of 'v': lex.buf.add('\v') - of 'f': lex.buf.add('\f') - of 'r': lex.buf.add('\c') - of 'e': lex.buf.add('\e') - of ' ': lex.buf.add(' ') - of '"': lex.buf.add('"') - of '/': lex.buf.add('/') - of '\\': lex.buf.add('\\') - of 'N': lex.buf.add(UTF8NextLine) - of '_': lex.buf.add(UTF8NonBreakingSpace) - of 'L': lex.buf.add(UTF8LineSeparator) - of 'P': lex.buf.add(UTF8ParagraphSeparator) - of 'x': unicodeSequence[T](lex, 2) - of 'u': unicodeSequence[T](lex, 4) - of 'U': unicodeSequence[T](lex, 8) - of '\l', '\c': - var newlines = 0 - processQuotedWhitespace[T](lex, newlines) - continue - else: raise generateError[T](lex, "Illegal character in escape sequence") - of '"': - lex.advance(T) - break - of '\l', '\c', '\t', ' ': - var newlines = 1 - processQuotedWhitespace[T](lex, newlines) - continue - else: lex.buf.add(lex.c) - lex.advance(T) - while lex.c in space: lex.advance(T) - if lex.c in lineEnd + {'#'}: - lex.nextState = expectLineEnd[T] - -proc insideLine[T](lex: YamlLexer): bool = - debug("lex: insideLine") - case lex.c - of ':': - result = possibleIndicatorChar[T](lex, ltMapValInd, - lex.inFlow and - lex.cur in [ltBraceClose, ltBracketClose, ltQuotedScalar]) - of '?': result = possibleIndicatorChar[T](lex, ltMapKeyInd) - of '-': result = possibleIndicatorChar[T](lex, ltSeqItemInd) - of lineEnd + {'#'}: - result = false - lex.nextState = expectLineEnd[T] - of '\"': - doubleQuotedScalar[T](lex) - lex.cur = ltQuotedScalar - result = true - of '\'': - singleQuotedScalar[T](lex) - lex.cur = ltQuotedScalar - result = true - of '>', '|': - startToken[T](lex) - lex.consumeNewlines() - if lex.inFlow: lex.nextState = plainScalarPart[T] - else: lex.nextState = blockScalarHeader[T] - result = false - of '{': result = flowIndicator[T](lex, ltBraceOpen) - of '}': result = flowIndicator[T](lex, ltBraceClose) - of '[': result = flowIndicator[T](lex, ltBracketOpen) - of ']': result = flowIndicator[T](lex, ltBracketClose) - of ',': result = flowIndicator[T](lex, ltComma) - of '!': - lex.nextState = tagHandle[T] - result = false - of '&': - lex.nextState = anchor[T] - result = false - of '*': - lex.nextState = alias[T] - result = false - of '@', '`': - raise generateError[T](lex, - "Reserved characters cannot start a plain scalar") - else: - startToken[T](lex) - lex.consumeNewlines() - lex.nextState = plainScalarPart[T] - result = false - -proc plainScalarPart[T](lex: YamlLexer): bool = - debug("lex: plainScalarPart") - block outer: - while true: - lex.buf.add(lex.c) - lex.advance(T) - case lex.c - of space: - let lenBeforeSpace = lex.buf.len() - while true: - lex.buf.add(lex.c) - lex.advance(T) - case lex.c - of lineEnd + {'#'}: - lex.buf.setLen(lenBeforeSpace) - lex.nextState = expectLineEnd[T] - break outer - of ':': - if lex.nextIsPlainSafe(T, lex.inFlow): break - else: - lex.buf.setLen(lenBeforeSpace) - lex.nextState = lex.insideLineImpl # could be insideLine[T] - break outer - of flowIndicators: - if lex.inFlow: - lex.buf.setLen(lenBeforeSpace) - lex.nextState = lex.insideLineImpl # could be insideLine[T] - break outer - else: - lex.buf.add(lex.c) - lex.advance(T) - break - of space: discard - else: break - of lineEnd: - lex.nextState = expectLineEnd[T] - break - of flowIndicators: - if lex.inFlow: - lex.nextState = lex.insideLineImpl # could be insideLine[T] - break - of ':': - if not lex.nextIsPlainSafe(T, lex.inFlow): - lex.nextState = lex.insideLineImpl # could be insideLine[T] - break outer - else: discard - lex.cur = ltScalarPart - result = true - -proc blockScalarHeader[T](lex: YamlLexer): bool = - debug("lex: blockScalarHeader") - lex.chomp = ctClip - lex.blockScalarIndent = UnknownIndentation - lex.folded = lex.c == '>' - when defined(yamlScalarRepInd): - lex.scalarKind = if lex.folded: skFolded else: skLiteral - startToken[T](lex) - while true: - lex.advance(T) - case lex.c - of '+': - if lex.chomp != ctClip: - raise generateError[T](lex, "Only one chomping indicator is allowed") - lex.chomp = ctKeep - of '-': - if lex.chomp != ctClip: - raise generateError[T](lex, "Only one chomping indicator is allowed") - lex.chomp = ctStrip - of '1'..'9': - if lex.blockScalarIndent != UnknownIndentation: - raise generateError[T](lex, "Only one indentation indicator is allowed") - lex.blockScalarIndent = ord(lex.c) - ord('\x30') - of spaceOrLineEnd: break - else: - raise generateError[T](lex, - "Illegal character in block scalar header: '" & escape("" & lex.c) & - '\'') - lex.nextState = expectLineEnd[T] - lex.lineStartState = blockScalar[T] - lex.cur = ltBlockScalarHeader - result = true - -proc blockScalarAfterLineStart[T](lex: YamlLexer, - recentWasMoreIndented: var bool): bool = - if lex.indentation < lex.blockScalarIndent: - lex.nextState = indentationAfterBlockScalar[T] - return false - - if lex.folded and not recentWasMoreIndented: lex.consumeNewlines() - else: - recentWasMoreIndented = false - lex.buf.add(repeat('\l', lex.newlines)) - lex.newlines = 0 - result = true - -proc blockScalarLineStart[T](lex: YamlLexer, recentWasMoreIndented: var bool): - bool = - while true: - case lex.c - of '-': - if lex.indentation < lex.blockScalarIndent: - lex.nextState = indentationAfterBlockScalar[T] - return false - discard possibleDirectivesEnd[T](lex) - case lex.cur - of ltDirectivesEnd: - lex.nextState = dirEndAfterBlockScalar[T] - return false - of ltIndentation: - if lex.nextState == afterSeqInd[T]: - lex.consumeNewlines() - lex.buf.add("- ") - else: discard - break - of '.': - if lex.indentation < lex.blockScalarIndent: - lex.nextState = indentationAfterBlockScalar[T] - return false - if possibleDocumentEnd[T](lex): - lex.nextState = docEndAfterBlockScalar[T] - return false - break - of spaceOrLineEnd: - while lex.c == ' ' and lex.indentation < lex.blockScalarIndent: - lex.indentation.inc() - lex.advance(T) - case lex.c - of '\l': - lex.newlines.inc() - lex.lexLF(T) - lex.indentation = 0 - of '\c': - lex.newlines.inc() - lex.lexCR(T) - lex.indentation = 0 - of EndOfFile: - lex.nextState = streamEnd[T] - return false - of ' ', '\t': - recentWasMoreIndented = true - lex.buf.add(repeat('\l', lex.newlines)) - lex.newlines = 0 - return true - else: break - else: break - result = blockScalarAfterLineStart[T](lex, recentWasMoreIndented) - -proc blockScalar[T](lex: YamlLexer): bool = - debug("lex: blockScalar") - block outer: - var recentWasMoreIndented = true - if lex.blockScalarIndent == UnknownIndentation: - while true: - lex.blockScalarIndent = 0 - while lex.c == ' ': - lex.blockScalarIndent.inc() - lex.advance(T) - case lex.c - of '\l': - lex.lexLF(T) - lex.newlines.inc() - of '\c': - lex.lexCR(T) - lex.newlines.inc() - of EndOfFile: - lex.nextState = streamEnd[T] - break outer - else: - if lex.blockScalarIndent <= lex.indentation: - lex.indentation = lex.blockScalarIndent - lex.nextState = indentationAfterBlockScalar[T] - break outer - lex.indentation = lex.blockScalarIndent - break - else: - lex.blockScalarIndent += lex.indentation - lex.indentation = 0 - if lex.c notin {'.', '-'} or lex.indentation == 0: - if not blockScalarLineStart[T](lex, recentWasMoreIndented): break outer - else: - if not blockScalarAfterLineStart[T](lex, recentWasMoreIndented): - break outer - while true: - while lex.c notin lineEnd: - 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 - of ctClip: - if lex.buf.len > 0: lex.buf.add('\l') - of ctKeep: lex.buf.add(repeat('\l', lex.newlines)) - lex.newlines = 0 - lex.lineStartState = insideDoc[T] - lex.cur = ltBlockScalar - result = true - -proc indentationAfterBlockScalar[T](lex: YamlLexer): bool = - if lex.indentation == 0: - lex.nextState = lex.insideDocImpl - elif lex.c == '#': - lex.nextState = expectLineEnd[T] - result = false - else: - lex.cur = ltIndentation - result = true - lex.nextState = lex.insideLineImpl - -proc dirEndAfterBlockScalar[T](lex: YamlLexer): bool = - lex.cur = ltDirectivesEnd - 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] - lex.lineStartState = lex.outsideDocImpl - result = true - -proc byteSequence[T](lex: YamlLexer) = - debug("lex: byteSequence") - var charCode = 0.int8 - for i in 0 .. 1: - lex.advance(T) - let digitPosition = int8(1 - i) - case lex.c - of EndOfFile, '\l', 'r': - raise generateError[T](lex, "Unfinished octet escape sequence") - of '0' .. '9': - charCode = charCode or (int8(lex.c) - 0x30.int8) shl (digitPosition * 4) - of 'A' .. 'F': - charCode = charCode or (int8(lex.c) - 0x37.int8) shl (digitPosition * 4) - of 'a' .. 'f': - charCode = charCode or (int8(lex.c) - 0x57.int8) shl (digitPosition * 4) - else: - raise generateError[T](lex, "Invalid character in octet escape sequence") - lex.buf.add(char(charCode)) - -proc tagHandle[T](lex: YamlLexer): bool = - debug("lex: tagHandle") - startToken[T](lex) - lex.advance(T) - if lex.c == '<': - lex.advance(T) - if lex.c == '!': - lex.buf.add('!') - lex.advance(T) - while true: - case lex.c - of spaceOrLineEnd: raise generateError[T](lex, "Unclosed verbatim tag") - of '%': byteSequence[T](lex) - of uriChars + {','}: lex.buf.add(lex.c) - of '>': break - else: raise generateError[T](lex, "Illegal character in verbatim tag") - lex.advance(T) - lex.advance(T) - lex.cur = ltLiteralTag - else: - lex.shorthandEnd = 0 - let m = lex.mark(T) - lex.buf.add('!') - while true: - case lex.c - of spaceOrLineEnd: break - of '!': - if lex.shorthandEnd != 0: - raise generateError[T](lex, "Illegal character in tag suffix") - lex.shorthandEnd = lex.afterMark(T, m) + 1 - lex.buf.add('!') - of ',': - if lex.shorthandEnd > 0: break # ',' after shorthand is flow indicator - lex.buf.add(',') - of '%': - if lex.shorthandEnd == 0: - raise generateError[T](lex, "Illegal character in tag handle") - byteSequence[T](lex) - of uriChars: lex.buf.add(lex.c) - else: raise generateError[T](lex, "Illegal character in tag handle") - lex.advance(T) - lex.cur = ltTagHandle - while lex.c in space: lex.advance(T) - if lex.c in lineEnd: lex.nextState = expectLineEnd[T] - else: lex.nextState = lex.insideLineImpl # could be insideLine[T] - result = true - -proc anchorName[T](lex: YamlLexer) = - debug("lex: anchorName") - startToken[T](lex) - while true: - lex.advance(T) - case lex.c - of spaceOrLineEnd, '[', ']', '{', '}', ',': break - else: lex.buf.add(lex.c) - while lex.c in space: lex.advance(T) - if lex.c in lineEnd: lex.nextState = expectLineEnd[T] - else: lex.nextState = lex.insideLineImpl # could be insideLine[T] - -proc anchor[T](lex: YamlLexer): bool = - debug("lex: anchor") - anchorName[T](lex) - lex.cur = ltAnchor - result = true - -proc alias[T](lex: YamlLexer): bool = - debug("lex: alias") - anchorName[T](lex) - lex.cur = ltAlias - result = true - -proc streamEnd[T](lex: YamlLexer): bool = - debug("lex: streamEnd") - startToken[T](lex) - lex.cur = ltStreamEnd - result = true - -proc tokenLine[T](lex: YamlLexer, pos: tuple[line, column: int], marker: bool): - string = - result = lex.lineWithMarker(pos, T, marker) - -proc searchColon[T](lex: YamlLexer): bool = - var flowDepth = if lex.cur in [ltBraceOpen, ltBracketOpen]: 1 else: 0 - let start = lex.getPos(T) - var - peek = start - recentAllowsAdjacent = lex.cur == ltQuotedScalar - result = false - - proc skipPlainScalarContent(lex: YamlLexer) {.closure.} = - while true: - inc(peek) - case lex.at(T, peek) - of ']', '}', ',': - if flowDepth > 0 or lex.inFlow: break - of '#': - if lex.at(T, peek - 1) in space: break - of ':': - if lex.at(T, peek + 1) in spaceOrLineEnd: break - of lineEnd: break - else: discard - - while peek < start + 1024: - case lex.at(T, peek) - of ':': - if flowDepth == 0: - if recentAllowsAdjacent or lex.at(T, peek + 1) in spaceOrLineEnd: - result = true - break - lex.skipPlainScalarContent() - continue - of '{', '[': inc(flowDepth) - of '}', ']': - dec(flowDepth) - if flowDepth < 0: - if lex.inFlow: break - else: - flowDepth = 0 - lex.skipPlainScalarContent() - continue - recentAllowsAdjacent = true - of lineEnd: break - of '"': - while true: - inc(peek) - case lex.at(T, peek) - of lineEnd, '"': break - of '\\': inc(peek) - else: discard - if lex.at(T, peek) != '"': break - recentAllowsAdjacent = true - of '\'': - inc(peek) - while lex.at(T, peek) notin {'\''} + lineEnd: inc(peek) - if lex.at(T, peek) != '\'': break - recentAllowsAdjacent = true - of '?', ',': - if flowDepth == 0: break - of '#': - if lex.at(T, peek - 1) in space: break - lex.skipPlainScalarContent() - continue - of '&', '*', '!': - inc(peek) - while lex.at(T, peek) notin spaceOrLineEnd: inc(peek) - recentAllowsAdjacent = false - continue - of space: discard - else: - lex.skipPlainScalarContent() - continue - inc(peek) - -# interface - -proc init*[T](lex: YamlLexer) = - lex.nextState = outsideDoc[T] - lex.lineStartState = outsideDoc[T] - lex.inlineState = insideLine[T] - lex.insideLineImpl = insideLine[T] - lex.insideDocImpl = insideDoc[T] - lex.insideFlowImpl = insideFlow[T] - lex.outsideDocImpl = outsideDoc[T] # only needed because of compiler checks - lex.tokenLineGetter = tokenLine[T] - lex.searchColonImpl = searchColon[T] - -when not defined(JS): - proc newYamlLexer*(source: Stream): YamlLexer {.raises: [YamlLexerError].} = - let blSource = new(BaseLexer) - try: blSource[].open(source) - except: - var e = newException(YamlLexerError, - "Could not open stream for reading:\n" & getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - GC_ref(blSource) - new(result, proc(x: ref YamlLexerObj) {.nimcall.} = - GC_unref(cast[ref BaseLexer](x.source)) - ) - result[] = YamlLexerObj(source: cast[pointer](blSource), inFlow: false, - buf: "", c: blSource[].buf[blSource[].bufpos], newlines: 0, - folded: true) - init[BaseLexer](result) - -proc newYamlLexer*(source: string, startAt: int = 0): YamlLexer - {.raises: [].} = - # append a `\0` at the very end to work around null terminator being - # inaccessible - let sourceNull = source & '\0' - when defined(JS): - let sSource = StringSource(pos: startAt, lineStart: startAt, line: 1, - src: sourceNull) - result = YamlLexer(buf: "", sSource: sSource, - inFlow: false, c: sSource.src[startAt], newlines: 0, folded: true) - else: - let sSource = new(StringSource) - sSource[] = StringSource(pos: startAt, lineStart: startAt, line: 1, - src: sourceNull) - GC_ref(sSource) - new(result, proc(x: ref YamlLexerObj) {.nimcall.} = - GC_unref(cast[ref StringSource](x.source)) - ) - result[] = YamlLexerObj(buf: "", source: cast[pointer](sSource), - inFlow: false, c: sSource.src[startAt], newlines: 0, folded: true) - init[StringSource](result) - -proc next*(lex: YamlLexer) = - while not lex.nextState(lex): discard - debug("lexer -> " & $lex.cur) - -proc setFlow*(lex: YamlLexer, value: bool) = - lex.inFlow = value - # in flow mode, no indentation tokens are generated because they are not - # necessary. actually, the lexer will behave wrongly if we do that, because - # adjacent values need to check if the preceding token was a JSON value, and - # if indentation tokens are generated, that information is not available. - # therefore, we use insideFlow instead of insideDoc in flow mode. another - # reason is that this would erratically check for document markers (---, ...) - # which are simply scalars in flow mode. - if value: lex.lineStartState = lex.insideFlowImpl - else: lex.lineStartState = lex.insideDocImpl - -proc endBlockScalar*(lex: YamlLexer) = - lex.inlineState = lex.insideLineImpl - lex.nextState = lex.insideLineImpl - lex.folded = true - -proc getTokenLine*(lex: YamlLexer, marker: bool = true): string = - result = lex.tokenLineGetter(lex, lex.curStartPos, marker) - -proc getTokenLine*(lex: YamlLexer, pos: tuple[line, column: int], - marker: bool = true): string = - result = lex.tokenLineGetter(lex, pos, marker) - -proc isImplicitKeyStart*(lex: YamlLexer): bool = - result = lex.searchColonImpl(lex) diff --git a/lib/yaml-legacy/yaml/serialization.nim b/lib/yaml-legacy/yaml/serialization.nim deleted file mode 100644 index 47ac7a1..0000000 --- a/lib/yaml-legacy/yaml/serialization.nim +++ /dev/null @@ -1,1463 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 - 2020 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ========================= -## Module yaml.serialization -## ========================= -## -## This is the most high-level API of NimYAML. It enables you to parse YAML -## character streams directly into native YAML types and vice versa. It builds -## on top of the low-level parser and presenter APIs. -## -## It is possible to define custom construction and serialization procs for any -## type. Please consult the serialization guide on the NimYAML website for more -## information. - -import tables, typetraits, strutils, macros, streams, times, parseutils, options -import parser, taglib, presenter, stream, private/internal, hints, annotations -export stream, macros, annotations, options - # *something* in here needs externally visible `==`(x,y: AnchorId), - # but I cannot figure out what. binding it would be the better option. - -type - SerializationContext* = ref object - ## Context information for the process of serializing YAML from Nim values. - when not defined(JS): - refs*: Table[pointer, AnchorId] # `pointer` does not work with JS - style: AnchorStyle - nextAnchorId*: AnchorId - put*: proc(e: YamlStreamEvent) {.raises: [], closure.} - - ConstructionContext* = ref object - ## Context information for the process of constructing Nim values from YAML. - when not defined(JS): - refs*: Table[AnchorId, pointer] - - YamlConstructionError* = object of YamlLoadingError - ## Exception that may be raised when constructing data objects from a - ## `YamlStream <#YamlStream>`_. The fields ``line``, ``column`` and - ## ``lineContent`` are only available if the costructing proc also does - ## parsing, because otherwise this information is not available to the - ## costruction proc. - -# forward declares - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var T) - {.raises: [YamlConstructionError, YamlStreamError].} - ## Constructs an arbitrary Nim value from a part of a YAML stream. - ## The stream will advance until after the finishing token that was used - ## for constructing the value. The ``ConstructionContext`` is needed for - ## potential child objects which may be refs. - -proc constructChild*(s: var YamlStream, c: ConstructionContext, - result: var string) - {.raises: [YamlConstructionError, YamlStreamError].} - ## Constructs a Nim value that is a string from a part of a YAML stream. - ## This specialization takes care of possible nil strings. - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var seq[T]) - {.raises: [YamlConstructionError, YamlStreamError].} - ## Constructs a Nim value that is a string from a part of a YAML stream. - ## This specialization takes care of possible nil seqs. - -proc constructChild*[O](s: var YamlStream, c: ConstructionContext, - result: var ref O) - {.raises: [YamlConstructionError, YamlStreamError].} - ## Constructs an arbitrary Nim value from a part of a YAML stream. - ## The stream will advance until after the finishing token that was used - ## for constructing the value. The object may be constructed from an alias - ## node which will be resolved using the ``ConstructionContext``. - -proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext) - {.raises: [].} - ## Represents an arbitrary Nim reference value as YAML object. The object - ## may be represented as alias node if it is already present in the - ## ``SerializationContext``. - -proc representChild*(value: string, ts: TagStyle, c: SerializationContext) - {.inline, raises: [].} - ## Represents a Nim string. Supports nil strings. - -proc representChild*[O](value: O, ts: TagStyle, c: SerializationContext) - ## Represents an arbitrary Nim object as YAML object. - -proc newConstructionContext*(): ConstructionContext = - new(result) - when defined(JS): - {.emit: [result, """.refs = new Map();"""].} - else: - result.refs = initTable[AnchorId, pointer]() - -proc newSerializationContext*(s: AnchorStyle, - putImpl: proc(e: YamlStreamEvent) {.raises: [], closure.}): - SerializationContext = - result = SerializationContext(style: s, nextAnchorId: 0.AnchorId, - put: putImpl) - when defined(JS): - {.emit: [result, """.refs = new Map();"""].} - else: result.refs = initTable[pointer, AnchorId]() - -template presentTag*(t: typedesc, ts: TagStyle): TagId = - ## Get the TagId that represents the given type in the given style - if ts == tsNone: yTagQuestionMark else: yamlTag(t) - -proc lazyLoadTag(uri: string): TagId {.inline, raises: [].} = - try: result = serializationTagLibrary.tags[uri] - except KeyError: result = serializationTagLibrary.registerUri(uri) - -proc safeTagUri(id: TagId): string {.raises: [].} = - try: - var - uri = serializationTagLibrary.uri(id) - i = 0 - # '!' is not allowed inside a tag handle - if uri.len > 0 and uri[0] == '!': uri = uri[1..^1] - # ',' is not allowed after a tag handle in the suffix because it's a flow - # indicator - for c in uri.mitems(): - if c == ',': c = ';' - inc(i) - return uri - except KeyError: internalError("Unexpected KeyError for TagId " & $id) - -proc constructionError(s: YamlStream, msg: string): ref YamlConstructionError = - result = newException(YamlConstructionError, msg) - if not s.getLastTokenContext(result.line, result.column, result.lineContent): - (result.line, result.column) = (-1, -1) - result.lineContent = "" - -template constructScalarItem*(s: var YamlStream, i: untyped, - t: typedesc, content: untyped) = - ## Helper template for implementing ``constructObject`` for types that - ## are constructed from a scalar. ``i`` is the identifier that holds - ## the scalar as ``YamlStreamEvent`` in the content. Exceptions raised in - ## the content will be automatically catched and wrapped in - ## ``YamlConstructionError``, which will then be raised. - bind constructionError - let i = s.next() - if i.kind != yamlScalar: - raise constructionError(s, "Expected scalar") - try: content - except YamlConstructionError as e: raise e - except Exception: - var e = constructionError(s, - "Cannot construct to " & name(t) & ": " & item.scalarContent & - "; error: " & getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -proc yamlTag*(T: typedesc[string]): TagId {.inline, noSideEffect, raises: [].} = - yTagString - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var string) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## costructs a string from a YAML scalar - constructScalarItem(s, item, string): - result = item.scalarContent - -proc representObject*(value: string, ts: TagStyle, - c: SerializationContext, tag: TagId) {.raises: [].} = - ## represents a string as YAML scalar - c.put(scalarEvent(value, tag, yAnchorNone)) - -proc parseHex[T: int8|int16|int32|int64|uint8|uint16|uint32|uint64]( - s: YamlStream, val: string): T = - result = 0 - for i in 2.. 1 and item.scalarContent[1] in {'x', 'X' }: - result = parseHex[T](s, item.scalarContent) - elif item.scalarContent[0] == '0' and item.scalarContent.len > 1 and item.scalarContent[1] in {'o', 'O'}: - result = parseOctal[T](s, item.scalarContent) - else: - let nInt = parseBiggestInt(item.scalarContent) - if nInt <= T.high: - # make sure we don't produce a range error - result = T(nInt) - else: - raise s.constructionError("Cannot construct int; out of range: " & - $nInt & " for type " & T.name & " with max of: " & $T.high) - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var int) - {.raises: [YamlConstructionError, YamlStreamError], inline.} = - ## constructs an integer of architecture-defined length by loading it into - ## int32 and then converting it. - var i32Result: int32 - constructObject(s, c, i32Result) - result = int(i32Result) - -proc representObject*[T: int8|int16|int32|int64](value: T, ts: TagStyle, - c: SerializationContext, tag: TagId) {.raises: [].} = - ## represents an integer value as YAML scalar - c.put(scalarEvent($value, tag, yAnchorNone)) - -proc representObject*(value: int, tagStyle: TagStyle, - c: SerializationContext, tag: TagId) - {.raises: [YamlStreamError], inline.}= - ## represent an integer of architecture-defined length by casting it to int32. - ## on 64-bit systems, this may cause a RangeError. - - # currently, sizeof(int) is at least sizeof(int32). - try: c.put(scalarEvent($int32(value), tag, yAnchorNone)) - except RangeError: - var e = newException(YamlStreamError, getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -when defined(JS): - type DefiniteUIntTypes = uint8 | uint16 | uint32 -else: - type DefiniteUIntTypes = uint8 | uint16 | uint32 | uint64 - -proc constructObject*[T: DefiniteUIntTypes]( - s: var YamlStream, c: ConstructionContext, result: var T) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## construct an unsigned integer value from a YAML scalar - constructScalarItem(s, item, T): - if item.scalarContent[0] == '0' and item.scalarContent[1] in {'x', 'X'}: - result = parseHex[T](s, item.scalarContent) - elif item.scalarContent[0] == '0' and item.scalarContent[1] in {'o', 'O'}: - result = parseOctal[T](s, item.scalarContent) - else: result = T(parseBiggestUInt(item.scalarContent)) - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var uint) - {.raises: [YamlConstructionError, YamlStreamError], inline.} = - ## represent an unsigned integer of architecture-defined length by loading it - ## into uint32 and then converting it. - var u32Result: uint32 - constructObject(s, c, u32Result) - result= uint(u32Result) - -when defined(JS): - # TODO: this is a dirty hack and may lead to overflows! - proc `$`(x: uint8|uint16|uint32|uint64|uint): string = - result = $BiggestInt(x) - -proc representObject*[T: uint8|uint16|uint32|uint64](value: T, ts: TagStyle, - c: SerializationContext, tag: TagId) {.raises: [].} = - ## represents an unsigned integer value as YAML scalar - c.put(scalarEvent($value, tag, yAnchorNone)) - -proc representObject*(value: uint, ts: TagStyle, c: SerializationContext, - tag: TagId) {.raises: [YamlStreamError], inline.} = - ## represent an unsigned integer of architecture-defined length by casting it - ## to int32. on 64-bit systems, this may cause a RangeError. - try: c.put(scalarEvent($uint32(value), tag, yAnchorNone)) - except RangeError: - var e = newException(YamlStreamError, getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -proc constructObject*[T: float|float32|float64]( - s: var YamlStream, c: ConstructionContext, result: var T) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## construct a float value from a YAML scalar - constructScalarItem(s, item, T): - let hint = guessType(item.scalarContent) - case hint - of yTypeFloat: - discard parseBiggestFloat(item.scalarContent, result) - of yTypeInteger: - discard parseBiggestFloat(item.scalarContent, result) - of yTypeFloatInf: - if item.scalarContent[0] == '-': result = NegInf - else: result = Inf - of yTypeFloatNaN: result = NaN - else: - raise s.constructionError("Cannot construct to float: " & - escape(item.scalarContent)) - -proc representObject*[T: float|float32|float64](value: T, ts: TagStyle, - c: SerializationContext, tag: TagId) {.raises: [].} = - ## represents a float value as YAML scalar - case value - of Inf: c.put(scalarEvent(".inf", tag)) - of NegInf: c.put(scalarEvent("-.inf", tag)) - of NaN: c.put(scalarEvent(".nan", tag)) - else: c.put(scalarEvent($value, tag)) - -proc yamlTag*(T: typedesc[bool]): TagId {.inline, raises: [].} = yTagBoolean - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var bool) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a bool value from a YAML scalar - constructScalarItem(s, item, bool): - case guessType(item.scalarContent) - of yTypeBoolTrue: result = true - of yTypeBoolFalse: result = false - else: - raise s.constructionError("Cannot construct to bool: " & - escape(item.scalarContent)) - -proc representObject*(value: bool, ts: TagStyle, c: SerializationContext, - tag: TagId) {.raises: [].} = - ## represents a bool value as a YAML scalar - c.put(scalarEvent(if value: "y" else: "n", tag, yAnchorNone)) - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var char) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a char value from a YAML scalar - constructScalarItem(s, item, char): - if item.scalarContent.len != 1: - raise s.constructionError("Cannot construct to char (length != 1): " & - escape(item.scalarContent)) - else: result = item.scalarContent[0] - -proc representObject*(value: char, ts: TagStyle, c: SerializationContext, - tag: TagId) {.raises: [].} = - ## represents a char value as YAML scalar - c.put(scalarEvent("" & value, tag, yAnchorNone)) - -proc yamlTag*(T: typedesc[Time]): TagId {.inline, raises: [].} = yTagTimestamp - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var Time) - {.raises: [YamlConstructionError, YamlStreamError].} = - constructScalarItem(s, item, Time): - if guessType(item.scalarContent) == yTypeTimestamp: - var - tmp = newStringOfCap(60) - pos = 8 - c: char - while pos < item.scalarContent.len(): - c = item.scalarContent[pos] - if c in {' ', '\t', 'T', 't'}: break - inc(pos) - if pos == item.scalarContent.len(): - tmp.add(item.scalarContent) - tmp.add("T00:00:00+00:00") - else: - tmp.add(item.scalarContent[0 .. pos - 1]) - if c in {' ', '\t'}: - while true: - inc(pos) - c = item.scalarContent[pos] - if c notin {' ', '\t'}: break - else: inc(pos) - tmp.add("T") - let timeStart = pos - inc(pos, 7) - var fractionStart = -1 - while pos < item.scalarContent.len(): - c = item.scalarContent[pos] - if c in {'+', '-', 'Z', ' ', '\t'}: break - elif c == '.': fractionStart = pos - inc(pos) - if fractionStart == -1: - tmp.add(item.scalarContent[timeStart .. pos - 1]) - else: - tmp.add(item.scalarContent[timeStart .. fractionStart - 1]) - if c in {'Z', ' ', '\t'}: tmp.add("+00:00") - else: - tmp.add(c) - inc(pos) - let tzStart = pos - inc(pos) - if pos < item.scalarContent.len() and item.scalarContent[pos] != ':': - inc(pos) - if pos - tzStart == 1: tmp.add('0') - tmp.add(item.scalarContent[tzStart .. pos - 1]) - if pos == item.scalarContent.len(): tmp.add(":00") - elif pos + 2 == item.scalarContent.len(): - tmp.add(":0") - tmp.add(item.scalarContent[pos + 1]) - else: - tmp.add(item.scalarContent[pos .. pos + 2]) - let info = tmp.parse("yyyy-M-d'T'H:mm:sszzz") - result = info.toTime() - else: - raise s.constructionError("Not a parsable timestamp: " & - escape(item.scalarContent)) - -proc representObject*(value: Time, ts: TagStyle, c: SerializationContext, - tag: TagId) {.raises: [ValueError].} = - #// let tmp = value.getGMTime() - let tmp = value.utc() - c.put(scalarEvent(tmp.format("yyyy-MM-dd'T'HH:mm:ss'Z'"))) - -proc yamlTag*[I](T: typedesc[seq[I]]): TagId {.inline, raises: [].} = - let uri = nimTag("system:seq(" & safeTagUri(yamlTag(I)) & ')') - result = lazyLoadTag(uri) - -proc yamlTag*[I](T: typedesc[set[I]]): TagId {.inline, raises: [].} = - let uri = nimTag("system:set(" & safeTagUri(yamlTag(I)) & ')') - result = lazyLoadTag(uri) - -proc constructObject*[T](s: var YamlStream, c: ConstructionContext, - result: var seq[T]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim seq from a YAML sequence - let event = s.next() - if event.kind != yamlStartSeq: - raise s.constructionError("Expected sequence start") - result = newSeq[T]() - while s.peek().kind != yamlEndSeq: - var item: T - constructChild(s, c, item) - result.add(item) - discard s.next() - -proc constructObject*[T](s: var YamlStream, c: ConstructionContext, - result: var set[T]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim seq from a YAML sequence - let event = s.next() - if event.kind != yamlStartSeq: - raise s.constructionError("Expected sequence start") - result = {} - while s.peek().kind != yamlEndSeq: - var item: T - constructChild(s, c, item) - result.incl(item) - discard s.next() - -proc representObject*[T](value: seq[T]|set[T], ts: TagStyle, - c: SerializationContext, tag: TagId) = - ## represents a Nim seq as YAML sequence - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startSeqEvent(tag)) - for item in value: - representChild(item, childTagStyle, c) - c.put(endSeqEvent()) - -proc yamlTag*[I, V](T: typedesc[array[I, V]]): TagId {.inline, raises: [].} = - const rangeName = name(I) - let uri = nimTag("system:array(" & rangeName[6..rangeName.high()] & ';' & - safeTagUri(yamlTag(V)) & ')') - result = lazyLoadTag(uri) - -proc constructObject*[I, T](s: var YamlStream, c: ConstructionContext, - result: var array[I, T]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim array from a YAML sequence - var event = s.next() - if event.kind != yamlStartSeq: - raise s.constructionError("Expected sequence start") - for index in low(I)..high(I): - event = s.peek() - if event.kind == yamlEndSeq: - raise s.constructionError("Too few array values") - constructChild(s, c, result[index]) - event = s.next() - if event.kind != yamlEndSeq: - raise s.constructionError("Too many array values") - -proc representObject*[I, T](value: array[I, T], ts: TagStyle, - c: SerializationContext, tag: TagId) = - ## represents a Nim array as YAML sequence - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startSeqEvent(tag)) - for item in value: - representChild(item, childTagStyle, c) - c.put(endSeqEvent()) - -proc yamlTag*[K, V](T: typedesc[Table[K, V]]): TagId {.inline, raises: [].} = - try: - let uri = nimTag("tables:Table(" & safeTagUri(yamlTag(K)) & ';' & - safeTagUri(yamlTag(V)) & ")") - result = lazyLoadTag(uri) - except KeyError: - # cannot happen (theoretically, you know) - internalError("Unexpected KeyError") - -proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext, - result: var Table[K, V]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim Table from a YAML mapping - let event = s.next() - if event.kind != yamlStartMap: - raise s.constructionError("Expected map start, got " & $event.kind) - result = initTable[K, V]() - while s.peek.kind != yamlEndMap: - var - key: K - value: V - constructChild(s, c, key) - constructChild(s, c, value) - if result.contains(key): - raise s.constructionError("Duplicate table key!") - result[key] = value - discard s.next() - -proc representObject*[K, V](value: Table[K, V], ts: TagStyle, - c: SerializationContext, tag: TagId) = - ## represents a Nim Table as YAML mapping - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startMapEvent(tag)) - for key, value in value.pairs: - representChild(key, childTagStyle, c) - representChild(value, childTagStyle, c) - c.put(endMapEvent()) - -proc yamlTag*[K, V](T: typedesc[OrderedTable[K, V]]): TagId - {.inline, raises: [].} = - try: - let uri = nimTag("tables:OrderedTable(" & safeTagUri(yamlTag(K)) & ';' & - safeTagUri(yamlTag(V)) & ")") - result = lazyLoadTag(uri) - except KeyError: - # cannot happen (theoretically, you know) - internalError("Unexpected KeyError") - -proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext, - result: var OrderedTable[K, V]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim OrderedTable from a YAML mapping - var event = s.next() - if event.kind != yamlStartSeq: - raise s.constructionError("Expected seq start, got " & $event.kind) - result = initOrderedTable[K, V]() - while s.peek.kind != yamlEndSeq: - var - key: K - value: V - event = s.next() - if event.kind != yamlStartMap: - raise s.constructionError("Expected map start, got " & $event.kind) - constructChild(s, c, key) - constructChild(s, c, value) - event = s.next() - if event.kind != yamlEndMap: - raise s.constructionError("Expected map end, got " & $event.kind) - if result.contains(key): - raise s.constructionError("Duplicate table key!") - result.add(key, value) - discard s.next() - -proc representObject*[K, V](value: OrderedTable[K, V], ts: TagStyle, - c: SerializationContext, tag: TagId) = - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startSeqEvent(tag)) - for key, value in value.pairs: - c.put(startMapEvent()) - representChild(key, childTagStyle, c) - representChild(value, childTagStyle, c) - c.put(endMapEvent()) - c.put(endSeqEvent()) - -proc yamlTag*(T: typedesc[object|enum]): - TagId {.inline, raises: [].} = - var uri = nimTag("custom:" & (typetraits.name(type(T)))) - try: serializationTagLibrary.tags[uri] - except KeyError: serializationTagLibrary.registerUri(uri) - -proc yamlTag*(T: typedesc[tuple]): - TagId {.inline, raises: [].} = - var - i: T - uri = nimTag("tuple(") - first = true - for name, value in fieldPairs(i): - if first: first = false - else: uri.add(",") - uri.add(safeTagUri(yamlTag(type(value)))) - uri.add(")") - try: serializationTagLibrary.tags[uri] - except KeyError: serializationTagLibrary.registerUri(uri) - -iterator recListItems(n: NimNode): NimNode = - if n.kind == nnkRecList: - for item in n.children: yield item - else: yield n - -proc recListLen(n: NimNode): int {.compileTime.} = - if n.kind == nnkRecList: result = n.len - else: result = 1 - -proc recListNode(n: NimNode): NimNode {.compileTime.} = - if n.kind == nnkRecList: result = n[0] - else: result = n - -proc fieldCount(t: NimNode): int {.compiletime.} = - result = 0 - let tDesc = getType(getType(t)[1]) - if tDesc.kind == nnkBracketExpr: - # tuple - result = tDesc.len - 1 - else: - # object - for child in tDesc[2].children: - inc(result) - if child.kind == nnkRecCase: - for bIndex in 1.. 0 - else: - const failOnUnknown = true - while s.peek.kind != endKind: - e = s.next() - when isVariantObject(getType(O)): - if e.kind != yamlStartMap: - raise s.constructionError("Expected single-pair map, got " & $e.kind) - e = s.next() - if e.kind != yamlScalar: - raise s.constructionError("Expected field name, got " & $e.kind) - let name = e.scalarContent - when result is tuple: - var i = 0 - var found = false - for fname, value in fieldPairs(result): - if fname == name: - if matched[i]: - raise s.constructionError("While constructing " & - typetraits.name(O) & ": Duplicate field: " & escape(name)) - constructChild(s, c, value) - matched[i] = true - found = true - break - inc(i) - when failOnUnknown: - if not found: - raise s.constructionError("While constructing " & - typetraits.name(O) & ": Unknown field: " & escape(name)) - else: - when hasIgnore(O) and failOnUnknown: - if name notin ignoredKeyList: - constructFieldValue(O, s, c, name, result, matched, failOnUnknown) - else: - e = s.next() - var depth = int(e.kind in {yamlStartMap, yamlStartSeq}) - while depth > 0: - case s.next().kind - of yamlStartMap, yamlStartSeq: inc(depth) - of yamlEndMap, yamlEndSeq: dec(depth) - of yamlScalar: discard - else: internalError("Unexpected event kind.") - else: - constructFieldValue(O, s, c, name, result, matched, failOnUnknown) - when isVariantObject(getType(O)): - e = s.next() - if e.kind != yamlEndMap: - raise s.constructionError("Expected end of single-pair map, got " & - $e.kind) - discard s.next() - when result is tuple: - var i = 0 - for fname, value in fieldPairs(result): - if not matched[i]: - raise s.constructionError("While constructing " & - typetraits.name(O) & ": Missing field: " & escape(fname)) - inc(i) - else: ensureAllFieldsPresent(s, O, result, matched) - -proc constructObject*[O: object|tuple]( - s: var YamlStream, c: ConstructionContext, result: var O) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## Overridable default implementation for custom object and tuple types - constructObjectDefault(s, c, result) - -macro genRepresentObject(t: typedesc, value, childTagStyle: typed) = - result = newStmtList() - let - tDecl = getType(t) - tDesc = getType(tDecl[1]) - isVO = isVariantObject(t) - var fieldIndex = 0'i16 - for child in tDesc[2].children: - if child.kind == nnkRecCase: - let - fieldName = $child[0] - fieldAccessor = newDotExpr(value, newIdentNode(fieldName)) - result.add(quote do: - c.put(startMapEvent(yTagQuestionMark, yAnchorNone)) - c.put(scalarEvent(`fieldName`, if `childTagStyle` == tsNone: - yTagQuestionMark else: yTagNimField, yAnchorNone)) - representChild(`fieldAccessor`, `childTagStyle`, c) - c.put(endMapEvent()) - ) - let enumName = $getTypeInst(child[0]) - var caseStmt = newNimNode(nnkCaseStmt).add(fieldAccessor) - for bIndex in 1 .. len(child) - 1: - var curBranch: NimNode - var recListIndex = 0 - case child[bIndex].kind - of nnkOfBranch: - curBranch = newNimNode(nnkOfBranch) - while recListIndex < child[bIndex].len - 1: - expectKind(child[bIndex][recListIndex], nnkIntLit) - curBranch.add(newCall(enumName, newLit(child[bIndex][recListIndex].intVal))) - inc(recListIndex) - of nnkElse: - curBranch = newNimNode(nnkElse) - else: - internalError("Unexpected child kind: " & $child[bIndex].kind) - var curStmtList = newStmtList() - if child[bIndex][recListIndex].recListLen > 0: - for item in child[bIndex][recListIndex].recListItems(): - inc(fieldIndex) - let - name = $item - itemAccessor = newDotExpr(value, newIdentNode(name)) - curStmtList.add(quote do: - when not `itemAccessor`.hasCustomPragma(transient): - c.put(startMapEvent(yTagQuestionMark, yAnchorNone)) - c.put(scalarEvent(`name`, if `childTagStyle` == tsNone: - yTagQuestionMark else: yTagNimField, yAnchorNone)) - representChild(`itemAccessor`, `childTagStyle`, c) - c.put(endMapEvent()) - ) - else: - curStmtList.add(newNimNode(nnkDiscardStmt).add(newEmptyNode())) - curBranch.add(curStmtList) - caseStmt.add(curBranch) - result.add(caseStmt) - else: - let - name = $child - childAccessor = newDotExpr(value, newIdentNode(name)) - result.add(quote do: - when not `childAccessor`.hasCustomPragma(transient): - when bool(`isVO`): c.put(startMapEvent(yTagQuestionMark, yAnchorNone)) - c.put(scalarEvent(`name`, if `childTagStyle` == tsNone: - yTagQuestionMark else: yTagNimField, yAnchorNone)) - representChild(`childAccessor`, `childTagStyle`, c) - when bool(`isVO`): c.put(endMapEvent()) - ) - inc(fieldIndex) - -proc representObject*[O: object](value: O, ts: TagStyle, - c: SerializationContext, tag: TagId) = - ## represents a Nim object or tuple as YAML mapping - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - when isVariantObject(getType(O)): c.put(startSeqEvent(tag, yAnchorNone)) - else: c.put(startMapEvent(tag, yAnchorNone)) - genRepresentObject(O, value, childTagStyle) - when isVariantObject(getType(O)): c.put(endSeqEvent()) - else: c.put(endMapEvent()) - -proc representObject*[O: tuple](value: O, ts: TagStyle, - c: SerializationContext, tag: TagId) = - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - var fieldIndex = 0'i16 - c.put(startMapEvent(tag, yAnchorNone)) - for name, fvalue in fieldPairs(value): - c.put(scalarEvent(name, if childTagStyle == tsNone: - yTagQuestionMark else: yTagNimField, yAnchorNone)) - representChild(fvalue, childTagStyle, c) - inc(fieldIndex) - c.put(endMapEvent()) - -proc constructObject*[O: enum](s: var YamlStream, c: ConstructionContext, - result: var O) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim enum from a YAML scalar - let e = s.next() - if e.kind != yamlScalar: - raise s.constructionError("Expected scalar, got " & $e.kind) - try: result = parseEnum[O](e.scalarContent) - except ValueError: - var ex = s.constructionError("Cannot parse '" & - escape(e.scalarContent) & "' as " & type(O).name) - ex.parent = getCurrentException() - raise ex - -proc representObject*[O: enum](value: O, ts: TagStyle, - c: SerializationContext, tag: TagId) {.raises: [].} = - ## represents a Nim enum as YAML scalar - c.put(scalarEvent($value, tag, yAnchorNone)) - -proc yamlTag*[O](T: typedesc[ref O]): TagId {.inline, raises: [].} = yamlTag(O) - -macro constructImplicitVariantObject(s, c, r, possibleTagIds: untyped, - t: typedesc) = - let tDesc = getType(getType(t)[1]) - yAssert tDesc.kind == nnkObjectTy - let recCase = tDesc[2][0] - yAssert recCase.kind == nnkRecCase - result = newNimNode(nnkIfStmt) - for i in 1 .. recCase.len - 1: - yAssert recCase[i].kind == nnkOfBranch - var branch = newNimNode(nnkElifBranch) - var branchContent = newStmtList(newAssignment(r, - newNimNode(nnkObjConstr).add( - newCall("type", r), - newColonExpr(newIdentNode($recCase[0]), recCase[i][0]) - ))) - case recCase[i][1].recListLen - of 0: - branch.add(infix(newIdentNode("yTagNull"), "in", possibleTagIds)) - branchContent.add(newNimNode(nnkDiscardStmt).add(newCall("next", s))) - of 1: - let field = newDotExpr(r, newIdentNode($recCase[i][1].recListNode)) - branch.add(infix( - newCall("yamlTag", newCall("type", field)), "in", possibleTagIds)) - branchContent.add(newCall("constructChild", s, c, field)) - else: - block: - internalError("Too many children: " & $recCase[i][1].recListlen) - branch.add(branchContent) - result.add(branch) - let raiseStmt = newNimNode(nnkRaiseStmt).add( - newCall(bindSym("constructionError"), s, - infix(newStrLitNode("This value type does not map to any field in " & - getTypeImpl(t)[1].repr & ": "), "&", - newCall("uri", newIdentNode("serializationTagLibrary"), - newNimNode(nnkBracketExpr).add(possibleTagIds, newIntLitNode(0))) - ) - )) - result.add(newNimNode(nnkElse).add(newNimNode(nnkTryStmt).add( - newStmtList(raiseStmt), newNimNode(nnkExceptBranch).add( - newIdentNode("KeyError"), - newNimNode(nnkDiscardStmt).add(newEmptyNode()) - )))) - -proc isImplicitVariantObject(t: typedesc): bool {.compileTime.} = - when compiles(t.hasCustomPragma(implicit)): - return t.hasCustomPragma(implicit) - else: - return false - -proc canBeImplicit(t: typedesc): bool {.compileTime.} = - let tDesc = getType(t) - if tDesc.kind != nnkObjectTy: return false - if tDesc[2].len != 1: return false - if tDesc[2][0].kind != nnkRecCase: return false - var foundEmptyBranch = false - for i in 1.. tDesc[2][0].len - 1: - case tDesc[2][0][i][1].recListlen # branch contents - of 0: - if foundEmptyBranch: return false - else: foundEmptyBranch = true - of 1: discard - else: return false - return true - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var T) = - let item = s.peek() - when isImplicitVariantObject(T): - when not canBeImplicit(T): - {. fatal: "This type cannot be marked as implicit" .} - var possibleTagIds = newSeq[TagId]() - case item.kind - of yamlScalar: - case item.scalarTag - of yTagQuestionMark: - case guessType(item.scalarContent) - of yTypeInteger: - possibleTagIds.add([yamlTag(int), yamlTag(int8), yamlTag(int16), - yamlTag(int32), yamlTag(int64)]) - if item.scalarContent[0] != '-': - possibleTagIds.add([yamlTag(uint), yamlTag(uint8), yamlTag(uint16), - yamlTag(uint32), yamlTag(uint64)]) - of yTypeFloat, yTypeFloatInf, yTypeFloatNaN: - possibleTagIds.add([yamlTag(float), yamlTag(float32), - yamlTag(float64)]) - of yTypeBoolTrue, yTypeBoolFalse: - possibleTagIds.add(yamlTag(bool)) - of yTypeNull: - raise s.constructionError("not implemented!") - of yTypeUnknown: - possibleTagIds.add(yamlTag(string)) - of yTypeTimestamp: - possibleTagIds.add(yamlTag(Time)) - of yTagExclamationMark: - possibleTagIds.add(yamlTag(string)) - else: - possibleTagIds.add(item.scalarTag) - of yamlStartMap: - if item.mapTag in [yTagQuestionMark, yTagExclamationMark]: - raise s.constructionError( - "Complex value of implicit variant object type must have a tag.") - possibleTagIds.add(item.mapTag) - of yamlStartSeq: - if item.seqTag in [yTagQuestionMark, yTagExclamationMark]: - raise s.constructionError( - "Complex value of implicit variant object type must have a tag.") - possibleTagIds.add(item.seqTag) - else: internalError("Unexpected item kind: " & $item.kind) - constructImplicitVariantObject(s, c, result, possibleTagIds, T) - else: - case item.kind - of yamlScalar: - if item.scalarTag notin [yTagQuestionMark, yTagExclamationMark, - yamlTag(T)]: - raise s.constructionError("Wrong tag for " & typetraits.name(T)) - elif item.scalarAnchor != yAnchorNone: - raise s.constructionError("Anchor on non-ref type") - of yamlStartMap: - if item.mapTag notin [yTagQuestionMark, yamlTag(T)]: - raise s.constructionError("Wrong tag for " & typetraits.name(T)) - elif item.mapAnchor != yAnchorNone: - raise s.constructionError("Anchor on non-ref type") - of yamlStartSeq: - if item.seqTag notin [yTagQuestionMark, yamlTag(T)]: - raise s.constructionError("Wrong tag for " & typetraits.name(T)) - elif item.seqAnchor != yAnchorNone: - raise s.constructionError("Anchor on non-ref type") - else: internalError("Unexpected item kind: " & $item.kind) - constructObject(s, c, result) - -proc constructChild*(s: var YamlStream, c: ConstructionContext, - result: var string) = - let item = s.peek() - if item.kind == yamlScalar: - if item.scalarTag notin - [yTagQuestionMark, yTagExclamationMark, yamlTag(string)]: - raise s.constructionError("Wrong tag for string") - elif item.scalarAnchor != yAnchorNone: - raise s.constructionError("Anchor on non-ref type") - constructObject(s, c, result) - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var seq[T]) = - let item = s.peek() - if item.kind == yamlStartSeq: - if item.seqTag notin [yTagQuestionMark, yamlTag(seq[T])]: - raise s.constructionError("Wrong tag for " & typetraits.name(seq[T])) - elif item.seqAnchor != yAnchorNone: - raise s.constructionError("Anchor on non-ref type") - constructObject(s, c, result) - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var Option[T]) = - ## constructs an optional value. A value with a !!null tag will be loaded - ## an empty value. - let event = s.peek() - if event.kind == yamlScalar and event.scalarTag == yTagNull: - result = none(T) - discard s.next() - else: - var inner: T - constructChild(s, c, inner) - result = some(inner) - -when defined(JS): - # in JS, Time is a ref type. Therefore, we need this specialization so that - # it is not handled by the general ref-type handler. - proc constructChild*(s: var YamlStream, c: ConstructionContext, - result: var Time) = - let e = s.peek() - if e.kind == yamlScalar: - if e.scalarTag notin [yTagQuestionMark, yTagTimestamp]: - raise s.constructionError("Wrong tag for Time") - elif guessType(e.scalarContent) != yTypeTimestamp: - raise s.constructionError("Invalid timestamp") - elif e.scalarAnchor != yAnchorNone: - raise s.constructionError("Anchor on non-ref type") - constructObject(s, c, result) - else: - raise s.constructionError("Unexpected structure, expected timestamp") - -proc constructChild*[O](s: var YamlStream, c: ConstructionContext, - result: var ref O) = - var e = s.peek() - if e.kind == yamlScalar: - if e.scalarTag == yTagNull or (e.scalarTag == yTagQuestionMark and - guessType(e.scalarContent) == yTypeNull): - result = nil - discard s.next() - return - elif e.kind == yamlAlias: - when defined(JS): - {.emit: [result, """ = """, c, """.refs.get(""", e.aliasTarget, """);"""].} - else: - result = cast[ref O](c.refs.getOrDefault(e.aliasTarget)) - discard s.next() - return - new(result) - template removeAnchor(anchor: var AnchorId) {.dirty.} = - if anchor != yAnchorNone: - when defined(JS): - {.emit: [c, """.refs.set(""", anchor, """, """, result, """);"""].} - else: - yAssert(not c.refs.hasKey(anchor)) - c.refs[anchor] = cast[pointer](result) - anchor = yAnchorNone - - case e.kind - of yamlScalar: removeAnchor(e.scalarAnchor) - of yamlStartMap: removeAnchor(e.mapAnchor) - of yamlStartSeq: removeAnchor(e.seqAnchor) - else: internalError("Unexpected event kind: " & $e.kind) - s.peek = e - try: constructChild(s, c, result[]) - except YamlConstructionError as e: - raise e - except YamlStreamError as e: - raise e - except Exception: - var e = newException(YamlStreamError, getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -proc representChild*(value: string, ts: TagStyle, c: SerializationContext) = - let tag = presentTag(string, ts) - representObject(value, ts, c, - if tag == yTagQuestionMark and guessType(value) != yTypeUnknown: - yTagExclamationMark - else: - tag) - -proc representChild*[T](value: seq[T], ts: TagStyle, c: SerializationContext) = - representObject(value, ts, c, presentTag(seq[T], ts)) - -proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext) = - if isNil(value): c.put(scalarEvent("~", yTagNull)) - elif c.style == asNone: representChild(value[], ts, c) - else: - var val: AnchorId - when defined(JS): - {.emit: [""" - if (""", c, """.refs.has(""", value, """) { - """, val, """ = """, c, """.refs.get(""", value, """); - if (val == """, yAnchorNone, ") {"].} - val = c.nextAnchorId - {.emit: [c, """.refs.set(""", value, """, """, val, """);"""].} - c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) - {.emit: "}".} - c.put(aliasEvent(val)) - return - else: - let p = cast[pointer](value) - if c.refs.hasKey(p): - val = c.refs.getOrDefault(p) - if val == yAnchorNone: - val = c.nextAnchorId - c.refs[p] = val - c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1) - c.put(aliasEvent(val)) - return - if c.style == asAlways: - val = c.nextAnchorId - when defined(JS): - {.emit: [c, ".refs.set(", p, ", ", val, ");"].} - else: c.refs[p] = val - c.nextAnchorId = AnchorId(int(val) + 1) - else: c.refs[p] = yAnchorNone - let - a = if c.style == asAlways: val else: cast[AnchorId](p) - childTagStyle = if ts == tsAll: tsAll else: tsRootOnly - origPut = c.put - c.put = proc(e: YamlStreamEvent) = - var ex = e - case ex.kind - of yamlStartMap: - ex.mapAnchor = a - if ts == tsNone: ex.mapTag = yTagQuestionMark - of yamlStartSeq: - ex.seqAnchor = a - if ts == tsNone: ex.seqTag = yTagQuestionMark - of yamlScalar: - ex.scalarAnchor = a - if ts == tsNone and guessType(ex.scalarContent) != yTypeNull: - ex.scalarTag = yTagQuestionMark - else: discard - c.put = origPut - c.put(ex) - representChild(value[], childTagStyle, c) - -proc representChild*[T](value: Option[T], ts: TagStyle, - c: SerializationContext) = - ## represents an optional value. If the value is missing, a !!null scalar - ## will be produced. - if value.isSome: - representChild(value.get(), ts, c) - else: - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(scalarEvent("~", yTagNull)) - -proc representChild*[O](value: O, ts: TagStyle, - c: SerializationContext) = - when isImplicitVariantObject(O): - # todo: this would probably be nicer if constructed with a macro - var count = 0 - for name, field in fieldPairs(value): - if count > 0: - representChild(field, if ts == tsAll: tsAll else: tsRootOnly, c) - inc(count) - if count == 1: c.put(scalarEvent("~", yTagNull)) - else: - representObject(value, ts, c, - if ts == tsNone: yTagQuestionMark else: yamlTag(O)) - -proc construct*[T](s: var YamlStream, target: var T) - {.raises: [YamlStreamError, YamlConstructionError].} = - ## Constructs a Nim value from a YAML stream. - var context = newConstructionContext() - try: - var e = s.next() - yAssert(e.kind == yamlStartDoc) - - constructChild(s, context, target) - e = s.next() - yAssert(e.kind == yamlEndDoc) - except YamlConstructionError: - raise (ref YamlConstructionError)(getCurrentException()) - except YamlStreamError: - let cur = getCurrentException() - var e = newException(YamlStreamError, cur.msg) - e.parent = cur.parent - raise e - except Exception: - # may occur while calling s() - var ex = newException(YamlStreamError, "") - ex.parent = getCurrentException() - raise ex - -proc load*[K](input: Stream | string, target: var K) - {.raises: [YamlConstructionError, IOError, YamlParserError].} = - ## Loads a Nim value from a YAML character stream. - var - parser = newYamlParser(serializationTagLibrary) - events = parser.parse(input) - try: construct(events, target) - except YamlStreamError: - let e = (ref YamlStreamError)(getCurrentException()) - 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.name) - -proc loadMultiDoc*[K](input: Stream | string, target: var seq[K]) = - var - parser = newYamlParser(serializationTagLibrary) - events = parser.parse(input) - try: - while not events.finished(): - var item: K - construct(events, item) - target.add(item) - except YamlConstructionError: - var e = (ref YamlConstructionError)(getCurrentException()) - discard events.getLastTokenContext(e.line, e.column, e.lineContent) - raise e - except YamlStreamError: - let e = (ref YamlStreamError)(getCurrentException()) - 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.name) - -proc setAnchor(a: var AnchorId, c: var SerializationContext) - {.inline.} = - if a != yAnchorNone: - when defined(JS): - {.emit: [a, """ = """, c, """.refs.get(""", a, """);"""].} - else: - a = c.refs.getOrDefault(cast[pointer](a)) - -proc represent*[T](value: T, ts: TagStyle = tsRootOnly, - a: AnchorStyle = asTidy): YamlStream = - ## Represents a Nim value as ``YamlStream`` - var bys = newBufferYamlStream() - var context = newSerializationContext(a, proc(e: YamlStreamEvent) = - bys.put(e) - ) - bys.put(startDocEvent()) - representChild(value, ts, context) - bys.put(endDocEvent()) - if a == asTidy: - for item in bys.mitems(): - case item.kind - of yamlStartMap: setAnchor(item.mapAnchor, context) - of yamlStartSeq: setAnchor(item.seqAnchor, context) - of yamlScalar: setAnchor(item.scalarAnchor, context) - else: discard - result = bys - -proc dump*[K](value: K, target: Stream, tagStyle: TagStyle = tsRootOnly, - anchorStyle: AnchorStyle = asTidy, - options: PresentationOptions = defaultPresentationOptions) - {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, - YamlStreamError].} = - ## Dump a Nim value as YAML character stream. - var events = represent(value, - if options.style == psCanonical: tsAll else: tagStyle, - if options.style == psJson: asNone else: anchorStyle) - try: present(events, target, serializationTagLibrary, options) - except YamlStreamError: - internalError("Unexpected exception: " & $getCurrentException().name) - -proc dump*[K](value: K, tagStyle: TagStyle = tsRootOnly, - anchorStyle: AnchorStyle = asTidy, - options: PresentationOptions = defaultPresentationOptions): - string = - ## Dump a Nim value as YAML into a string - 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().name) diff --git a/lib/yaml-legacy/yaml/stream.nim b/lib/yaml-legacy/yaml/stream.nim deleted file mode 100644 index 1bfaf62..0000000 --- a/lib/yaml-legacy/yaml/stream.nim +++ /dev/null @@ -1,367 +0,0 @@ - # NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================== -## Module yaml.stream -## ================== -## -## The stream API provides the basic data structure on which all low-level APIs -## operate. It is not named ``streams`` to not confuse it with the modle in the -## stdlib with that name. - -import hashes -import private/internal, taglib - -when defined(nimNoNil): - {.experimental: "notnil".} - -when defined(yamlScalarRepInd): - type ScalarRepresentationIndicator* = enum - srPlain, srSingleQuoted, srDoubleQuoted, srLiteral, srFolded - -type - AnchorId* = distinct int ## \ - ## An ``AnchorId`` identifies an anchor in the current document. It - ## becomes invalid as soon as the current document scope is invalidated - ## (for example, because the parser yielded a ``yamlEndDocument`` - ## event). ``AnchorId`` s exists because of efficiency, much like - ## ``TagId`` s. The actual anchor name is a presentation detail and - ## cannot be queried by the user. - - YamlStreamEventKind* = enum - ## Kinds of YAML events that may occur in an ``YamlStream``. Event kinds - ## are discussed in `YamlStreamEvent <#YamlStreamEvent>`_. - yamlStartDoc, yamlEndDoc, yamlStartMap, yamlEndMap, - yamlStartSeq, yamlEndSeq, yamlScalar, yamlAlias - - YamlStreamEvent* = object - ## An element from a `YamlStream <#YamlStream>`_. Events that start an - ## object (``yamlStartMap``, ``yamlStartSeq``, ``yamlScalar``) have - ## an optional anchor and a tag associated with them. The anchor will be - ## set to ``yAnchorNone`` if it doesn't exist. - ## - ## A non-existing tag in the YAML character stream will be resolved to - ## the non-specific tags ``?`` or ``!`` according to the YAML - ## specification. These are by convention mapped to the ``TagId`` s - ## ``yTagQuestionMark`` and ``yTagExclamationMark`` respectively. - ## Mapping is done by a `TagLibrary <#TagLibrary>`_. - case kind*: YamlStreamEventKind - of yamlStartMap: - mapAnchor* : AnchorId - mapTag* : TagId - of yamlStartSeq: - seqAnchor* : AnchorId - seqTag* : TagId - of yamlScalar: - scalarAnchor* : AnchorId - scalarTag* : TagId - scalarContent*: string # may not be nil (but empty) - when defined(yamlScalarRepInd): - scalarRep* : ScalarRepresentationIndicator - of yamlStartDoc: - when defined(yamlScalarRepInd): - explicitDirectivesEnd*: bool - else: discard - of yamlEndDoc: - when defined(yamlScalarRepInd): - explicitDocumentEnd*: bool - of yamlEndMap, yamlEndSeq: discard - of yamlAlias: - aliasTarget* : AnchorId - - 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 - ## ``yamlStartSeq`` is terminated by a ``yamlEndSeq`` and every - ## ``yamlStartDoc`` is terminated by a ``yamlEndDoc``. Moreover, every - ## emitted mapping has an even number of children. - ## - ## The creator of a ``YamlStream`` is responsible for it being - ## well-formed. A user of the stream may assume that it is well-formed - ## 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. - nextImpl*: proc(s: YamlStream, e: var YamlStreamEvent): bool - lastTokenContextImpl*: - proc(s: YamlStream, line, column: var int, - lineContent: var string): bool {.raises: [].} - isFinished*: bool - peeked: bool - cached: YamlStreamEvent - - YamlStreamError* = object of Exception - ## Exception that may be raised by a ``YamlStream`` when the underlying - ## backend raises an exception. The error that has occurred is - ## available from ``parent``. - -const - yAnchorNone*: AnchorId = (-1).AnchorId ## \ - ## yielded when no anchor was defined for a YAML node - -proc `==`*(left, right: AnchorId): bool {.borrow.} -proc `$`*(id: AnchorId): string {.borrow.} -proc hash*(id: AnchorId): Hash {.borrow.} - -proc noLastContext(s: YamlStream, line, column: var int, - lineContent: var string): bool {.raises: [].} = - (line, column, lineContent) = (-1, -1, "") - result = false - -proc basicInit*(s: YamlStream, lastTokenContextImpl: - proc(s: YamlStream, line, column: var int, lineContent: var string): bool - {.raises: [].} = noLastContext) {.raises: [].} = - ## initialize basic values of the YamlStream. Call this in your constructor - ## if you subclass YamlStream. - s.peeked = false - s.isFinished = false - s.lastTokenContextImpl = lastTokenContextImpl - -when not defined(JS): - type IteratorYamlStream = ref object of YamlStream - backend: iterator(): YamlStreamEvent - - proc initYamlStream*(backend: iterator(): YamlStreamEvent): YamlStream - {.raises: [].} = - ## Creates a new ``YamlStream`` that uses the given iterator as backend. - result = new(IteratorYamlStream) - result.basicInit() - 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 - -type - BufferYamlStream* = ref object of YamlStream - pos: int - buf: seq[YamlStreamEvent] - -proc newBufferYamlStream*(): BufferYamlStream not nil = - result = cast[BufferYamlStream not nil](new(BufferYamlStream)) - result.basicInit() - result.buf = @[] - result.pos = 0 - result.nextImpl = proc(s: YamlStream, e: var YamlStreamEvent): bool = - let bys = BufferYamlStream(s) - if bys.pos == bys.buf.len: - result = false - s.isFinished = true - else: - e = bys.buf[bys.pos] - inc(bys.pos) - result = true - -proc put*(bys: BufferYamlStream, e: YamlStreamEvent) {.raises: [].} = - bys.buf.add(e) - -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. - if s.peeked: - s.peeked = false - shallowCopy(result, s.cached) - return - else: - yAssert(not s.isFinished) - try: - while true: - if s.nextImpl(s, result): break - yAssert(not s.isFinished) - except YamlStreamError: - let cur = getCurrentException() - var e = newException(YamlStreamError, cur.msg) - e.parent = cur.parent - raise e - except Exception: - let cur = getCurrentException() - var e = newException(YamlStreamError, cur.msg) - e.parent = cur - raise e - -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()``. - if not s.peeked: - shallowCopy(s.cached, s.next()) - s.peeked = true - shallowCopy(result, s.cached) - -proc `peek=`*(s: YamlStream, value: YamlStreamEvent) {.raises: [].} = - ## Set the next item of the stream. Will replace a previously peeked item, - ## if one exists. - s.cached = value - s.peeked = true - -proc finished*(s: YamlStream): bool {.raises: [YamlStreamError].} = - ## ``true`` if no more items are available in the stream. Handles exceptions - ## of the backend like ``next()``. - if s.peeked: result = false - else: - try: - 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) - e.parent = cur.parent - raise e - except Exception: - let cur = getCurrentException() - var e = newException(YamlStreamError, cur.msg) - e.parent = cur - raise e - -proc getLastTokenContext*(s: YamlStream, line, column: var int, - lineContent: var string): bool = - ## ``true`` if source context information is available about the last returned - ## token. If ``true``, line, column and lineContent are set to position and - ## line content where the last token has been read from. - result = s.lastTokenContextImpl(s, line, column, lineContent) - -iterator items*(s: YamlStream): YamlStreamEvent - {.raises: [YamlStreamError].} = - ## Iterate over all items of the stream. You may not use ``peek()`` on the - ## stream while iterating. - while not s.finished(): yield s.next() - -iterator mitems*(bys: BufferYamlStream): var YamlStreamEvent {.raises: [].} = - ## Iterate over all items of the stream. You may not use ``peek()`` on the - ## stream while iterating. - for e in bys.buf.mitems(): yield e - -proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool {.raises: [].} = - ## compares all existing fields of the given items - if left.kind != right.kind: return false - case left.kind - of yamlStartDoc, yamlEndDoc, yamlEndMap, yamlEndSeq: result = true - of yamlStartMap: - result = left.mapAnchor == right.mapAnchor and left.mapTag == right.mapTag - of yamlStartSeq: - result = left.seqAnchor == right.seqAnchor and left.seqTag == right.seqTag - of yamlScalar: - result = left.scalarAnchor == right.scalarAnchor and - left.scalarTag == right.scalarTag and - left.scalarContent == right.scalarContent - of yamlAlias: result = left.aliasTarget == right.aliasTarget - -proc renderAttrs(tag: TagId, anchor: AnchorId, isPlain: bool = true): string = - result = "" - if anchor != yAnchorNone: result &= " &" & $anchor - case tag - of yTagQuestionmark: discard - of yTagExclamationmark: - when defined(yamlScalarRepInd): - if isPlain: result &= " " - else: - result &= " <" & $tag & ">" - -proc `$`*(event: YamlStreamEvent): string {.raises: [].} = - ## outputs a human-readable string describing the given event. - ## This string is compatible to the format used in the yaml test suite. - case event.kind - of yamlEndMap: result = "-MAP" - of yamlEndSeq: result = "-SEQ" - of yamlStartDoc: - result = "+DOC" - when defined(yamlScalarRepInd): - if event.explicitDirectivesEnd: result &= " ---" - of yamlEndDoc: - result = "-DOC" - when defined(yamlScalarRepInd): - if event.explicitDocumentEnd: result &= " ..." - of yamlStartMap: result = "+MAP" & renderAttrs(event.mapTag, event.mapAnchor) - of yamlStartSeq: result = "+SEQ" & renderAttrs(event.seqTag, event.seqAnchor) - of yamlScalar: - when defined(yamlScalarRepInd): - result = "=VAL" & renderAttrs(event.scalarTag, event.scalarAnchor, - event.scalarRep == srPlain) - case event.scalarRep - of srPlain: result &= " :" - of srSingleQuoted: result &= " \'" - of srDoubleQuoted: result &= " \"" - of srLiteral: result &= " |" - of srFolded: result &= " >" - else: - result = "=VAL" & renderAttrs(event.scalarTag, event.scalarAnchor, - false) - if event.scalarTag == yTagExclamationmark: result &= " \"" - else: result &= " :" - result &= yamlTestSuiteEscape(event.scalarContent) - of yamlAlias: result = "=ALI *" & $event.aliasTarget - -proc tag*(event: YamlStreamEvent): TagId {.raises: [FieldError].} = - ## returns the tag of the given event - case event.kind - of yamlStartMap: result = event.mapTag - of yamlStartSeq: result = event.seqTag - of yamlScalar: result = event.scalarTag - else: raise newException(FieldError, "Event " & $event.kind & " has no tag") - -when defined(yamlScalarRepInd): - proc startDocEvent*(explicit: bool = false): YamlStreamEvent - {.inline, raises: [].} = - ## creates a new event that marks the start of a YAML document - result = YamlStreamEvent(kind: yamlStartDoc, - explicitDirectivesEnd: explicit) - - proc endDocEvent*(explicit: bool = false): YamlStreamEvent - {.inline, raises: [].} = - ## creates a new event that marks the end of a YAML document - result = YamlStreamEvent(kind: yamlEndDoc, explicitDocumentEnd: explicit) -else: - proc startDocEvent*(): YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that marks the start of a YAML document - result = YamlStreamEvent(kind: yamlStartDoc) - - proc endDocEvent*(): YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that marks the end of a YAML document - result = YamlStreamEvent(kind: yamlEndDoc) - -proc startMapEvent*(tag: TagId = yTagQuestionMark, - anchor: AnchorId = yAnchorNone): YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that marks the start of a YAML mapping - result = YamlStreamEvent(kind: yamlStartMap, mapTag: tag, mapAnchor: anchor) - -proc endMapEvent*(): YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that marks the end of a YAML mapping - result = YamlStreamEvent(kind: yamlEndMap) - -proc startSeqEvent*(tag: TagId = yTagQuestionMark, - anchor: AnchorId = yAnchorNone): YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that marks the beginning of a YAML sequence - result = YamlStreamEvent(kind: yamlStartSeq, seqTag: tag, seqAnchor: anchor) - -proc endSeqEvent*(): YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that marks the end of a YAML sequence - result = YamlStreamEvent(kind: yamlEndSeq) - -when defined(yamlScalarRepInd): - proc scalarEvent*(content: string = "", tag: TagId = yTagQuestionMark, - anchor: AnchorId = yAnchorNone, - scalarRep: ScalarRepresentationIndicator = srPlain): - YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that represents a YAML scalar - result = YamlStreamEvent(kind: yamlScalar, scalarTag: tag, - scalarAnchor: anchor, scalarContent: content, - scalarRep: scalarRep) -else: - proc scalarEvent*(content: string = "", tag: TagId = yTagQuestionMark, - anchor: AnchorId = yAnchorNone): YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that represents a YAML scalar - result = YamlStreamEvent(kind: yamlScalar, scalarTag: tag, - scalarAnchor: anchor, scalarContent: content) - -proc aliasEvent*(anchor: AnchorId): YamlStreamEvent {.inline, raises: [].} = - ## creates a new event that represents a YAML alias - result = YamlStreamEvent(kind: yamlAlias, aliasTarget: anchor) diff --git a/lib/yaml-legacy/yaml/taglib.nim b/lib/yaml-legacy/yaml/taglib.nim deleted file mode 100644 index 646e77e..0000000 --- a/lib/yaml-legacy/yaml/taglib.nim +++ /dev/null @@ -1,312 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================== -## Module yaml.taglib -## ================== -## -## The taglib API enables you to query real names of tags emitted by the parser -## and create own tags. It also enables you to define tags for types used with -## the serialization API. - -import tables, macros, hashes, strutils - -type - TagId* = distinct int ## \ - ## A ``TagId`` identifies a tag URI, like for example - ## ``"tag:yaml.org,2002:str"``. The URI corresponding to a ``TagId`` can - ## be queried from the `TagLibrary <#TagLibrary>`_ which was - ## used to create this ``TagId``; e.g. when you parse a YAML character - ## stream, the ``TagLibrary`` of the parser is the one which generates - ## the resulting ``TagId`` s. - ## - ## URI strings are mapped to ``TagId`` s for efficiency reasons (you - ## do not need to compare strings every time) and to be able to - ## discover unknown tag URIs early in the parsing process. - - TagLibrary* = ref object - ## A ``TagLibrary`` maps tag URIs to ``TagId`` s. - ## - ## When `YamlParser <#YamlParser>`_ encounters tags not existing in the - ## tag library, it will use - ## `registerUri <#registerUri,TagLibrary,string>`_ to add - ## the tag to the library. - ## - ## You can base your tag library on common tag libraries by initializing - ## them with `initFailsafeTagLibrary <#initFailsafeTagLibrary>`_, - ## `initCoreTagLibrary <#initCoreTagLibrary>`_ or - ## `initExtendedTagLibrary <#initExtendedTagLibrary>`_. - tags*: Table[string, TagId] - nextCustomTagId*: TagId - tagHandles: Table[string, string] - -const - # failsafe schema - - yTagExclamationMark*: TagId = 0.TagId ## ``!`` non-specific tag - yTagQuestionMark* : TagId = 1.TagId ## ``?`` non-specific tag - yTagString* : TagId = 2.TagId ## \ - ## `!!str `_ tag - yTagSequence* : TagId = 3.TagId ## \ - ## `!!seq `_ tag - yTagMapping* : TagId = 4.TagId ## \ - ## `!!map `_ tag - - # json & core schema - - yTagNull* : TagId = 5.TagId ## \ - ## `!!null `_ tag - yTagBoolean* : TagId = 6.TagId ## \ - ## `!!bool `_ tag - yTagInteger* : TagId = 7.TagId ## \ - ## `!!int `_ tag - yTagFloat* : TagId = 8.TagId ## \ - ## `!!float `_ tag - - # other language-independent YAML types (from http://yaml.org/type/ ) - - yTagOrderedMap* : TagId = 9.TagId ## \ - ## `!!omap `_ tag - yTagPairs* : TagId = 10.TagId ## \ - ## `!!pairs `_ tag - yTagSet* : TagId = 11.TagId ## \ - ## `!!set `_ tag - yTagBinary* : TagId = 12.TagId ## \ - ## `!!binary `_ tag - yTagMerge* : TagId = 13.TagId ## \ - ## `!!merge `_ tag - yTagTimestamp* : TagId = 14.TagId ## \ - ## `!!timestamp `_ tag - yTagValue* : TagId = 15.TagId ## \ - ## `!!value `_ tag - yTagYaml* : TagId = 16.TagId ## \ - ## `!!yaml `_ tag - - yTagNimField* : TagId = 100.TagId ## \ - ## This tag is used in serialization for the name of a field of an - ## object. It may contain any string scalar that is a valid Nim symbol. - - yFirstStaticTagId* : TagId = 1000.TagId ## \ - ## The first ``TagId`` assigned by the ``setTagId`` templates. - - yFirstCustomTagId* : TagId = 10000.TagId ## \ - ## The first ``TagId`` which should be assigned to an URI that does not - ## exist in the ``YamlTagLibrary`` which is used for parsing. - - yamlTagRepositoryPrefix* = "tag:yaml.org,2002:" - nimyamlTagRepositoryPrefix* = "tag:nimyaml.org,2016:" - -proc `==`*(left, right: TagId): bool {.borrow.} -proc hash*(id: TagId): Hash {.borrow.} - -proc `$`*(id: TagId): string {.raises: [].} = - case id - of yTagQuestionMark: "?" - of yTagExclamationMark: "!" - of yTagString: "!!str" - of yTagSequence: "!!seq" - of yTagMapping: "!!map" - of yTagNull: "!!null" - of yTagBoolean: "!!bool" - of yTagInteger: "!!int" - of yTagFloat: "!!float" - of yTagOrderedMap: "!!omap" - of yTagPairs: "!!pairs" - of yTagSet: "!!set" - of yTagBinary: "!!binary" - of yTagMerge: "!!merge" - of yTagTimestamp: "!!timestamp" - of yTagValue: "!!value" - of yTagYaml: "!!yaml" - of yTagNimField: "!nim:field" - else: "<" & $int(id) & ">" - -proc initTagLibrary*(): TagLibrary {.raises: [].} = - ## initializes the ``tags`` table and sets ``nextCustomTagId`` to - ## ``yFirstCustomTagId``. - new(result) - result.tags = initTable[string, TagId]() - result.tagHandles = {"!": "!", yamlTagRepositoryPrefix : "!!"}.toTable() - result.nextCustomTagId = yFirstCustomTagId - -proc registerUri*(tagLib: TagLibrary, uri: string): TagId {.raises: [].} = - ## registers a custom tag URI with a ``TagLibrary``. The URI will get - ## the ``TagId`` ``nextCustomTagId``, which will be incremented. - tagLib.tags[uri] = tagLib.nextCustomTagId - result = tagLib.nextCustomTagId - tagLib.nextCustomTagId = cast[TagId](cast[int](tagLib.nextCustomTagId) + 1) - -proc uri*(tagLib: TagLibrary, id: TagId): string {.raises: [KeyError].} = - ## retrieve the URI a ``TagId`` maps to. - for iUri, iId in tagLib.tags.pairs: - if iId == id: return iUri - raise newException(KeyError, "Unknown tag id: " & $id) - -template y(suffix: string): string = yamlTagRepositoryPrefix & suffix -template n(suffix: string): string = nimyamlTagRepositoryPrefix & suffix - -proc initFailsafeTagLibrary*(): TagLibrary {.raises: [].} = - ## Contains only: - ## - ``!`` - ## - ``?`` - ## - ``!!str`` - ## - ``!!map`` - ## - ``!!seq`` - result = initTagLibrary() - result.tags["!"] = yTagExclamationMark - result.tags["?"] = yTagQuestionMark - result.tags[y"str"] = yTagString - result.tags[y"seq"] = yTagSequence - result.tags[y"map"] = yTagMapping - -proc initCoreTagLibrary*(): TagLibrary {.raises: [].} = - ## Contains everything in ``initFailsafeTagLibrary`` plus: - ## - ``!!null`` - ## - ``!!bool`` - ## - ``!!int`` - ## - ``!!float`` - result = initFailsafeTagLibrary() - result.tags[y"null"] = yTagNull - result.tags[y"bool"] = yTagBoolean - result.tags[y"int"] = yTagInteger - result.tags[y"float"] = yTagFloat - -proc initExtendedTagLibrary*(): TagLibrary {.raises: [].} = - ## Contains everything from ``initCoreTagLibrary`` plus: - ## - ``!!omap`` - ## - ``!!pairs`` - ## - ``!!set`` - ## - ``!!binary`` - ## - ``!!merge`` - ## - ``!!timestamp`` - ## - ``!!value`` - ## - ``!!yaml`` - result = initCoreTagLibrary() - result.tags[y"omap"] = yTagOrderedMap - result.tags[y"pairs"] = yTagPairs - result.tags[y"binary"] = yTagBinary - result.tags[y"merge"] = yTagMerge - result.tags[y"timestamp"] = yTagTimestamp - result.tags[y"value"] = yTagValue - result.tags[y"yaml"] = yTagYaml - -proc initSerializationTagLibrary*(): TagLibrary = - result = initTagLibrary() - result.tagHandles[nimyamlTagRepositoryPrefix] = "!n!" - result.tags["!"] = yTagExclamationMark - result.tags["?"] = yTagQuestionMark - result.tags[y"str"] = yTagString - result.tags[y"null"] = yTagNull - result.tags[y"bool"] = yTagBoolean - result.tags[y"float"] = yTagFloat - result.tags[y"timestamp"] = yTagTimestamp - result.tags[y"value"] = yTagValue - result.tags[y"binary"] = yTagBinary - result.tags[n"field"] = yTagNimField - -var - serializationTagLibrary* = initSerializationTagLibrary() ## \ - ## contains all local tags that are used for type serialization. Does - ## not contain any of the specific default tags for sequences or maps, - ## as those are not suited for Nim's static type system. - ## - ## Should not be modified manually. Will be extended by - ## `serializable <#serializable,stmt,stmt>`_. - -var - nextStaticTagId {.compileTime.} = yFirstStaticTagId ## \ - ## used for generating unique TagIds with ``setTagUri``. - registeredUris {.compileTime.} = newSeq[string]() ## \ - ## Since Table doesn't really work at compile time, we also store - ## registered URIs here to be able to generate a static compiler error - ## when the user tries to register an URI more than once. - -template setTagUri*(t: typedesc, uri: string) = - ## Associate the given uri with a certain type. This uri is used as YAML tag - ## when loading and dumping values of this type. - when uri in registeredUris: - {. fatal: "[NimYAML] URI \"" & uri & "\" registered twice!" .} - const id {.genSym.} = nextStaticTagId - static: - registeredUris.add(uri) - nextStaticTagId = TagId(int(nextStaticTagId) + 1) - when nextStaticTagId == yFirstCustomTagId: - {.fatal: "Too many tags!".} - serializationTagLibrary.tags[uri] = id - proc yamlTag*(T: typedesc[t]): TagId {.inline, raises: [].} = id - ## autogenerated - -template setTagUri*(t: typedesc, uri: string, idName: untyped) = - ## Like `setTagUri <#setTagUri.t,typedesc,string>`_, but lets - ## you choose a symbol for the `TagId <#TagId>`_ of the uri. This is only - ## necessary if you want to implement serialization / construction yourself. - when uri in registeredUris: - {. fatal: "[NimYAML] URI \"" & uri & "\" registered twice!" .} - const idName* = nextStaticTagId - static: - registeredUris.add(uri) - nextStaticTagId = TagId(int(nextStaticTagId) + 1) - when nextStaticTagId == yFirstCustomTagId: - {.fatal: "Too many tags!".} - serializationTagLibrary.tags[uri] = idName - proc yamlTag*(T: typedesc[t]): TagId {.inline, raises: [].} = idName - ## autogenerated - -static: - # standard YAML tags used by serialization - registeredUris.add("!") - registeredUris.add("?") - registeredUris.add(y"str") - registeredUris.add(y"null") - registeredUris.add(y"bool") - registeredUris.add(y"float") - registeredUris.add(y"timestamp") - registeredUris.add(y"value") - registeredUris.add(y"binary") - # special tags used by serialization - registeredUris.add(n"field") - -# tags for Nim's standard types -setTagUri(char, n"system:char", yTagNimChar) -setTagUri(int8, n"system:int8", yTagNimInt8) -setTagUri(int16, n"system:int16", yTagNimInt16) -setTagUri(int32, n"system:int32", yTagNimInt32) -setTagUri(int64, n"system:int64", yTagNimInt64) -setTagUri(uint8, n"system:uint8", yTagNimUInt8) -setTagUri(uint16, n"system:uint16", yTagNimUInt16) -setTagUri(uint32, n"system:uint32", yTagNimUInt32) -setTagUri(uint64, n"system:uint64", yTagNimUInt64) -setTagUri(float32, n"system:float32", yTagNimFloat32) -setTagUri(float64, n"system:float64", yTagNimFloat64) - -proc registerHandle*(tagLib: TagLibrary, handle, prefix: string) = - ## Registers a handle for a prefix. When presenting any tag that starts with - ## this prefix, the handle is used instead. Also causes the presenter to - ## output a TAG directive for the handle. - taglib.tagHandles[prefix] = handle - -proc searchHandle*(tagLib: TagLibrary, tag: string): - tuple[handle: string, len: int] {.raises: [].} = - ## search in the registered tag handles for one whose prefix matches the start - ## of the given tag. If multiple registered handles match, the one with the - ## longest prefix is returned. If no registered handle matches, (nil, 0) is - ## returned. - result.len = 0 - for key, value in tagLib.tagHandles: - if key.len > result.len: - if tag.startsWith(key): - result.len = key.len - result.handle = value - -iterator handles*(tagLib: TagLibrary): tuple[prefix, handle: string] = - ## iterate over registered tag handles that may be used as shortcuts - ## (e.g. ``!n!`` for ``tag:nimyaml.org,2016:``) - for key, value in tagLib.tagHandles: yield (key, value) - -proc nimTag*(suffix: string): string = - ## prepends NimYAML's tag repository prefix to the given suffix. For example, - ## ``nimTag("system:char")`` yields ``"tag:nimyaml.org,2016:system:char"``. - nimyamlTagRepositoryPrefix & suffix diff --git a/lib/yaml-legacy/yaml/tojson.nim b/lib/yaml-legacy/yaml/tojson.nim deleted file mode 100644 index 01ab8d4..0000000 --- a/lib/yaml-legacy/yaml/tojson.nim +++ /dev/null @@ -1,210 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================== -## Module yaml.tojson -## ================== -## -## The tojson API enables you to parser a YAML character stream into the JSON -## structures provided by Nim's stdlib. - -import json, streams, strutils, tables -import taglib, hints, serialization, stream, private/internal, parser - -# represents a single YAML level. The `node` with name `key`. -# `expKey` is used to indicate that an empty node shall be filled -type Level = tuple[node: JsonNode, key: string, expKey: bool] - -proc initLevel(node: JsonNode): Level {.raises: [].} = - (node: node, key: "", expKey: true) - -proc jsonFromScalar(content: string, tag: TagId): JsonNode - {.raises: [YamlConstructionError].}= - new(result) - var mappedType: TypeHint - - case tag - of yTagQuestionMark: mappedType = guessType(content) - of yTagExclamationMark, yTagString: mappedType = yTypeUnknown - of yTagBoolean: - case guessType(content) - of yTypeBoolTrue: mappedType = yTypeBoolTrue - of yTypeBoolFalse: mappedType = yTypeBoolFalse - else: - raise newException(YamlConstructionError, - "Invalid boolean value: " & content) - of yTagInteger: mappedType = yTypeInteger - of yTagNull: mappedType = yTypeNull - of yTagFloat: - case guessType(content) - of yTypeFloat: mappedType = yTypeFloat - of yTypeFloatInf: mappedType = yTypeFloatInf - of yTypeFloatNaN: mappedType = yTypeFloatNaN - else: - raise newException(YamlConstructionError, - "Invalid float value: " & content) - else: mappedType = yTypeUnknown - - try: - case mappedType - of yTypeInteger: - result = JsonNode(kind: JInt, num: parseBiggestInt(content)) - of yTypeFloat: - result = JsonNode(kind: JFloat, fnum: parseFloat(content)) - of yTypeFloatInf: - result = JsonNode(kind: JFloat, fnum: if content[0] == '-': NegInf else: Inf) - of yTypeFloatNaN: - result = JsonNode(kind: JFloat, fnum: NaN) - of yTypeBoolTrue: - result = JsonNode(kind: JBool, bval: true) - of yTypeBoolFalse: - result = JsonNode(kind: JBool, bval: false) - of yTypeNull: - result = JsonNode(kind: JNull) - else: - result = JsonNode(kind: JString) - shallowCopy(result.str, content) - except ValueError: - var e = newException(YamlConstructionError, "Cannot parse numeric value") - e.parent = getCurrentException() - raise e - -proc constructJson*(s: var YamlStream): seq[JsonNode] - {.raises: [YamlConstructionError, YamlStreamError].} = - ## Construct an in-memory JSON tree from a YAML event stream. The stream may - ## not contain any tags apart from those in ``coreTagLibrary``. Anchors and - ## aliases will be resolved. Maps in the input must not contain - ## non-scalars as keys. Each element of the result represents one document - ## in the YAML stream. - ## - ## **Warning:** The special float values ``[+-]Inf`` and ``NaN`` will be - ## parsed into Nim's JSON structure without error. However, they cannot be - ## rendered to a JSON character stream, because these values are not part - ## of the JSON specification. Nim's JSON implementation currently does not - ## check for these values and will output invalid JSON when rendering one - ## of these values into a JSON character stream. - newSeq(result, 0) - - var - levels = newSeq[Level]() - anchors = initTable[AnchorId, JsonNode]() - for event in s: - case event.kind - of yamlStartDoc: - # we don't need to do anything here; root node will be created - # by first scalar, sequence or map event - discard - of yamlEndDoc: - # we can savely assume that levels has e length of exactly 1. - result.add(levels.pop().node) - of yamlStartSeq: - levels.add(initLevel(newJArray())) - if event.seqAnchor != yAnchorNone: - anchors[event.seqAnchor] = levels[levels.high].node - of yamlStartMap: - levels.add(initLevel(newJObject())) - if event.mapAnchor != yAnchorNone: - anchors[event.mapAnchor] = levels[levels.high].node - of yamlScalar: - if levels.len == 0: - # parser ensures that next event will be yamlEndDocument - levels.add((node: jsonFromScalar(event.scalarContent, - event.scalarTag), - key: "", - expKey: true)) - continue - - case levels[levels.high].node.kind - of JArray: - let jsonScalar = jsonFromScalar(event.scalarContent, - event.scalarTag) - levels[levels.high].node.elems.add(jsonScalar) - if event.scalarAnchor != yAnchorNone: - anchors[event.scalarAnchor] = jsonScalar - of JObject: - if levels[levels.high].expKey: - levels[levels.high].expKey = false - # JSON only allows strings as keys - levels[levels.high].key = event.scalarContent - if event.scalarAnchor != yAnchorNone: - raise newException(YamlConstructionError, - "scalar keys may not have anchors in JSON") - else: - let jsonScalar = jsonFromScalar(event.scalarContent, - event.scalarTag) - levels[levels.high].node[levels[levels.high].key] = jsonScalar - levels[levels.high].expKey = true - if event.scalarAnchor != yAnchorNone: - anchors[event.scalarAnchor] = jsonScalar - else: - internalError("Unexpected node kind: " & $levels[levels.high].node.kind) - of yamlEndSeq, yamlEndMap: - if levels.len > 1: - let level = levels.pop() - case levels[levels.high].node.kind - of JArray: levels[levels.high].node.elems.add(level.node) - of JObject: - if levels[levels.high].expKey: - raise newException(YamlConstructionError, - "non-scalar as key not allowed in JSON") - else: - levels[levels.high].node[levels[levels.high].key] = level.node - levels[levels.high].expKey = true - else: - internalError("Unexpected node kind: " & - $levels[levels.high].node.kind) - else: discard # wait for yamlEndDocument - of yamlAlias: - # we can savely assume that the alias exists in anchors - # (else the parser would have already thrown an exception) - case levels[levels.high].node.kind - of JArray: - levels[levels.high].node.elems.add( - anchors.getOrDefault(event.aliasTarget)) - of JObject: - if levels[levels.high].expKey: - raise newException(YamlConstructionError, - "cannot use alias node as key in JSON") - else: - levels[levels.high].node.fields.add( - levels[levels.high].key, anchors.getOrDefault(event.aliasTarget)) - levels[levels.high].expKey = true - else: - internalError("Unexpected node kind: " & $levels[levels.high].node.kind) - -when not defined(JS): - proc loadToJson*(s: Stream): seq[JsonNode] - {.raises: [YamlParserError, YamlConstructionError, IOError].} = - ## Uses `YamlParser <#YamlParser>`_ and - ## `constructJson <#constructJson>`_ to construct an in-memory JSON tree - ## from a YAML character stream. - var - parser = newYamlParser(initCoreTagLibrary()) - events = parser.parse(s) - try: - return constructJson(events) - except YamlStreamError: - let e = getCurrentException() - 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 loadToJson*(str: string): seq[JsonNode] - {.raises: [YamlParserError, YamlConstructionError].} = - ## Uses `YamlParser <#YamlParser>`_ and - ## `constructJson <#constructJson>`_ to construct an in-memory JSON tree - ## from a YAML character stream. - var - parser = newYamlParser(initCoreTagLibrary()) - events = parser.parse(str) - try: return constructJson(events) - except YamlStreamError: - let e = getCurrentException() - if e.parent of YamlParserError: - raise (ref YamlParserError)(e.parent) - else: internalError("Unexpected exception: " & e.parent.repr) diff --git a/lib/yaml/.github/FUNDING.yml b/lib/yaml/.github/FUNDING.yml deleted file mode 100644 index a6579c1..0000000 --- a/lib/yaml/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: flyx \ No newline at end of file diff --git a/lib/yaml/.github/workflows/action.yml b/lib/yaml/.github/workflows/action.yml deleted file mode 100644 index 9658e85..0000000 --- a/lib/yaml/.github/workflows/action.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Test nimYAML - -on: [push, pull_request] - -jobs: - test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: - - ubuntu-latest - - windows-latest - - macOS-latest - nim-version: - - stable - - devel - steps: - - name: Checkout - uses: actions/checkout@v2 - with: - submodules: true - - - name: Cache choosenim - id: cache-choosenim - uses: actions/cache@v2 - with: - path: ~/.choosenim - key: ${{ runner.os }}-choosenim-${{ matrix.nim-version}} - - - name: Cache nimble - id: cache-nimble - uses: actions/cache@v2 - with: - path: ~/.nimble - key: ${{ runner.os }}-nimble-${{ matrix.nim-version}}-${{ hashFiles('yaml.nimble') }} - restore-keys: | - ${{ runner.os }}-nimble-${{ matrix.nim-version}}- - - name: Setup nim - uses: jiro4989/setup-nim-action@v1 - with: - nim-version: ${{ matrix.nim-version }} - - - name: Install Packages - run: nimble install -y - - - name: Test - run: | - nim lexerTests - nim parserTests - nim quickstartTests - nim jsonTests - nim domTests - nim serializationTests diff --git a/lib/yaml/.gitignore b/lib/yaml/.gitignore deleted file mode 100644 index 86a1d0a..0000000 --- a/lib/yaml/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -nimcache -test/tests -test/tlex -test/tdom -test/tserialization -test/tjson -test/tparser -test/tquickstart -test/*.exe -test/*.pdb -test/*.ilk -server/server -bench/jsonBench -bench/yamlBench -bench/bench -yaml.html -libyaml.dylib -libyaml.so -bench/json -docout -doc/rstPreproc -doc/tmp.rst -doc/**/code -nimsuggest.log diff --git a/lib/yaml/.gitmodules b/lib/yaml/.gitmodules deleted file mode 100644 index 3366e49..0000000 --- a/lib/yaml/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "test/yaml-test-suite"] - path = test/yaml-test-suite - url = https://github.com/yaml/yaml-test-suite.git - branch = data-2020-08-01 diff --git a/lib/yaml/CHANGELOG.md b/lib/yaml/CHANGELOG.md deleted file mode 100644 index 20d8d6a..0000000 --- a/lib/yaml/CHANGELOG.md +++ /dev/null @@ -1,300 +0,0 @@ -## 0.16.0 - -Features: - - * dumping ``sparse`` objects now omits empty ``Option`` fields (#100). - -Bugfixes: - - * Fixed several parser errors that emerged from updates on the test suite. - * Fixed ``raises`` annotations which could lead to compilation errors (#99). - -## 0.15.0 - -Features: - - * Compiles with --gc:arc and --gc:orc - -Bugfixes: - - * Parser rewrite: Fixes some test suite errors (including #83) - * Fixed problems where a syntax error lead to an invalid state (#39, #90) - * Serialize boolean values as ``true`` / ``false`` instead of ``y`` / ``y`` - to conform to YAML 1.2 spec. - -## 0.14.0 - -Features: - - * **Breaking change**: - transient, defaultVal, ignore and implicit are now annotations. - * Added ``sparse`` annotation to treat all ``Option`` fields as optional. - -Bugfixes: - - * can now use default values with ref objects (#66) - -## 0.13.1 - -Bugfixes: - - * Changed `nim tests` to `nim test` to make nim ci happy. - -## 0.13.0 - -Bugfixes: - - * Fixed submodule link to yaml-test-suite. - -Features: - - * Added support for `Option` type. - -## 0.12.0 - -Bugfixes: - - * Made it work with Nim 0.20.2 - -### 0.11.0 - -Bugfixes: - - * Made it work with Nim 0.19.0 - -NimYAML 0.11.0 is unlikely to work with older Nim versions. - -## 0.10.4 - -Bugfixes: - - * Made it work with Nim 0.18.0 - -### 0.10.3 - -Bugfixes: - - * Fixed a nimble error when installing the package. - -Features: - - * Added `ignoreUnknownKeys` macro to ignore all mapping keys that do not map - to a field of an object / tuple (#43). - -### 0.10.2 - -Bugfixes: - - * Fixed a nimble warning (#42) - * Make sure special strings (e.g. "null") are properly quoted when dumping JSON - (#44) - -### 0.10.1 - -Bugfixes: - - * Made it *actually* work with Nim 0.17.0. - -### 0.10.0 - -Features: - - * Compatibility with Nim 0.17.0 (#40). - **Important:** This fix breaks compatibility with previous - Nim versions! - -### 0.9.1 - -Features: - - * Added `YamlParser.display()` which is mainly used by tests - * NimYAML now builds for JS target (but does not work properly yet) - -Bugfixes: - - * Correctly present empty collections in block-only style (#33) - * Correctly handle `{1}` (#34) - * Recognize empty plain scalar as possible `!!null` value - * Require colons before subsequent keys in a flow mapping (#35) - * Allow stream end after block scalar indicators - * Fixed regression bugs introduced with timestamp parsing (#37) - -### 0.9.0 - -Features: - - * Better DOM API: - - yMapping is now a Table - - field names have changed to imitate those of Nim's json API - - Better getter and setter procs - * Added ability to resolve non-specific tags in presenter.transform - -Bugfixes: - - * Fixed parsing floating point literals (#30) - * Fixed a bug with variant records (#31) - * Empty documents now always contain an empty scalar - * Block scalars with indentation indicator now have correct whitespace on first - line. - -### 0.8.0 - -Features: - - * NimYAML now has a global tag URI prefix for Nim types, - `tag:nimyaml.org,2016:`. This prefix is denoted by the custom tag handle - `!n!`. - * Support arbitrary tag handles. - * Added ability to mark object and tuple fields as transient. - * Added ability to set a default value for object fields. - * Added ability to ignore key-value pairs in the input when loading object - values. - * Support `!!timestamp` by parsing it to `Time` from module `times`. - -Bugfixes: - - * Fixed a bug concerning duplicate TagIds for different tags in the - `serializationTagLibrary` - * Convert commas in tag URIs to semicolons when using a tag URI as generic - parameter to another one, because commas after the tag handle are interpreted - as flow separators. - -### 0.7.0 - -Features: - - * Better handling of internal error messages - * Refactoring of low-level API: - * No more usage of first-class iterators (not supported for JS target) - * Added ability to directly use strings as input without stdlib's streams - (which are not available for JS) - * Added ability to parse octal and hexadecimal numbers - * Restructuring of API: now available as submodules of yaml. For backwards - compatibility, it is still possible to `import yaml`, which will import all - submodules - * Check for missing, duplicate and unknown fields when deserializing tuples and - objects - -Bugfixes: - - * Fixed double quotes inside plain scalar (#25) - * Return correct line content for errors if possible (#23) - * Some smaller lexer/parser fixes - -### 0.6.3 - -Bugfixes: - - * Can load floats from integer literals (without decimal point) (#22) - -### 0.6.2 - -Bugfixes: - - * Fixed problem when serializing a type that overloads the `==` operator (#19) - * Fixed type hints for floats (`0` digit was not processed properly) (#21) - -### 0.6.1 - -Bugfixes: - - * Fixed deserialization of floats (#17) - * Handle IndexError from queues properly - -### 0.6.0 - -Features: - - * Properly support variant object types - * First version that works with a released Nim version (0.14.0) - -Bugfixes: - - * Fixed a crash in presenter when outputting JSON or canonical YAML - * Raise an exception when trying to output multiple documents in JSON style - -### 0.5.1 - -Bugfixes: - - * Fixed a problem that was introduced by a change in Nim devel - -### 0.5.0 - -Features: - - * Support variant object types (experimental) - * Added ability to use variant object types to process - heterogeneous data - * Support `set` type - * Support `array` type - * Support `int`, `uint` and `float` types - (previously, the precision must be specified) - * Check for duplicate tag URIs at compile time - * Renamed `setTagUriForType` to `setTagUri` - -Bugfixes: - - * None, but fastparse.nim has seen heavy refactoring - -### 0.4.0 - -Features: - - * Added option to output YAML 1.1 - * Added benchmark for processing YAML input - * Serialization for OrderedMap - * Use !nim:field for object field names (#12) - -Bugfixes: - - * Code refactoring (#9, #10, #11, #13) - * Some small improvements parsing and presenting - -### 0.3.0 - -Features: - - * Renamed some symbols to improve consistency (#6): - - `yamlStartSequence` -> `yamlStartSeq` - - `yamlEndSequence` -> `yamlEndSeq` - - `yamlStartDocument` -> `yamlStartDoc` - - `yamlEndDocument` -> `yamlEndDoc` - - `yTagMap` -> `yTagMapping` - * Introduced `PresentationOptions`: - - Let user specify newline style - - Merged old presentation options `indentationStep` and `presentationStyle` - into it - * Use YAML test suite from `yaml-dev-kit` to test parser. - -Bugfixes: - - * Fixed various parser bugs discovered with YAML test suite: - - Block scalar as root node no longer leads to a parser error - - Fixed a bug that caused incorrect handling of comments after plain scalars - - Fixed bugs with newline handling of block scalars - - Fixed a bug related to block sequence indentation - - Skip content in tag and anchor names and single-quoted scalars when - scanning for possible implicit map key - - Properly handle more indented lines in folded block scalars - - Fixed a problem with handling ':' after whitespace - - Fixed indentation handling after block scalar - -### 0.2.0 - -Features: - - * Added DOM API - * Output block scalars in presenter if scalar is long and block scalar output - is feasible. Else, use multiple lines for long scalars in double quotes. - -Bugfixes: - - * Improved parser (#1, #3, #5) - * Made parser correctly handle block sequences that have the same indentation - as their parent node (#2) - * Fixed problems with outputting double quoted strings (#4) - -### 0.1.0 - - * Initial release diff --git a/lib/yaml/README.md b/lib/yaml/README.md deleted file mode 100644 index 43204dc..0000000 --- a/lib/yaml/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# NimYAML - YAML implementation for Nim - -![Test Status](https://github.com/flyx/NimYAML/actions/workflows/action.yml/badge.svg) - -NimYAML is a pure Nim YAML implementation without any dependencies other than -Nim's standard library. It enables you to serialize Nim objects to a YAML stream -and back. It also provides a low-level event-based API, and a document object -model which you do not want to use because serializing to native types is much -more awesome. - -Documentation, examples and an online demo are available [here][1]. Releases are -available as tags in this repository and can be fetched via nimble: - - nimble install yaml - -## Status - -The library is fairly stable, I only maintain it and will not add any features due to lack of time and interest. NimYAML passes all tests of the current YAML -test suite which makes it 100% conformant with YAML 1.2. - -PRs for bugs are welcome. If you want to add a feature, you are free to; but be aware that I will not maintain it and am unlikely to review it in depth, so if I accept it, you will be co-maintainer. - -## Features that have been planned, but will not be implemented by myself - - * Serialization: - - Support for more standard library types - - Support for polymorphism - - Support for generic objects - -## Developers - -```bash -nim test # runs all tests -nim lexerTests # run lexer tests -nim parserTests # run parser tests (git-clones yaml-dev-kit) -nim serializationTests # runs serialization tests -nim quickstartTests # run tests for quickstart snippets from documentation -nim documentation # builds documentation to folder docout -nim server # builds the REST server used for the testing ground -nim bench # runs benchmarks, requires libyaml -nim clean # guess -nim build # build a library -``` - -NimYAML supports Nim 1.4.0 and later. -Previous versions are untested. -NimYAML v0.9.1 is the last release to support Nim 0.15.x and 0.16.0. - -When debugging crashes in this library, use the `d:debug` compile flag to enable printing of the internal stack traces for calls to `internalError` and `yAssert`. - -## License - -[MIT][2] - -## Support this Project - -If you like this project and want to give something back, you can check out GitHub's Sponsor button to the right. This is just an option I provide, not something I request you to do, and I will never nag about it. - - [1]: http://flyx.github.io/NimYAML/ - [2]: copying.txt diff --git a/lib/yaml/bench/bench.nim b/lib/yaml/bench/bench.nim deleted file mode 100644 index a02a5a5..0000000 --- a/lib/yaml/bench/bench.nim +++ /dev/null @@ -1 +0,0 @@ -import jsonBench, yamlBench \ No newline at end of file diff --git a/lib/yaml/bench/commonBench.nim b/lib/yaml/bench/commonBench.nim deleted file mode 100644 index 4c01a4d..0000000 --- a/lib/yaml/bench/commonBench.nim +++ /dev/null @@ -1,18 +0,0 @@ -import stopwatch - -template multiBench*(nanosecs: int64, times: int, body: stmt): stmt = - assert(times mod 2 == 0) - var arr: array[0..times - 1, int64] - for i in countup(0, times - 1): - var c: clock - bench(c): - body - arr[i] = c.nanoseconds() - sort(arr, cmp) - # ignore lowest and highest 10% - let tenth: int = times div 10 - let lowest = arr[tenth] - var totaldiff = 0.int64 - for i in countup(tenth + 1, times - tenth - 1): - totaldiff += arr[i] - lowest - nanosecs = lowest + totaldiff div (times - 2 * tenth) \ No newline at end of file diff --git a/lib/yaml/bench/jsonBench.nim b/lib/yaml/bench/jsonBench.nim deleted file mode 100644 index d187e59..0000000 --- a/lib/yaml/bench/jsonBench.nim +++ /dev/null @@ -1,207 +0,0 @@ -import "../yaml", commonBench - -from nimlets_yaml import objKind - -import math, strutils, stopwatch, terminal, algorithm, random, json - -proc cmp(left, right: clock): int = cmp(left.nanoseconds(), right.nanoseconds()) - -type - ObjectKind = enum - otMap, otSequence - - Level = tuple - kind: ObjectKind - len: int - -proc genString(maxLen: int): string = - let len = random(maxLen) - result = "\"" - var i = 0 - while i < len - 1: - let c = cast[char](random(127 - 32) + 32) - case c - of '"', '\\': - result.add('\\') - result.add(c) - i += 2 - else: - result.add(c) - i += 1 - result.add('\"') - -proc genJsonString(size: int, maxStringLen: int): string = - ## Generates a random JSON string. - ## size is in KiB, mayStringLen in characters. - - randomize(size * maxStringLen) - result = "{" - - let targetSize = size * 1024 - var - indentation = 2 - levels = newSeq[Level]() - curSize = 1 - justOpened = true - levels.add((kind: otMap, len: 0)) - - while levels.len > 0: - let - objectCloseProbability = - float(levels[levels.high].len + levels.high) * 0.025 - closeObject = random(1.0) <= objectCloseProbability - - if (closeObject and levels.len > 1) or curSize > targetSize: - indentation -= 2 - if justOpened: - justOpened = false - else: - result.add("\x0A") - result.add(repeat(' ', indentation)) - curSize += indentation + 1 - case levels[levels.high].kind - of otMap: - result.add('}') - of otSequence: - result.add(']') - curSize += 1 - discard levels.pop() - continue - - levels[levels.high].len += 1 - - if justOpened: - justOpened = false - result.add("\x0A") - result.add(repeat(' ', indentation)) - curSize += indentation + 1 - else: - result.add(",\x0A") - result.add(repeat(' ', indentation)) - curSize += indentation + 2 - - case levels[levels.high].kind - of otMap: - let key = genString(maxStringLen) - result.add(key) - result.add(": ") - curSize += key.len + 2 - of otSequence: - discard - - let - objectValueProbability = - 0.8 / float(levels.len * levels.len) - generateObjectValue = random(1.0) <= objectValueProbability - - if generateObjectValue: - let objectKind = if random(2) == 0: otMap else: otSequence - case objectKind - of otMap: - result.add('{') - of otSequence: - result.add('[') - curSize += 1 - levels.add((kind: objectKind, len: 0)) - justOpened = true - indentation += 2 - else: - var s: string - case random(11) - of 0..5: - s = genString(maxStringLen) - of 6..7: - s = $random(32000) - of 8..9: - s = $(random(424242.4242) - 212121.21) - of 10: - case random(3) - of 0: - s = "true" - of 1: - s = "false" - of 2: - s = "null" - else: - discard - else: - discard - - result.add(s) - curSize += s.len - -var - cYaml1k, cYaml10k, cYaml100k, cJson1k, cJson10k, cJson100k, - cLibYaml1k, cLibYaml10k, cLibYaml100k: int64 - json1k = genJsonString(1, 32) - json10k = genJsonString(10, 32) - json100k = genJsonString(100, 32) - tagLib = initCoreTagLibrary() - parser = newYamlParser(initCoreTagLibrary()) - -block: - multibench(cJson1k, 100): - let res = parseJson(json1k) - assert res.kind == JObject - -block: - multibench(cJson10k, 100): - let res = parseJson(json10k) - assert res.kind == JObject - -block: - multibench(cJson100k, 100): - let res = parseJson(json100k) - assert res.kind == JObject - -block: - multibench(cYaml1k, 100): - let res = loadToJson(json1k) - assert res[0].kind == JObject - -block: - multibench(cYaml10k, 100): - let res = loadToJson(json10k) - assert res[0].kind == JObject - -block: - multibench(cYaml100k, 100): - let res = loadToJson(json100k) - assert res[0].kind == JObject - -block: - multibench(cLibYaml1k, 100): - let res = nimlets_yaml.load(json1k) - assert res[0].objKind == nimlets_yaml.YamlObjKind.Map - -block: - multibench(cLibYaml10k, 100): - let res = nimlets_yaml.load(json10k) - assert res[0].objKind == nimlets_yaml.YamlObjKind.Map - -block: - multibench(cLibYaml100k, 100): - let res = nimlets_yaml.load(json100k) - assert res[0].objKind == nimlets_yaml.YamlObjKind.Map - -proc writeResult(caption: string, num: int64) = - styledWriteLine(stdout, resetStyle, caption, fgGreen, $num, resetStyle, "μs") - -setForegroundColor(fgWhite) - -writeStyled "Benchmark: Processing JSON input\n" -writeStyled "================================\n" -writeStyled "1k input\n--------\n" -writeResult "NimYAML: ", cYaml1k div 1000 -writeResult "JSON: ", cJson1k div 1000 -writeResult "LibYAML: ", cLibYaml1k div 1000 -setForegroundColor(fgWhite) -writeStyled "10k input\n---------\n" -writeResult "NimYAML: ", cYaml10k div 1000 -writeResult "JSON: ", cJson10k div 1000 -writeResult "LibYAML: ", cLibYaml10k div 1000 -setForegroundColor(fgWhite) -writeStyled "100k input\n----------\n" -writeResult "NimYAML: ", cYaml100k div 1000 -writeResult "JSON: ", cJson100k div 1000 -writeResult "LibYAML: ", cLibYaml100k div 1000 diff --git a/lib/yaml/bench/lib/libyaml.nim b/lib/yaml/bench/lib/libyaml.nim deleted file mode 100644 index 2e3ef89..0000000 --- a/lib/yaml/bench/lib/libyaml.nim +++ /dev/null @@ -1,577 +0,0 @@ -# This code is taken from https://github.com/nimlets/nimlets -# and has been slightly modified to fit our needs. - -type - yaml_version_directive_t* = object - major*: cint - minor*: cint -type - yaml_tag_directive_t* = object - handle*: cstring - prefix*: cstring -type - yaml_encoding_t* {.size: sizeof(cint).} = enum - YAML_ANY_ENCODING, - YAML_UTF8_ENCODING, - YAML_UTF16LE_ENCODING, - YAML_UTF16BE_ENCODING -type - yaml_break_t* {.size: sizeof(cint).} = enum - YAML_ANY_BREAK, - YAML_CR_BREAK, - YAML_LN_BREAK, - YAML_CRLN_BREAK -type - yaml_error_type_t* {.size: sizeof(cint).} = enum - YAML_NO_ERROR, - YAML_MEMORY_ERROR, - YAML_READER_ERROR, - YAML_SCANNER_ERROR, - YAML_PARSER_ERROR, - YAML_COMPOSER_ERROR, - YAML_WRITER_ERROR, - YAML_EMITTER_ERROR -type - yaml_mark_t* = object - index*: csize - line*: csize - column*: csize -type - yaml_scalar_style_t* {.size: sizeof(cint).} = enum - YAML_ANY_SCALAR_STYLE, - YAML_PLAIN_SCALAR_STYLE, - YAML_SINGLE_QUOTED_SCALAR_STYLE, - YAML_DOUBLE_QUOTED_SCALAR_STYLE, - YAML_LITERAL_SCALAR_STYLE, - YAML_FOLDED_SCALAR_STYLE -type - yaml_sequence_style_t* {.size: sizeof(cint).} = enum - YAML_ANY_SEQUENCE_STYLE, - YAML_BLOCK_SEQUENCE_STYLE, - YAML_FLOW_SEQUENCE_STYLE -type - yaml_mapping_style_t* {.size: sizeof(cint).} = enum - YAML_ANY_MAPPING_STYLE, - YAML_BLOCK_MAPPING_STYLE, - YAML_FLOW_MAPPING_STYLE -type - yaml_token_type_t* {.size: sizeof(cint).} = enum - YAML_NO_TOKEN, - YAML_STREAM_START_TOKEN, - YAML_STREAM_END_TOKEN, - YAML_VERSION_DIRECTIVE_TOKEN, - YAML_TAG_DIRECTIVE_TOKEN, - YAML_DOCUMENT_START_TOKEN, - YAML_DOCUMENT_END_TOKEN, - YAML_BLOCK_SEQUENCE_START_TOKEN, - YAML_BLOCK_MAPPING_START_TOKEN, - YAML_BLOCK_END_TOKEN, - YAML_FLOW_SEQUENCE_START_TOKEN, - YAML_FLOW_SEQUENCE_END_TOKEN, - YAML_FLOW_MAPPING_START_TOKEN, - YAML_FLOW_MAPPING_END_TOKEN, - YAML_BLOCK_ENTRY_TOKEN, - YAML_FLOW_ENTRY_TOKEN, - YAML_KEY_TOKEN, - YAML_VALUE_TOKEN, - YAML_ALIAS_TOKEN, - YAML_ANCHOR_TOKEN, - YAML_TAG_TOKEN, - YAML_SCALAR_TOKEN -type - INNER_C_STRUCT_9581966235636552858* = object - encoding*: yaml_encoding_t - INNER_C_STRUCT_1221667129857401972* = object - value*: cstring - INNER_C_STRUCT_3317256698323717696* = object - value*: cstring - INNER_C_STRUCT_5441002398333014240* = object - handle*: cstring - suffix*: cstring - INNER_C_STRUCT_7453632048426669727* = object - value*: cstring - length*: csize - style*: yaml_scalar_style_t - INNER_C_STRUCT_9783180209656813162* = object - major*: cint - minor*: cint - INNER_C_STRUCT_13940099295483927389* = object - handle*: cstring - prefix*: cstring - INNER_C_UNION_9404448031707501477* = object {.union.} - stream_start*: INNER_C_STRUCT_9581966235636552858 - alias*: INNER_C_STRUCT_1221667129857401972 - anchor*: INNER_C_STRUCT_3317256698323717696 - tag*: INNER_C_STRUCT_5441002398333014240 - scalar*: INNER_C_STRUCT_7453632048426669727 - version_directive*: INNER_C_STRUCT_9783180209656813162 - tag_directive*: INNER_C_STRUCT_13940099295483927389 - yaml_token_t* = object - typ*: yaml_token_type_t - data*: INNER_C_UNION_9404448031707501477 - start_mark*: yaml_mark_t - end_mark*: yaml_mark_t -type - yaml_event_type_t* {.size: sizeof(cint).} = enum - YAML_NO_EVENT, - YAML_STREAM_START_EVENT, - YAML_STREAM_END_EVENT, - YAML_DOCUMENT_START_EVENT, - YAML_DOCUMENT_END_EVENT, - YAML_ALIAS_EVENT, - YAML_SCALAR_EVENT, - YAML_SEQUENCE_START_EVENT, - YAML_SEQUENCE_END_EVENT, - YAML_MAPPING_START_EVENT, - YAML_MAPPING_END_EVENT -type - INNER_C_STRUCT_12590518896704616971* = object - encoding*: yaml_encoding_t - INNER_C_STRUCT_2667561393214118032* = object - start*: ptr yaml_tag_directive_t - endd*: ptr yaml_tag_directive_t - INNER_C_STRUCT_8611624117794791642* = object - version_directive*: ptr yaml_version_directive_t - tag_directives*: INNER_C_STRUCT_2667561393214118032 - implicit*: cint - INNER_C_STRUCT_6989068223488568623* = object - implicit*: cint - INNER_C_STRUCT_12004643997943399240* = object - anchor*: cstring - INNER_C_STRUCT_14974408632587267100* = object - anchor*: cstring - tag*: cstring - value*: cstring - length*: csize - plain_implicit*: cint - quoted_implicit*: cint - style*: yaml_scalar_style_t - INNER_C_STRUCT_17970865806594553108* = object - anchor*: cstring - tag*: cstring - implicit*: cint - style*: yaml_sequence_style_t - INNER_C_STRUCT_1674767092908407322* = object - anchor*: cstring - tag*: cstring - implicit*: cint - style*: yaml_mapping_style_t - INNER_C_UNION_14299011587659785980* = object {.union.} - stream_start*: INNER_C_STRUCT_12590518896704616971 - document_start*: INNER_C_STRUCT_8611624117794791642 - document_endd*: INNER_C_STRUCT_6989068223488568623 - alias*: INNER_C_STRUCT_12004643997943399240 - scalar*: INNER_C_STRUCT_14974408632587267100 - sequence_start*: INNER_C_STRUCT_17970865806594553108 - mapping_start*: INNER_C_STRUCT_1674767092908407322 - yaml_event_t* = object - typ*: yaml_event_type_t - data*: INNER_C_UNION_14299011587659785980 - start_mark*: yaml_mark_t - end_mark*: yaml_mark_t -const YAML_NULL_TAG* = "tag:yaml.org,2002:null" -const YAML_BOOL_TAG* = "tag:yaml.org,2002:bool" -const YAML_STR_TAG* = "tag:yaml.org,2002:str" -const YAML_INT_TAG* = "tag:yaml.org,2002:int" -const YAML_FLOAT_TAG* = "tag:yaml.org,2002:float" -const YAML_TIMESTAMP_TAG* = "tag:yaml.org,2002:timestamp" -const YAML_SEQ_TAG* = "tag:yaml.org,2002:seq" -const YAML_MAP_TAG* = "tag:yaml.org,2002:map" -const YAML_DEFAULT_SCALAR_TAG* = YAML_STR_TAG -const YAML_DEFAULT_SEQUENCE_TAG* = YAML_SEQ_TAG -const YAML_DEFAULT_MAPPING_TAG* = YAML_MAP_TAG -var YAML_VNULL_TAG* = "tag:yaml.org,2002:null" -var YAML_VBOOL_TAG* = "tag:yaml.org,2002:bool" -var YAML_VSTR_TAG* = "tag:yaml.org,2002:str" -var YAML_VINT_TAG* = "tag:yaml.org,2002:int" -var YAML_VFLOAT_TAG* = "tag:yaml.org,2002:float" -var YAML_VTIMESTAMP_TAG* = "tag:yaml.org,2002:timestamp" -var YAML_VSEQ_TAG* = "tag:yaml.org,2002:seq" -var YAML_VMAP_TAG* = "tag:yaml.org,2002:map" -var YAML_VDEFAULT_SCALAR_TAG* = YAML_STR_TAG -var YAML_VDEFAULT_SEQUENCE_TAG* = YAML_SEQ_TAG -var YAML_VDEFAULT_MAPPING_TAG* = YAML_MAP_TAG -type - yaml_node_type_t* {.size: sizeof(cint).} = enum - YAML_NO_NODE, - YAML_SCALAR_NODE, - YAML_SEQUENCE_NODE, - YAML_MAPPING_NODE - yaml_node_t* = yaml_node_s - yaml_node_item_t* = cint - yaml_node_pair_t* = object - key*: cint - value*: cint - INNER_C_STRUCT_2771607800107246221* = object - value*: cstring - length*: csize - style*: yaml_scalar_style_t - INNER_C_STRUCT_16176656515014249903* = object - start*: ptr yaml_node_item_t - endd*: ptr yaml_node_item_t - top*: ptr yaml_node_item_t - INNER_C_STRUCT_17512274596170441087* = object - items*: INNER_C_STRUCT_16176656515014249903 - style*: yaml_sequence_style_t - INNER_C_STRUCT_6534273983681155882* = object - start*: ptr yaml_node_pair_t - endd*: ptr yaml_node_pair_t - top*: ptr yaml_node_pair_t - INNER_C_STRUCT_11518003446976276318* = object - pairs*: INNER_C_STRUCT_6534273983681155882 - style*: yaml_mapping_style_t - INNER_C_UNION_9402779093446787060* = object {.union.} - scalar*: INNER_C_STRUCT_2771607800107246221 - sequence*: INNER_C_STRUCT_17512274596170441087 - mapping*: INNER_C_STRUCT_11518003446976276318 - yaml_node_s* = object - typ*: yaml_node_type_t - tag*: cstring - data*: INNER_C_UNION_9402779093446787060 - start_mark*: yaml_mark_t - end_mark*: yaml_mark_t -type - INNER_C_STRUCT_2411546260517137131* = object - start*: ptr yaml_node_t - endd*: ptr yaml_node_t - top*: ptr yaml_node_t - INNER_C_STRUCT_4991458144178661981* = object - start*: ptr yaml_tag_directive_t - endd*: ptr yaml_tag_directive_t - yaml_document_t* = object - nodes*: INNER_C_STRUCT_2411546260517137131 - version_directive*: ptr yaml_version_directive_t - tag_directives*: INNER_C_STRUCT_4991458144178661981 - start_implicit*: cint - end_implicit*: cint - start_mark*: yaml_mark_t - end_mark*: yaml_mark_t -type - yaml_read_handler_t* = proc (data: pointer; buffer: cstring; size: csize; - size_read: ptr csize): cint -type - yaml_simple_key_t* = object - possible*: cint - required*: cint - token_number*: csize - mark*: yaml_mark_t -type - yaml_parser_state_t* {.size: sizeof(cint).} = enum - YAML_PARSE_STREAM_START_STATE, - YAML_PARSE_IMPLICIT_DOCUMENT_START_STATE, - YAML_PARSE_DOCUMENT_START_STATE, - YAML_PARSE_DOCUMENT_CONTENT_STATE, - YAML_PARSE_DOCUMENT_END_STATE, - YAML_PARSE_BLOCK_NODE_STATE, - YAML_PARSE_BLOCK_NODE_OR_INDENTLESS_SEQUENCE_STATE, - YAML_PARSE_FLOW_NODE_STATE, - YAML_PARSE_BLOCK_SEQUENCE_FIRST_ENTRY_STATE, - YAML_PARSE_BLOCK_SEQUENCE_ENTRY_STATE, - YAML_PARSE_INDENTLESS_SEQUENCE_ENTRY_STATE, - YAML_PARSE_BLOCK_MAPPING_FIRST_KEY_STATE, - YAML_PARSE_BLOCK_MAPPING_KEY_STATE, - YAML_PARSE_BLOCK_MAPPING_VALUE_STATE, - YAML_PARSE_FLOW_SEQUENCE_FIRST_ENTRY_STATE, - YAML_PARSE_FLOW_SEQUENCE_ENTRY_STATE, - YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_KEY_STATE, - YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_VALUE_STATE, - YAML_PARSE_FLOW_SEQUENCE_ENTRY_MAPPING_END_STATE, - YAML_PARSE_FLOW_MAPPING_FIRST_KEY_STATE, - YAML_PARSE_FLOW_MAPPING_KEY_STATE, - YAML_PARSE_FLOW_MAPPING_VALUE_STATE, - YAML_PARSE_FLOW_MAPPING_EMPTY_VALUE_STATE, - YAML_PARSE_END_STATE -type - yaml_alias_data_t* = object - anchor*: cstring - index*: cint - mark*: yaml_mark_t -type - INNER_C_STRUCT_16371464751651700497* = object - start*: cstring - endd*: cstring - current*: cstring - INNER_C_UNION_14844535658673536178* = object {.union.} - string*: INNER_C_STRUCT_16371464751651700497 - file*: ptr FILE - INNER_C_STRUCT_5449995434778144246* = object - start*: cstring - endd*: cstring - pointer*: cstring - last*: cstring - INNER_C_STRUCT_1533468219873624615* = object - start*: cstring - endd*: cstring - pointer*: cstring - last*: cstring - INNER_C_STRUCT_12302340786945222376* = object - start*: ptr yaml_token_t - endd*: ptr yaml_token_t - head*: ptr yaml_token_t - tail*: ptr yaml_token_t - INNER_C_STRUCT_6311148685867902540* = object - start*: ptr cint - endd*: ptr cint - top*: ptr cint - INNER_C_STRUCT_6741121270717550011* = object - start*: ptr yaml_simple_key_t - endd*: ptr yaml_simple_key_t - top*: ptr yaml_simple_key_t - INNER_C_STRUCT_14987939425048783309* = object - start*: ptr yaml_parser_state_t - endd*: ptr yaml_parser_state_t - top*: ptr yaml_parser_state_t - INNER_C_STRUCT_11595967245106118857* = object - start*: ptr yaml_mark_t - endd*: ptr yaml_mark_t - top*: ptr yaml_mark_t - INNER_C_STRUCT_426684507395569091* = object - start*: ptr yaml_tag_directive_t - endd*: ptr yaml_tag_directive_t - top*: ptr yaml_tag_directive_t - INNER_C_STRUCT_7828170433486051057* = object - start*: ptr yaml_alias_data_t - endd*: ptr yaml_alias_data_t - top*: ptr yaml_alias_data_t - yaml_parser_t* = object - error*: yaml_error_type_t - problem*: cstring - problem_offset*: csize - problem_value*: cint - problem_mark*: yaml_mark_t - context*: cstring - context_mark*: yaml_mark_t - read_handler*: ptr yaml_read_handler_t - read_handler_data*: pointer - input*: INNER_C_UNION_14844535658673536178 - eof*: cint - buffer*: INNER_C_STRUCT_5449995434778144246 - unread*: csize - raw_buffer*: INNER_C_STRUCT_1533468219873624615 - encoding*: yaml_encoding_t - offset*: csize - mark*: yaml_mark_t - stream_start_produced*: cint - stream_end_produced*: cint - flow_level*: cint - tokens*: INNER_C_STRUCT_12302340786945222376 - tokens_parsed*: csize - token_available*: cint - indents*: INNER_C_STRUCT_6311148685867902540 - indent*: cint - simple_key_allowed*: cint - simple_keys*: INNER_C_STRUCT_6741121270717550011 - states*: INNER_C_STRUCT_14987939425048783309 - state*: yaml_parser_state_t - marks*: INNER_C_STRUCT_11595967245106118857 - tag_directives*: INNER_C_STRUCT_426684507395569091 - aliases*: INNER_C_STRUCT_7828170433486051057 - document*: ptr yaml_document_t -type - yaml_write_handler_t* = proc (data: pointer; buffer: cstring; size: csize): cint -type - yaml_emitter_state_t* {.size: sizeof(cint).} = enum - YAML_EMIT_STREAM_START_STATE, - YAML_EMIT_FIRST_DOCUMENT_START_STATE, - YAML_EMIT_DOCUMENT_START_STATE, - YAML_EMIT_DOCUMENT_CONTENT_STATE, - YAML_EMIT_DOCUMENT_END_STATE, - YAML_EMIT_FLOW_SEQUENCE_FIRST_ITEM_STATE, - YAML_EMIT_FLOW_SEQUENCE_ITEM_STATE, - YAML_EMIT_FLOW_MAPPING_FIRST_KEY_STATE, - YAML_EMIT_FLOW_MAPPING_KEY_STATE, - YAML_EMIT_FLOW_MAPPING_SIMPLE_VALUE_STATE, - YAML_EMIT_FLOW_MAPPING_VALUE_STATE, - YAML_EMIT_BLOCK_SEQUENCE_FIRST_ITEM_STATE, - YAML_EMIT_BLOCK_SEQUENCE_ITEM_STATE, - YAML_EMIT_BLOCK_MAPPING_FIRST_KEY_STATE, - YAML_EMIT_BLOCK_MAPPING_KEY_STATE, - YAML_EMIT_BLOCK_MAPPING_SIMPLE_VALUE_STATE, - YAML_EMIT_BLOCK_MAPPING_VALUE_STATE, - YAML_EMIT_END_STATE -type - INNER_C_STRUCT_12749614999235445465* = object - buffer*: cstring - size*: csize - size_written*: ptr csize - INNER_C_UNION_12199099344959672631* = object {.union.} - string*: INNER_C_STRUCT_12749614999235445465 - file*: ptr FILE - INNER_C_STRUCT_12563198298657885016* = object - start*: cstring - endd*: cstring - pointer*: cstring - last*: cstring - INNER_C_STRUCT_2333930655588273530* = object - start*: cstring - endd*: cstring - pointer*: cstring - last*: cstring - INNER_C_STRUCT_3757196451896818589* = object - start*: ptr yaml_emitter_state_t - endd*: ptr yaml_emitter_state_t - top*: ptr yaml_emitter_state_t - INNER_C_STRUCT_394143963162845597* = object - start*: ptr yaml_event_t - endd*: ptr yaml_event_t - head*: ptr yaml_event_t - tail*: ptr yaml_event_t - INNER_C_STRUCT_16850922517203281724* = object - start*: ptr cint - endd*: ptr cint - top*: ptr cint - INNER_C_STRUCT_12260090914027529514* = object - start*: ptr yaml_tag_directive_t - endd*: ptr yaml_tag_directive_t - top*: ptr yaml_tag_directive_t - INNER_C_STRUCT_1556210231363541236* = object - anchor*: cstring - anchor_length*: csize - alias*: cint - INNER_C_STRUCT_17739845129940504956* = object - handle*: cstring - handle_length*: csize - suffix*: cstring - suffix_length*: csize - INNER_C_STRUCT_2932767511639488752* = object - value*: cstring - length*: csize - multiline*: cint - flow_plain_allowed*: cint - block_plain_allowed*: cint - single_quoted_allowed*: cint - block_allowed*: cint - style*: yaml_scalar_style_t - INNER_C_STRUCT_11864533033166503222* = object - references*: cint - anchor*: cint - serialized*: cint - yaml_emitter_t* = object - error*: yaml_error_type_t - problem*: cstring - write_handler*: ptr yaml_write_handler_t - write_handler_data*: pointer - output*: INNER_C_UNION_12199099344959672631 - buffer*: INNER_C_STRUCT_12563198298657885016 - raw_buffer*: INNER_C_STRUCT_2333930655588273530 - encoding*: yaml_encoding_t - canonical*: cint - best_indent*: cint - best_width*: cint - unicode*: cint - line_break*: yaml_break_t - states*: INNER_C_STRUCT_3757196451896818589 - state*: yaml_emitter_state_t - events*: INNER_C_STRUCT_394143963162845597 - indents*: INNER_C_STRUCT_16850922517203281724 - tag_directives*: INNER_C_STRUCT_12260090914027529514 - indent*: cint - flow_level*: cint - root_context*: cint - sequence_context*: cint - mapping_context*: cint - simple_key_context*: cint - line*: cint - column*: cint - whitespace*: cint - indention*: cint - open_ended*: cint - anchor_data*: INNER_C_STRUCT_1556210231363541236 - tag_data*: INNER_C_STRUCT_17739845129940504956 - scalar_data*: INNER_C_STRUCT_2932767511639488752 - opened*: cint - closed*: cint - anchors*: ptr INNER_C_STRUCT_11864533033166503222 - last_anchor_id*: cint - document*: ptr yaml_document_t - -{.push importc, cdecl.} -proc yaml_get_version_string*(): cstring -proc yaml_get_version*(major: ptr cint; minor: ptr cint; patch: ptr cint) -proc yaml_token_delete*(token: ptr yaml_token_t) -proc yaml_stream_start_event_initialize*(event: ptr yaml_event_t; - encoding: yaml_encoding_t): cint -proc yaml_stream_end_event_initialize*(event: ptr yaml_event_t): cint -proc yaml_document_start_event_initialize*(event: ptr yaml_event_t; - version_directive: ptr yaml_version_directive_t; - tag_directives_start: ptr yaml_tag_directive_t; - tag_directives_end: ptr yaml_tag_directive_t; implicit: cint): cint -proc yaml_document_end_event_initialize*(event: ptr yaml_event_t; implicit: cint): cint -proc yaml_alias_event_initialize*(event: ptr yaml_event_t; - anchor: cstring): cint -proc yaml_scalar_event_initialize*(event: ptr yaml_event_t; - anchor: cstring; - tag: cstring; value: cstring; - length: cint; plain_implicit: cint; - quoted_implicit: cint; - style: yaml_scalar_style_t): cint -proc yaml_sequence_start_event_initialize*(event: ptr yaml_event_t; - anchor: cstring; tag: cstring; implicit: cint; - style: yaml_sequence_style_t): cint -proc yaml_sequence_end_event_initialize*(event: ptr yaml_event_t): cint -proc yaml_mapping_start_event_initialize*(event: ptr yaml_event_t; - anchor: cstring; tag: cstring; implicit: cint; - style: yaml_mapping_style_t): cint -proc yaml_mapping_end_event_initialize*(event: ptr yaml_event_t): cint -proc yaml_event_delete*(event: ptr yaml_event_t) -proc yaml_document_initialize*(document: ptr yaml_document_t; - version_directive: ptr yaml_version_directive_t; - tag_directives_start: ptr yaml_tag_directive_t; - tag_directives_end: ptr yaml_tag_directive_t; - start_implicit: cint; end_implicit: cint): cint -proc yaml_document_delete*(document: ptr yaml_document_t) -proc yaml_document_get_node*(document: ptr yaml_document_t; index: cint): ptr yaml_node_t -proc yaml_document_get_root_node*(document: ptr yaml_document_t): ptr yaml_node_t -proc yaml_document_add_scalar*(document: ptr yaml_document_t; - tag: cstring; value: cstring; - length: cint; style: yaml_scalar_style_t): cint -proc yaml_document_add_sequence*(document: ptr yaml_document_t; - tag: cstring; - style: yaml_sequence_style_t): cint -proc yaml_document_add_mapping*(document: ptr yaml_document_t; - tag: cstring; - style: yaml_mapping_style_t): cint -proc yaml_document_append_sequence_item*(document: ptr yaml_document_t; - sequence: cint; item: cint): cint -proc yaml_document_append_mapping_pair*(document: ptr yaml_document_t; - mapping: cint; key: cint; value: cint): cint -proc yaml_parser_initialize*(parser: ptr yaml_parser_t): cint -proc yaml_parser_delete*(parser: ptr yaml_parser_t) -proc yaml_parser_set_input_string*(parser: ptr yaml_parser_t; input: cstring; - size: csize) -proc yaml_parser_set_input_file*(parser: ptr yaml_parser_t; file: ptr FILE) -proc yaml_parser_set_input*(parser: ptr yaml_parser_t; - handler: ptr yaml_read_handler_t; data: pointer) -proc yaml_parser_set_encoding*(parser: ptr yaml_parser_t; - encoding: yaml_encoding_t) -proc yaml_parser_scan*(parser: ptr yaml_parser_t; token: ptr yaml_token_t): cint -proc yaml_parser_parse*(parser: ptr yaml_parser_t; event: ptr yaml_event_t): cint -proc yaml_parser_load*(parser: ptr yaml_parser_t; document: ptr yaml_document_t): cint -proc yaml_emitter_initialize*(emitter: ptr yaml_emitter_t): cint -proc yaml_emitter_delete*(emitter: ptr yaml_emitter_t) -proc yaml_emitter_set_output_string*(emitter: ptr yaml_emitter_t; - output: cstring; size: csize; - size_written: ptr csize) -proc yaml_emitter_set_output_file*(emitter: ptr yaml_emitter_t; file: ptr FILE) -proc yaml_emitter_set_output*(emitter: ptr yaml_emitter_t; - handler: ptr yaml_write_handler_t; data: pointer) -proc yaml_emitter_set_encoding*(emitter: ptr yaml_emitter_t; - encoding: yaml_encoding_t) -proc yaml_emitter_set_canonical*(emitter: ptr yaml_emitter_t; canonical: cint) -proc yaml_emitter_set_indent*(emitter: ptr yaml_emitter_t; indent: cint) -proc yaml_emitter_set_width*(emitter: ptr yaml_emitter_t; width: cint) -proc yaml_emitter_set_unicode*(emitter: ptr yaml_emitter_t; unicode: cint) -proc yaml_emitter_set_break*(emitter: ptr yaml_emitter_t; - line_break: yaml_break_t) -proc yaml_emitter_emit*(emitter: ptr yaml_emitter_t; event: ptr yaml_event_t): cint -proc yaml_emitter_open*(emitter: ptr yaml_emitter_t): cint -proc yaml_emitter_close*(emitter: ptr yaml_emitter_t): cint -proc yaml_emitter_dump*(emitter: ptr yaml_emitter_t; - document: ptr yaml_document_t): cint -proc yaml_emitter_flush*(emitter: ptr yaml_emitter_t): cint -{.pop.} - -when system.hostOS == "linux": - {.link: "/usr/lib/x86_64-linux-gnu/libyaml-0.so.2".} -elif system.hostOS == "macosx": - {.link: "/Users/flyx/.nix-profile/lib/libyaml-0.2.dylib"} \ No newline at end of file diff --git a/lib/yaml/bench/nimlets_yaml.nim b/lib/yaml/bench/nimlets_yaml.nim deleted file mode 100644 index afd465a..0000000 --- a/lib/yaml/bench/nimlets_yaml.nim +++ /dev/null @@ -1,556 +0,0 @@ -# This code is taken from https://github.com/nimlets/nimlets -# and has been slightly modified to fit our needs. - -import lib.libyaml -from tables import Table, initTable, `[]`, `[]=`, pairs, `==` -from strutils import parseInt, parseFloat, `%` -from hashes import hash, THash, `!&`, `!$` -from typetraits import name -import unsigned - -type - YamlObjKind* {.pure.} = enum - Seq - Map - String - Null - Bool - Int - Float - Document - YamlObj* = ref object - case kind: YamlObjKind - of YamlObjKind.Map: - mapVal: Table[YamlObj, YamlObj] - of YamlObjKind.Seq: - seqVal: seq[YamlObj] - of YamlObjKind.String: - strVal: string - of YamlObjKind.Bool: - boolVal: bool - of YamlObjKind.Int: - intVal: int - of YamlObjKind.Float: - floatVal: float64 - of YamlObjKind.Null: - nil - of YamlObjKind.Document: - nil - YamlDoc* = YamlObj - -proc objKind*(obj: YamlObj): YamlObjKind = obj.kind - -# hash & == {{{ -proc hash*(self: YamlObj): THash = - result = 0 - result = result !& ord(self.kind) - case self.kind - of YamlObjKind.Map: - for k, v in self.mapVal: - result = result !& hash(k) - result = result !& hash(v) - of YamlObjKind.Seq: - for v in self.seqVal: - result = result !& hash(v) - of YamlObjKind.String: - result = result !& hash(self.strVal) - of YamlObjKind.Bool: - result = result !& ord(self.boolVal) - of YamlObjKind.Int: - result = result !& hash(self.intVal) - of YamlObjKind.Float: - result = result !& hash(self.floatVal) - of YamlObjKind.Null, YamlObjKind.Document: - discard - -proc `==`*(a, b: YamlObj): bool = - if a.kind != b.kind: return false - case a.kind - of YamlObjKind.Map: - if a.mapVal != b.mapVal: return false - of YamlObjKind.Seq: - if a.seqVal != b.seqVal: return false - of YamlObjKind.String: - if a.strVal != b.strVal: return false - of YamlObjKind.Bool: - if a.boolVal != b.boolVal: return false - of YamlObjKind.Int: - if a.intVal != b.intVal: return false - of YamlObjKind.Float: - if a.floatVal != b.floatVal: return false - of YamlObjKind.Null, YamlObjKind.Document: - discard - return true -# }}} - -template success(test: expr): stmt = - if test != 1: raise newException(Exception, "failed to execute") - -# `load()` Internals {{{ -type - LoadContext = ref object - parser: yaml_parser_t - anchors: Table[string, YamlObj] - gen: iterator(): yaml_event_t {.closure.} - -proc copyEvent(self: yaml_event_t): tuple[typ: yaml_event_type_t, anchor: string] = - # not for general-purpose use - if self.data.scalar.anchor == nil: - return - return (self.typ, $self.data.scalar.anchor) - -proc handleAnchors(self: LoadContext, - event: tuple[typ: yaml_event_type_t, anchor: string], - result: YamlObj) = - if event.typ in { YAML_SCALAR_EVENT, - YAML_SEQUENCE_START_EVENT, - YAML_MAPPING_START_EVENT }: - # first element in each branch, so is equvilent for all three - let anchor = event.anchor - - if anchor != nil: - self.anchors[anchor] = result - -proc events(self: LoadContext): iterator(): yaml_event_t = - # returned events must be copied before this run again - return iterator(): yaml_event_t = - var event: yaml_event_t - while true: - if yaml_parser_parse(addr self.parser, addr event) != 1: - raise newException(Exception, $self.parser.error & ": " & $self.parser.problem) - - if event.typ == YAML_NO_EVENT: - break - - yield event - - yaml_event_delete(addr event) - -var recognize: array[yaml_event_type_t, proc(self: LoadContext, event: yaml_event_t): YamlObj {.nimcall.}] - -recognize[YAML_DOCUMENT_START_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - let next = self.gen() - result = recognize[next.typ](self, next) - let endDoc = self.gen() - assert(endDoc.typ == YAML_DOCUMENT_END_EVENT, "Document must only have one thing inside") - - -recognize[YAML_ALIAS_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - return self.anchors[$event.data.alias.anchor] - - -recognize[YAML_SCALAR_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - var tag: string - if event.data.scalar.tag != nil: - tag = $event.data.scalar.tag - - case tag - of YAML_NULL_TAG: return YamlObj(kind : YamlObjKind.Null) - of YAML_BOOL_TAG: - result = YamlObj(kind : YamlObjKind.Bool) - case $event.data.scalar.value - of "true": result.boolVal = true - of "false": result.boolVal = false - else: assert(false, - "Unknown boolean value \"" & $event.data.scalar.value & '\"') - of YAML_INT_TAG: - return YamlObj(kind : YamlObjKind.Int, intVal : parseInt($event.data.scalar.value)) - of YAML_FLOAT_TAG: - return YamlObj(kind : YamlObjKind.Float, floatVal : parseFloat($event.data.scalar.value)) - else: # unknown or string, treat as string - return YamlObj(kind : YamlObjKind.String, strVal : $event.data.scalar.value) - - -recognize[YAML_SEQUENCE_START_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - let initialEvent = copyEvent event - - result = YamlObj(kind : YamlObjKind.Seq, seqVal : @[]) - - var event = event - while true: - event = self.gen() - if event.typ == YAML_SEQUENCE_END_EVENT: break - result.seqVal.add(recognize[event.typ](self, event)) - - self.handleAnchors(initialEvent, result) - - -recognize[YAML_MAPPING_START_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - let initialEvent = copyEvent event - - result = YamlObj(kind : YamlObjKind.Map, mapVal : initTable[YamlObj, YamlObj]()) - - while true: - let keyEvent = self.gen() - if keyEvent.typ == YAML_MAPPING_END_EVENT: break - let key = recognize[keyEvent.typ](self, keyEvent) - - let valEvent = self.gen() - let val = recognize[valEvent.typ](self, valEvent) - - result.mapVal[key] = val - - self.handleAnchors(initialEvent, result) - - -recognize[YAML_SEQUENCE_END_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - assert(false, "Sequence end event should never be triggered") - - -recognize[YAML_MAPPING_END_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - assert(false, "Mapping end event should never be triggered") - - -recognize[YAML_DOCUMENT_END_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - assert(false, "Document end event should never be triggered") - - -recognize[YAML_STREAM_END_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - assert(false, "Stream end event should never be triggered") - - -recognize[YAML_NO_EVENT] = proc(self: LoadContext, event: yaml_event_t): YamlObj = - discard -# }}} - -proc load*(text: string): seq[YamlDoc] = - ## Parses the sequence of YAML documents in `text` - ## - ## Note: while the YAML specification allows non-scalar - ## mapping keys, this does not. - var parser: yaml_parser_t - success yaml_parser_initialize(addr parser) - - var loadCtx = LoadContext(parser : parser, - anchors : initTable[string, YamlObj]() ) - - yaml_parser_set_input_string(addr loadCtx.parser, text, csize(text.len)) - yaml_parser_set_encoding(addr loadCtx.parser, YAML_UTF8_ENCODING) - loadCtx.gen = loadCtx.events() - - result = @[] - - var event = loadCtx.gen() - assert(event.typ == YAML_STREAM_START_EVENT, "first event must be a YAML_STREAM_START_EVENT") - while true: - event = loadCtx.gen() - if event.typ == YAML_STREAM_END_EVENT: break - result.add(recognize[event.typ](loadCtx, event)) - - yaml_parser_delete(addr loadCtx.parser) - -# `$`() Internals {{{ -type - StringifyContext = ref object - emitter: yaml_emitter_t - result: string - -proc emit(ctx: StringifyContext, event: ptr yaml_event_t) = - if yaml_emitter_emit(addr ctx.emitter, event) != 1: - raise newException(Exception, "Failed to emit event: " & - $ctx.emitter.problem) - -var renderers: array[YamlObjKind, proc(self: YamlObj, ctx: StringifyContext) {.nimcall.}] - -renderers[YamlObjKind.Seq] = proc(self: YamlObj, ctx: StringifyContext) = - var event = create(yaml_event_t) - success yaml_sequence_start_event_initialize(event, nil, nil, 1, YAML_ANY_SEQUENCE_STYLE) - ctx.emit(event) - - for elem in self.seqVal: - renderers[elem.kind](elem, ctx) - - success yaml_sequence_end_event_initialize(event) - ctx.emit(event) - - dealloc event - - -renderers[YamlObjKind.Map] = proc(self: YamlObj, ctx: StringifyContext) = - var event = create(yaml_event_t) - success yaml_mapping_start_event_initialize(event, nil, nil, 1, YAML_ANY_MAPPING_STYLE) - ctx.emit(event) - - for k, v in self.mapVal: - renderers[k.kind](k, ctx) - renderers[v.kind](v, ctx) - - success yaml_mapping_end_event_initialize(event) - ctx.emit(event) - - dealloc event - - -renderers[YamlObjKind.String] = proc(self: YamlObj, ctx: StringifyContext) = - var event = create(yaml_event_t) - success yaml_scalar_event_initialize(event, nil, - YAML_STR_TAG, - self.strVal, - self.strVal.len.cint, - 1, 1, YAML_ANY_SCALAR_STYLE) - ctx.emit(event) - dealloc event - - -renderers[YamlObjKind.Null] = proc(self: YamlObj, ctx: StringifyContext) = - var event = create(yaml_event_t) - success yaml_scalar_event_initialize(event, nil, - YAML_NULL_TAG, - "null", - "null".len, - 1, 1, YAML_ANY_SCALAR_STYLE) - ctx.emit(event) - dealloc event - - -renderers[YamlObjKind.Bool] = proc(self: YamlObj, ctx: StringifyContext) = - var event = create(yaml_event_t) - success yaml_scalar_event_initialize(event, nil, - YAML_BOOL_TAG, - $self.boolVal, - ($self.boolVal).len.cint, - 1, 1, YAML_ANY_SCALAR_STYLE) - ctx.emit(event) - dealloc event - - -renderers[YamlObjKind.Int] = proc(self: YamlObj, ctx: StringifyContext) = - var event = create(yaml_event_t) - success yaml_scalar_event_initialize(event, nil, - YAML_INT_TAG, - $self.intVal, - ($self.intVal).len.cint, - 1, 1, YAML_ANY_SCALAR_STYLE) - ctx.emit(event) - dealloc event - - -renderers[YamlObjKind.Float] = proc(self: YamlObj, ctx: StringifyContext) = - var event = create(yaml_event_t) - success yaml_scalar_event_initialize(event, nil, - YAML_FLOAT_TAG, - $self.floatVal, - ($self.floatVal).len.cint, - 1, 1, YAML_ANY_SCALAR_STYLE) - ctx.emit(event) - dealloc event - - -renderers[YamlObjKind.Document] = proc(self: YamlObj, ctx: StringifyContext) = - assert(false, "Document should never be used as a Yaml object") - -# }}} - -proc `$`*(input: seq[YamlDoc], - indent: int = 2, - maxWidth: int = 80): string = - ## Stringifies the sequence of YAML documents - ## - ## `indent` - the size of the indentation - ## `maxWidth` - the level at which it should be - ## wrapped, -1 means no wrapping - var ctx = StringifyContext( result : "" ) - - success yaml_emitter_initialize(addr ctx.emitter) - - yaml_emitter_set_output( - addr ctx.emitter, - cast[ptr yaml_write_handler_t]( - proc(ctx: ptr StringifyContext, buffer: pointer, size: csize): cint {.nimcall.}= - var bufferString = newString(size) - moveMem(cstring(bufferString), buffer, size) - ctx.result.add(bufferString) - return 1 - ), - addr ctx) - yaml_emitter_set_encoding(addr ctx.emitter, YAML_UTF8_ENCODING) - yaml_emitter_set_canonical(addr ctx.emitter, 0) - yaml_emitter_set_indent(addr ctx.emitter, indent.cint) - yaml_emitter_set_unicode(addr ctx.emitter, 1) - - var event = create(yaml_event_t) - - success yaml_stream_start_event_initialize(event, YAML_UTF8_ENCODING) - ctx.emit(event) - - for doc in input: - success yaml_document_start_event_initialize(event, nil, nil, nil, 1) - ctx.emit(event) - - renderers[doc.kind](doc, ctx) - - success yaml_document_end_event_initialize(event, 1) - ctx.emit(event) - - success yaml_stream_end_event_initialize(event) - ctx.emit(event) - - dealloc event - - yaml_emitter_delete(addr ctx.emitter) - - return ctx.result - -proc `$`*(val: YamlObj, - maxWidth: int = 80, - indent: int = 2): string = - let docSeq = @[val] - return `$`(docSeq, maxWidth = maxWidth, indent = indent) - -# Navigation {{{ -const # errors - eKeyInScalar = "Cannot look up key in a scalar" - eKeyInScalarSeq = "Cannot look up key in scalar or sequence" - eScalarType = "Type $2 is incompatible with scalar type $1" - eCollectionNotScalar = "Cannot retrieve values from collections, only scalars" - eMalformedCollection = "Cannot create $1, field mismatch" - eNotIterable = "Cannot iterate over $1" - - -proc yamlize*(val: YamlObj): YamlObj = - return val - -proc yamlize*(val: int): YamlObj = - return YamlObj(kind : YamlObjKind.Int, intVal : int(val)) - -proc yamlize*(val: uint): YamlObj = - doAssert(val shr 63 != 1) # prevent overflow - return YamlObj(kind : YamlObjKind.Int, intVal : int(val)) - -proc yamlize*(val: string): YamlObj = - if val == nil: - return YamlObj(kind : YamlObjKind.Null) - else: - return YamlObj(kind : YamlObjKind.String, strVal : val) - -proc yamlize*(val: bool): YamlObj = - return YamlObj(kind : YamlObjKind.Bool, boolVal : val) - -proc yamlize*(val: float): YamlObj = - return YamlObj(kind : YamlObjKind.Float, floatVal : float64(val)) - -proc yamlize*[T](val: T): YamlObj = - result = YamlObj(kind : YamlObjKind.Map, mapVal : initTable[YamlObj, YamlObj]()) - for name, val in fieldPairs(val): - result[yamlize(name)] = yamlize(val) - -proc yamlize*[T](val: ref T): YamlObj = - if val == nil: - return YamlObj(kind : YamlObjKind.Null) - else: - return yamlize(val[]) - -proc yamlize*[I, K, V](val: array[I, tuple[k: K, v: V]]): YamlObj = - ## Yamizes a map literal: - ## - ## yamlize({ "foo" : "bar", "obj1" : "obj2}) - result = YamlObj(kind : YamlObjKind.Map, mapVal : initTable()) - for pair in val: - let (k, v) = pair - result.mapVal[yamlize(k)] = yamlize(v) - -proc yamlize*[V](val: openarray[V]): YamlObj = - result = YamlObj(kind : YamlObjKind.Seq, seqVal : @[]) - for v in val: - result.seqVal.add(yamlize(val)) - - -proc `[]`*(self: YamlObj, key: int): YamlObj = - case self.kind - of YamlObjKind.Seq: - return self.seqVal[key] - of YamlObjKind.Map: - return self.mapVal[yamlize(key)] - else: - raise newException(ValueError, eKeyInScalar) - -proc `[]`*[T](self: YamlObj, key: T): YamlObj = - case self.kind - of YamlObjKind.Map: - return self.mapVal[yamlize(key)] - else: - raise newException(ValueError, eKeyInScalarSeq) - - -proc `[]=`*[V](self: YamlObj, key: int, val: V) = - case self.kind - of YamlObjKind.Seq: - self.seqVal[key] = yamlize(val) - of YamlObjKind.Map: - self.mapVal[yamlize(key)] = yamlize(val) - else: - raise newException(ValueError, eKeyInScalar) - -proc `[]=`*[T, V](self: YamlObj, key: T, val: V) = - case self.kind - of YamlObjKind.Map: - self.mapVal[yamlize(key)] = yamlize(val) - else: - raise newException(ValueError, eKeyInScalarSeq) - - -iterator items*(self: YamlObj): YamlObj = - case self.kind - of YamlObjKind.Seq: - for v in self.seqVal: - yield v - else: - raise newException(ValueError, eNotIterable % [$self.kind]) - -iterator pairs*(self: YamlObj): tuple[idx: int, val: YamlObj] = - case self.kind - of YamlObjKind.Seq: - for i, v in self.seqVal: - yield (i, v) - else: - raise newException(ValueError, eNotIterable % [$self.kind]) - -iterator pairs*(self: YamlObj): tuple[key, val: YamlObj] = - case self.kind - of YamlObjKind.Map: - for k, v in self.mapVal: - yield (k, v) - else: - raise newException(ValueError, eNotIterable % [$self.kind]) - -proc `.`*(self: YamlObj, key: string): YamlObj = - return self[key] - -proc `.=`*[T](self: YamlObj, key: string, val: T): YamlObj = - self[key] = val - - -proc get*(self: YamlObj, T: typedesc): T = - if self.kind == YamlObjKind.Int: - when not compiles(int(result)): - raise newException(ValueError, eScalarType % [$self.kind, name T]) - else: - return self.intVal - - if self.kind == YamlObjKind.Float: - when not compiles(float(result)): - raise newException(ValueError, eScalarType % [$self.kind, name T]) - else: - return self.floatVal - - if self.kind == YamlObjKind.Bool: - when not compiles(bool(result)): - raise newException(ValueError, eScalarType % [$self.kind, name T]) - else: - return self.boolVal - - if self.kind == YamlObjKind.String: - when not compiles(string(result)): - raise newException(ValueError, eScalarType % [$self.kind, name T]) - else: - return self.strVal - - if self.kind == YamlObjKind.Null: - when not compiles(result[]): - raise newException(ValueError, eScalarType % [$self.kind, name T]) - else: - return nil - - raise newException(ValueError, eCollectionNotScalar) - -# }}} diff --git a/lib/yaml/bench/yamlBench.nim b/lib/yaml/bench/yamlBench.nim deleted file mode 100644 index 9cb2e6d..0000000 --- a/lib/yaml/bench/yamlBench.nim +++ /dev/null @@ -1,202 +0,0 @@ -import "../yaml", commonBench -import math, strutils, stopwatch, terminal, algorithm, random, streams - -from nimlets_yaml import objKind - -type - Level = tuple - kind: YamlNodeKind - len: int - -proc genString(maxLen: int): string = - let len = random(maxLen) - result = "" - for i in 1 .. len: result.add(cast[char](random(127 - 32) + 32)) - -proc genBlockString(): string = - let lines = 5 + random(10) - let flow = random(2) == 0 - result = "" - for i in 1 .. lines: - let lineLen = 32 + random(12) - for i in i .. lineLen: result.add(cast[char](random(127 - 33) + 33)) - result.add(if flow: ' ' else: '\l') - result.add('\l') - -proc genKey(): string = - let genPossiblePlainKey = random(1.0) < 0.75 - if genPossiblePlainKey: - result = "" - let len = random(24) + 1 - for i in 1 .. len: - let c = random(26 + 26 + 10) - if c < 26: result.add(char(c + 65)) - elif c < 52: result.add(char(c + 97 - 26)) - else: result.add(char(c + 48 - 52)) - else: result = genString(31) & char(random(26) + 65) - -proc genYamlString(size: int, maxStringLen: int, - style: PresentationStyle): string = - ## Generates a random YAML string. - ## size is in KiB, mayStringLen in characters. - - randomize(size * maxStringLen * ord(style)) - - let targetSize = size * 1024 - var - target = newStringStream() - input = iterator(): YamlStreamEvent = - var - levels = newSeq[Level]() - curSize = 1 - levels.add((kind: yMapping, len: 0)) - yield startDocEvent() - yield startMapEvent() - - while levels.len > 0: - let - objectCloseProbability = - float(levels[levels.high].len + levels.high) * 0.025 - closeObject = random(1.0) <= objectCloseProbability - - if (closeObject and levels.len > 1) or curSize > targetSize: - case levels[levels.high].kind - of yMapping: yield endMapEvent() - of ySequence: yield endSeqEvent() - else: assert(false) - curSize += 1 - discard levels.pop() - continue - - levels[levels.high].len += 1 - if levels[levels.high].kind == yMapping: - let key = genKey() - yield scalarEvent(key) - - let - objectValueProbability = - 0.8 / float(levels.len * levels.len) - generateObjectValue = random(1.0) <= objectValueProbability - hasTag = random(2) == 0 - var tag = yTagQuestionMark - - if generateObjectValue: - let objectKind = if random(3) == 0: ySequence else: yMapping - case objectKind - of yMapping: - if hasTag: tag = yTagMapping - yield startMapEvent(tag) - of ySequence: - if hasTag: tag = yTagSequence - yield startSeqEvent(tag) - else: assert(false) - curSize += 1 - levels.add((kind: objectKind, len: 0)) - else: - var s: string - case random(11) - of 0..4: - s = genString(maxStringLen) - if hasTag: tag = yTagString - of 5: - s = genBlockString() - of 6..7: - s = $random(32000) - if hasTag: tag = yTagInteger - of 8..9: - s = $(random(424242.4242) - 212121.21) - if hasTag: tag = yTagFloat - of 10: - case random(3) - of 0: - s = "true" - if hasTag: tag = yTagBoolean - of 1: - s = "false" - if hasTag: tag = yTagBoolean - of 2: - s = "null" - if hasTag: tag = yTagNull - else: discard - else: discard - - yield scalarEvent(s, tag) - curSize += s.len - yield endDocEvent() - var yStream = initYamlStream(input) - present(yStream, target, initExtendedTagLibrary(), - defineOptions(style=style, outputVersion=ov1_1)) - result = target.data - -var - cYaml1k, cYaml10k, cYaml100k, cLibYaml1k, cLibYaml10k, cLibYaml100k, - cYaml1m, cLibYaml1m: int64 - yaml1k = genYamlString(1, 32, psDefault) - yaml10k = genYamlString(10, 32, psDefault) - yaml100k = genYamlString(100, 32, psDefault) - yaml1m = genYamlString(1000, 32, psDefault) - tagLib = initExtendedTagLibrary() - parser = newYamlParser(tagLib) - -block: - multibench(cYaml1k, 100): - let res = loadDOM(yaml1k) - assert res.root.kind == yMapping - -block: - multibench(cYaml10k, 100): - let res = loadDOM(yaml10k) - assert res.root.kind == yMapping - -block: - multibench(cYaml100k, 100): - let res = loadDOM(yaml100k) - assert res.root.kind == yMapping - -block: - multibench(cYaml1m, 2): - let res = loadDOM(yaml1m) - assert res.root.kind == yMapping - -block: - multibench(cLibYaml1k, 100): - let res = nimlets_yaml.load(yaml1k) - assert res[0].objKind == nimlets_yaml.YamlObjKind.Map - -block: - multibench(cLibYaml10k, 100): - let res = nimlets_yaml.load(yaml10k) - assert res[0].objKind == nimlets_yaml.YamlObjKind.Map - -block: - multibench(cLibYaml100k, 100): - let res = nimlets_yaml.load(yaml100k) - assert res[0].objKind == nimlets_yaml.YamlObjKind.Map - -block: - multibench(cLibYaml1m, 2): - let res = nimlets_yaml.load(yaml1m) - assert res[0].objKind == nimlets_yaml.YamlObjKind.Map - -proc writeResult(caption: string, num: int64) = - styledWriteLine(stdout, resetStyle, caption, fgGreen, $num, resetStyle, "μs") - -setForegroundColor(fgWhite) - -writeStyled "Benchmark: Processing YAML input\n" -writeStyled "================================\n" -writeStyled "1k input\n--------\n" -writeResult "NimYAML: ", cYaml1k div 1000 -writeResult "LibYAML: ", cLibYaml1k div 1000 -setForegroundColor(fgWhite) -writeStyled "10k input\n---------\n" -writeResult "NimYAML: ", cYaml10k div 1000 -writeResult "LibYAML: ", cLibYaml10k div 1000 -setForegroundColor(fgWhite) -writeStyled "100k input\n----------\n" -writeResult "NimYAML: ", cYaml100k div 1000 -writeResult "LibYAML: ", cLibYaml100k div 1000 -setForegroundColor(fgWhite) -writeStyled "1m input\n---------\n" -writeResult "NimYAML: ", cYaml1m div 1000 -writeResult "LibYAML: ", cLibYaml1m div 1000 diff --git a/lib/yaml/config.nims b/lib/yaml/config.nims deleted file mode 100644 index d35a93d..0000000 --- a/lib/yaml/config.nims +++ /dev/null @@ -1,80 +0,0 @@ -task build, "Compile the YAML module into a library": - --app:lib - --d:release - setCommand "c", "yaml" - -task test, "Run all tests": - --r - --verbosity:0 - setCommand "c", "test/tests" - -task lexerTests, "Run lexer tests": - --r - --verbosity:0 - setCommand "c", "test/tlex" - -task parserTests, "Run parser tests": - --r - --verbosity:0 - setCommand "c", "test/tparser" - -task jsonTests, "Run JSON tests": - --r - --verbosity:0 - setCommand "c", "test/tjson" - -task domTests, "Run DOM tests": - --r - --verbosity:0 - setCommand "c", "test/tdom" - -task serializationTests, "Run serialization tests": - --r - --verbosity:0 - setCommand "c", "test/tserialization" - -task quickstartTests, "Run quickstart tests": - --r - --verbosity:0 - setCommand "c", "test/tquickstart" - -task documentation, "Generate documentation": - exec "mkdir -p docout" - withDir "doc": - exec r"nim c rstPreproc" - exec r"./rstPreproc -o:tmp.rst index.txt" - exec r"nim rst2html -o:../docout/index.html tmp.rst" - exec r"./rstPreproc -o:tmp.rst api.txt" - exec r"nim rst2html -o:../docout/api.html tmp.rst" - exec r"./rstPreproc -o:tmp.rst serialization.txt" - exec r"nim rst2html -o:../docout/serialization.html tmp.rst" - exec r"nim rst2html -o:../docout/testing.html testing.rst" - exec r"nim rst2html -o:../docout/schema.html schema.rst" - exec "cp docutils.css style.css processing.svg ../docout" - exec r"nim doc2 -o:docout/yaml.html --docSeeSrcUrl:https://github.com/flyx/NimYAML/blob/`git log -n 1 --format=%H` yaml" - for file in listFiles("yaml"): - let packageName = file[5..^5] - exec r"nim doc2 -o:docout/yaml." & packageName & - ".html --docSeeSrcUrl:https://github.com/flyx/NimYAML/blob/yaml/`git log -n 1 --format=%H` " & - file - setCommand "nop" - -task bench, "Benchmarking": - --r - --w:off - --hints:off - --d:release - setCommand "c", "bench/bench" - -task clean, "Remove all generated files": - exec "rm -rf libyaml.* test/tests test/parsing test/lexing bench/json docout" - setCommand "nop" - -task server, "Compile server daemon": - --d:release - --d:yamlScalarRepInd - setCommand "c", "server/server" - -task testSuiteEvents, "Compile the testSuiteEvents tool": - --d:release - setCommand "c", "tools/testSuiteEvents" diff --git a/lib/yaml/copying.txt b/lib/yaml/copying.txt deleted file mode 100644 index 9e5aef7..0000000 --- a/lib/yaml/copying.txt +++ /dev/null @@ -1,24 +0,0 @@ -===================================================== -NimYAML -- YAML implementation in Nim. - -Copyright (C) 2015 Felix Krause. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -[ MIT license: http://www.opensource.org/licenses/mit-license.php ] \ No newline at end of file diff --git a/lib/yaml/doc/api.txt b/lib/yaml/doc/api.txt deleted file mode 100644 index 9d38333..0000000 --- a/lib/yaml/doc/api.txt +++ /dev/null @@ -1,111 +0,0 @@ -============ -API Overview -============ - -Introduction -============ - -NimYAML advocates parsing YAML input into native Nim types. Basic Nim library -types like integers, floats and strings, as well as all tuples, enums and -objects without private fields are supported out-of-the-box. Reference types are -also supported, and NimYAML is able to detect if a reference occurs more than -once and will serialize it accordingly. This means that NimYAML is able to dump -and load potentially cyclic objects. - -While loading into and dumping from native Nim types is the preferred way to use -NimYAML, it also gives you complete control over each processing step, so that -you can for example only use the parser and process its event stream yourself. -The following diagram gives an overview of NimYAML's features based on the YAML -processing pipeline. The items and terminology YAML defines is shown in -*italic*, NimYAML's implementation name is shown in **bold**. - -.. image:: processing.svg - -Intermediate Representation -=========================== - -The base of all YAML processing with NimYAML is the -`YamlStream `_. This is basically an iterator over -`YamlStreamEvent `_ objects. Every proc that -represents a single stage of the loading or dumping process will either take a -``YamlStream`` as input or return a ``YamlStream``. Procs that implement the -whole process in one step hide the ``YamlStream`` from the user. Every proc that -returns a ``YamlStream`` guarantees that this stream is well-formed according to -the YAML specification. - -This stream-oriented API can efficiently be used to parse large amounts of data. -The drawback is that errors in the input are only discovered while processing -the ``YamlStream``. If the ``YamlStream`` encounters an exception while -producing the next event, it will throw a ``YamlStreamError`` which contains the -original exception as ``parent``. The caller should know which exceptions are -possible as parents of ``YamlStream`` because they know the source of the -``YamlStream`` they provided. - -Loading YAML -============ - -If you want to load YAML character data directly into a native Nim variable, you -can use `load `_. This is the easiest and -recommended way to load YAML data. This section gives an overview about how -``load`` is implemented. It is absolutely possible to reimplement the loading -step using the low-level API. - -For parsing, a `YamlParser `_ object is needed. -This object stores some state while parsing that may be useful for error -reporting to the user. The `parse `_ -proc implements the YAML processing step of the same name. All syntax errors in -the input character stream are processed by ``parse``, which will raise a -``YamlParserError`` if it encounters a syntax error. - -Transforming a ``YamlStream`` to a native YAML object is done via -``construct``. It skips the ``compose`` step for efficiency reasons. As Nim is -statically typed, you have to know the target type when you write your loading -code. This is different from YAML APIs of dynamically typed languages. If you -cannot know the type of your YAML input at compile time, you have to manually -process the ``YamlStream`` to serve your needs. - -Dumping YAML -============ - -Dumping is preferredly done with -`dump `_, -which serializes a native Nim variable to a character stream. As with ``load``, -the following paragraph describes how ``dump`` is implemented using the -low-level API. - -A Nim value is transformed into a ``YamlStream`` with -`represent `_. -Depending on the ``AnchorStyle`` you specify, this will transform ``ref`` -variables with multiple instances into anchored elements and aliases (for -``asTidy`` and ``asAlways``) or write the same element into all places it -occurs (for ``asNone``). Be aware that if you use ``asNone``, the value you -serialize might not round-trip. - -Transforming a ``YamlStream`` into YAML character data is done with -`present `_. -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/lib/yaml/doc/docutils.css b/lib/yaml/doc/docutils.css deleted file mode 100644 index 89f357f..0000000 --- a/lib/yaml/doc/docutils.css +++ /dev/null @@ -1,1124 +0,0 @@ -/* -Stylesheet for use with Docutils/rst2html. - -See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to -customize this style sheet. - -Modified from Chad Skeeters' rst2html-style -https://bitbucket.org/cskeeters/rst2html-style/ - -Modified by Boyd Greenfield -*/ -/* SCSS variables */ -/* Text weights */ -/* Body colors */ -/* Text colors */ -/* Link colors */ -/* Syntax highlighting colors */ -/* Pct changes */ -/* Mixins */ -/* Body/layout */ -html { - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; } - -/* Where we want fancier font if available */ -h1, h2, h3, h4, h5, h6, p.module-desc, table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p { - font-family: "Raleway", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important; } - -h1.title { - font-weight: 900; } - -article { - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; - font-weight: 400; - font-size: 14px; - line-height: 20px; - color: #666; - - position: relative; - width: 100%; - max-width: 960px; - margin: 0 auto; - padding: 0 20px; - box-sizing: border-box; } - -.column, -.columns { - width: 100%; - float: left; - box-sizing: border-box; } - -/* For devices larger than 400px */ -@media (min-width: 400px) { - .container { - width: 100%; - padding: 0; } } -/* For devices larger than 650px */ -@media (min-width: 650px) { - .container { - width: 100%; } - - .column, - .columns { - margin-left: 4%; } - - .column:first-child, - .columns:first-child { - margin-left: 0; } - - .one.column, - .one.columns { - width: 4.66666666667%; } - - .two.columns { - width: 13.3333333333%; } - - .three.columns { - width: 22%; } - - .four.columns { - width: 30.6666666667%; } - - .five.columns { - width: 39.3333333333%; } - - .six.columns { - width: 48%; } - - .seven.columns { - width: 56.6666666667%; } - - .eight.columns { - width: 65.3333333333%; } - - .nine.columns { - width: 74.0%; } - - .ten.columns { - width: 82.6666666667%; } - - .eleven.columns { - width: 91.3333333333%; } - - .twelve.columns { - width: 100%; - margin-left: 0; } - - .one-third.column { - width: 30.6666666667%; } - - .two-thirds.column { - width: 65.3333333333%; } } -/* Customer Overrides */ -.footer { - text-align: center; - color: #969696; - padding-top: 10%; } - -p.module-desc { - font-size: 1.1em; - color: #666666; } - -a.link-seesrc { - color: #aec7d2; - font-style: italic; } - -a.link-seesrc:hover { - color: #6c9aae; } - -#toc-list { - word-wrap: break-word; } - -ul.simple-toc { - list-style: none; } - -ul.simple-toc a.reference-toplevel { - font-weight: bold; - color: #0077b3; } - -ul.simple-toc-section { - list-style-type: circle; - color: #6c9aae; } - -ul.simple-toc-section a.reference { - color: #0077b3; } - -cite { - font-style: italic !important; } - -dt > pre { - border-color: rgba(0, 0, 0, 0.15); - background-color: transparent; - margin: 15px 0px 5px; } - -dd > pre { - border-color: rgba(0, 0, 0, 0.1); - background-color: whitesmoke; - margin-top: 8px; } - -.item > dd { - margin-left: 10px; - margin-bottom: 30px; } - -/* Nim line-numbered tables */ -.line-nums-table { - width: 100%; - table-layout: fixed; } - -table.line-nums-table { - border-radius: 4px; - border: 1px solid #cccccc; - background-color: whitesmoke; - border-collapse: separate; - margin-top: 15px; - margin-bottom: 25px; } - -.line-nums-table tbody { - border: none; } - -.line-nums-table td pre { - border: none; - background-color: transparent; } - -.line-nums-table td.blob-line-nums { - width: 28px; } - -.line-nums-table td.blob-line-nums pre { - color: #b0b0b0; - -webkit-filter: opacity(75%); - text-align: right; - border-color: transparent; - background-color: transparent; - padding-left: 0px; - margin-left: 0px; - padding-right: 0px; - margin-right: 0px; } - -/* Docgen styles */ -/* Links */ -a { - color: #0077b3; - text-decoration: none; } - -a:hover, -a:focus { - color: #00334d; - text-decoration: underline; } - -a:visited { - color: #00334d; } - -a:focus { - outline: thin dotted #2d2d2d; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; } - -a:hover, -a:active { - outline: 0; } - -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; } - -sup { - top: -0.5em; } - -sub { - bottom: -0.25em; } - -img { - width: auto; - height: auto; - max-width: 100%; - vertical-align: middle; - border: 0; - -ms-interpolation-mode: bicubic; } - -@media print { - * { - color: black !important; - text-shadow: none !important; - background: transparent !important; - box-shadow: none !important; } - - a, - a:visited { - text-decoration: underline; } - - a[href]:after { - content: " (" attr(href) ")"; } - - abbr[title]:after { - content: " (" attr(title) ")"; } - - .ir a:after, - a[href^="javascript:"]:after, - a[href^="#"]:after { - content: ""; } - - pre, - blockquote { - border: 1px solid #999; - page-break-inside: avoid; } - - thead { - display: table-header-group; } - - tr, - img { - page-break-inside: avoid; } - - img { - max-width: 100% !important; } - - @page { - margin: 0.5cm; } - - h1 { - page-break-before: always; } - - h1.title { - page-break-before: avoid; } - - p, - h2, - h3 { - orphans: 3; - widows: 3; } - - h2, - h3 { - page-break-after: avoid; } } -.img-rounded { - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; } - -.img-polaroid { - padding: 4px; - background-color: rgba(252, 248, 244, 0.75); - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } - -p { - margin: 0 0 12px; } - -small { - font-size: 85%; } - -strong { - font-weight: 600; } - -em { - font-style: italic; } - -cite { - font-style: normal; } - -h1, -h2, -h3, -h4, -h5, -h6 { - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; - font-weight: 600; - line-height: 20px; - color: inherit; - text-rendering: optimizelegibility; } - -h1 { - font-size: 2em; - padding-bottom: .15em; - border-bottom: 1px solid #aaaaaa; - margin-top: 1.0em; - line-height: 1.2em; } - -h1.title { - padding-bottom: 1em; - border-bottom: 0px; - font-size: 2.75em; } - -h2 { - font-size: 1.5em; - margin-top: 1.5em; } - -h3 { - font-size: 1.3em; - font-style: italic; - margin-top: 0.75em; } - -h4 { - font-size: 1.3em; - margin-top: 0.5em; } - -h5 { - font-size: 1.2em; - margin-top: 0.25em; } - -h6 { - font-size: 1.1em; } - -ul, -ol { - padding: 0; - margin: 0 0 0px 15px; } - -ul ul, -ul ol, -ol ol, -ol ul { - margin-bottom: 0; } - -li { - line-height: 20px; } - -dl { - margin-bottom: 20px; } - -dt, -dd { - line-height: 20px; } - -dt { - font-weight: bold; } - -dd { - margin-left: 10px; - margin-bottom: 26px; } - -hr { - margin: 20px 0; - border: 0; - border-top: 1px solid #eeeeee; - border-bottom: 1px solid #ffffff; } - -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #999999; } - -abbr.initialism { - font-size: 90%; - text-transform: uppercase; } - -blockquote { - padding: 0 0 0 15px; - margin: 0 0 20px; - border-left: 5px solid #EFEBE0; } - -table.docinfo + blockquote, table.docinfo blockquote, h1 + blockquote { - border-left: 5px solid #c9c9c9; -} - -table.docinfo + blockquote p, table.docinfo blockquote p, h1 + blockquote p { - margin-bottom: 0; - font-size: 15px; - font-weight: 200; - line-height: 1.5; - font-style: italic; } - -q:before, -q:after, -blockquote:before, -blockquote:after { - content: ""; } - -address { - display: block; - margin-bottom: 20px; - font-style: normal; - line-height: 20px; } - -code, -pre { - font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; - padding: 0 3px 2px; - font-weight: 500; - font-size: 12px; - color: #444444; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; } - -.pre { - font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; - font-weight: 600; - /*color: #504da6;*/ -} - -code { - padding: 2px 4px; - color: #444444; - white-space: nowrap; - background-color: white; - border: 1px solid #777777; } - -pre { - display: inline-block; - box-sizing: border-box; - min-width: calc(100% - 19.5px); - padding: 9.5px; - margin: 0.25em 10px 0.25em 10px; - font-size: 14px; - line-height: 20px; - white-space: pre !important; - overflow-y: hidden; - overflow-x: visible; - background-color: whitesmoke; - border: 1px solid #cccccc; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; } - -pre.prettyprint { - margin-bottom: 20px; } - -pre code { - padding: 0; - color: inherit; - white-space: pre; - overflow-x: visible; - background-color: transparent; - border: 0; } - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; } - -table { - max-width: 100%; - background-color: transparent; - border-collapse: collapse; - border-spacing: 0; } - -table th, table td { - padding: 0px 8px 0px; -} - -.table { - width: 100%; - margin-bottom: 20px; } - -.table th, -.table td { - padding: 8px; - line-height: 20px; - text-align: left; - vertical-align: top; - border-top: 1px solid #444444; } - -.table th { - font-weight: bold; } - -.table thead th { - vertical-align: bottom; } - -.table caption + thead tr:first-child th, -.table caption + thead tr:first-child td, -.table colgroup + thead tr:first-child th, -.table colgroup + thead tr:first-child td, -.table thead:first-child tr:first-child th, -.table thead:first-child tr:first-child td { - border-top: 0; } - -.table tbody + tbody { - border-top: 2px solid #444444; } - -.table .table { - background-color: rgba(252, 248, 244, 0.75); } - -.table-condensed th, -.table-condensed td { - padding: 4px 5px; } - -.table-bordered { - border: 1px solid #444444; - border-collapse: separate; - *border-collapse: collapse; - border-left: 0; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; } - -.table-bordered th, -.table-bordered td { - border-left: 1px solid #444444; } - -.table-bordered caption + thead tr:first-child th, -.table-bordered caption + tbody tr:first-child th, -.table-bordered caption + tbody tr:first-child td, -.table-bordered colgroup + thead tr:first-child th, -.table-bordered colgroup + tbody tr:first-child th, -.table-bordered colgroup + tbody tr:first-child td, -.table-bordered thead:first-child tr:first-child th, -.table-bordered tbody:first-child tr:first-child th, -.table-bordered tbody:first-child tr:first-child td { - border-top: 0; } - -.table-bordered thead:first-child tr:first-child > th:first-child, -.table-bordered tbody:first-child tr:first-child > td:first-child, -.table-bordered tbody:first-child tr:first-child > th:first-child { - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -moz-border-radius-topleft: 4px; } - -.table-bordered thead:first-child tr:first-child > th:last-child, -.table-bordered tbody:first-child tr:first-child > td:last-child, -.table-bordered tbody:first-child tr:first-child > th:last-child { - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -moz-border-radius-topright: 4px; } - -.table-bordered thead:last-child tr:last-child > th:first-child, -.table-bordered tbody:last-child tr:last-child > td:first-child, -.table-bordered tbody:last-child tr:last-child > th:first-child, -.table-bordered tfoot:last-child tr:last-child > td:first-child, -.table-bordered tfoot:last-child tr:last-child > th:first-child { - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; - -moz-border-radius-bottomleft: 4px; } - -.table-bordered thead:last-child tr:last-child > th:last-child, -.table-bordered tbody:last-child tr:last-child > td:last-child, -.table-bordered tbody:last-child tr:last-child > th:last-child, -.table-bordered tfoot:last-child tr:last-child > td:last-child, -.table-bordered tfoot:last-child tr:last-child > th:last-child { - -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; - -moz-border-radius-bottomright: 4px; } - -.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { - -webkit-border-bottom-left-radius: 0; - border-bottom-left-radius: 0; - -moz-border-radius-bottomleft: 0; } - -.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { - -webkit-border-bottom-right-radius: 0; - border-bottom-right-radius: 0; - -moz-border-radius-bottomright: 0; } - -.table-bordered caption + thead tr:first-child th:first-child, -.table-bordered caption + tbody tr:first-child td:first-child, -.table-bordered colgroup + thead tr:first-child th:first-child, -.table-bordered colgroup + tbody tr:first-child td:first-child { - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -moz-border-radius-topleft: 4px; } - -.table-bordered caption + thead tr:first-child th:last-child, -.table-bordered caption + tbody tr:first-child td:last-child, -.table-bordered colgroup + thead tr:first-child th:last-child, -.table-bordered colgroup + tbody tr:first-child td:last-child { - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -moz-border-radius-topright: 4px; } - -table.docutils th { - background-color: #e8e8e8; } - -table.docutils tr:hover { - background-color: whitesmoke; } - -.table-striped tbody > tr:nth-child(odd) > td, -.table-striped tbody > tr:nth-child(odd) > th { - background-color: rgba(252, 248, 244, 0.75); } - -.table-hover tbody tr:hover > td, -.table-hover tbody tr:hover > th { - background-color: rgba(241, 222, 204, 0.75); } - -table td[class*="span"], -table th[class*="span"], -.row-fluid table td[class*="span"], -.row-fluid table th[class*="span"] { - display: table-cell; - float: none; - margin-left: 0; } - -.hero-unit { - padding: 60px; - margin-bottom: 30px; - font-size: 18px; - font-weight: 200; - line-height: 30px; - color: inherit; - background-color: rgba(230, 197, 164, 0.75); - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; } - -.hero-unit h1 { - margin-bottom: 0; - font-size: 60px; - line-height: 1; - letter-spacing: -1px; - color: inherit; } - -.hero-unit li { - line-height: 30px; } - -/* rst2html default used to remove borders from tables and images */ -.borderless, table.borderless td, table.borderless th { - border: 0; } - -table.borderless td, table.borderless th { - /* Override padding for "table.docutils td" with "! important". - The right padding separates the table cells. */ - padding: 0 0.5em 0 0 !important; } - -.first { - /* Override more specific margin styles with "! important". */ - margin-top: 0 !important; } - -.last, .with-subtitle { - margin-bottom: 0 !important; } - -.hidden { - display: none; } - -a.toc-backref { - text-decoration: none; - color: #444444; } - -blockquote.epigraph { - margin: 2em 5em; } - -dl.docutils dd { - margin-bottom: 0.5em; } - -object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { - overflow: hidden; } - -/* Uncomment (and remove this text!) to get bold-faced definition list terms -dl.docutils dt { - font-weight: bold } -*/ -div.abstract { - margin: 2em 5em; } - -div.abstract p.topic-title { - font-weight: bold; - text-align: center; } - -div.admonition, div.attention, div.caution, div.danger, div.error, -div.hint, div.important, div.note, div.tip, div.warning { - margin: 2em; - border: medium outset; - padding: 1em; } - -div.note, div.warning { - margin: 1.5em 0px; - border: none; } - -div.note p.admonition-title, -div.warning p.admonition-title { - display: none; } - -/* Clearfix - * http://css-tricks.com/snippets/css/clear-fix/ - */ -div.note:after, -div.warning:after { - content: ""; - display: table; - clear: both; } - -div.note p:before, -div.warning p:before { - display: block; - float: left; - font-size: 4em; - line-height: 1em; - margin-right: 20px; - margin-left: 0em; - margin-top: -10px; - content: '\0270D'; - /*handwriting*/ } - -div.warning p:before { - content: '\026A0'; - /*warning*/ } - -div.admonition p.admonition-title, div.hint p.admonition-title, -div.important p.admonition-title, div.note p.admonition-title, -div.tip p.admonition-title { - font-weight: bold; - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; } - -div.attention p.admonition-title, div.caution p.admonition-title, -div.danger p.admonition-title, div.error p.admonition-title, -div.warning p.admonition-title, .code .error { - color: #b30000; - font-weight: bold; - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; } - -/* Uncomment (and remove this text!) to get reduced vertical space in - compound paragraphs. -div.compound .compound-first, div.compound .compound-middle { - margin-bottom: 0.5em } - -div.compound .compound-last, div.compound .compound-middle { - margin-top: 0.5em } -*/ -div.dedication { - margin: 2em 5em; - text-align: center; - font-style: italic; } - -div.dedication p.topic-title { - font-weight: bold; - font-style: normal; } - -div.figure { - margin-left: 2em; - margin-right: 2em; } - -div.footer, div.header { - clear: both; - font-size: smaller; } - -div.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; } - -div.line-block div.line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; } - -div.sidebar { - margin: 0 0 0.5em 1em; - border: medium outset; - padding: 1em; - background-color: rgba(252, 248, 244, 0.75); - width: 40%; - float: right; - clear: right; } - -div.sidebar p.rubric { - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; - font-size: medium; } - -div.system-messages { - margin: 5em; } - -div.system-messages h1 { - color: #b30000; } - -div.system-message { - border: medium outset; - padding: 1em; } - -div.system-message p.system-message-title { - color: #b30000; - font-weight: bold; } - -div.topic { - margin: 2em; } - -h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, -h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { - margin-top: 0.4em; } - -h1.title { - text-align: center; } - -h2.subtitle { - text-align: center; } - -hr.docutils { - width: 75%; } - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; } - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; } - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; } - -.align-left { - text-align: left; } - -.align-center { - clear: both; - text-align: center; } - -.align-right { - text-align: right; } - -/* reset inner alignment in figures */ -div.align-right { - text-align: inherit; } - -/* div.align-center * { */ -/* text-align: left } */ - -ul.simple > li { - margin-bottom: 0.5em } - -ol.simple, ul.simple { - margin-bottom: 1em; } - -ol.arabic { - list-style: decimal; } - -ol.loweralpha { - list-style: lower-alpha; } - -ol.upperalpha { - list-style: upper-alpha; } - -ol.lowerroman { - list-style: lower-roman; } - -ol.upperroman { - list-style: upper-roman; } - -p.attribution { - text-align: right; - margin-left: 50%; } - -p.caption { - font-style: italic; } - -p.credits { - font-style: italic; - font-size: smaller; } - -p.label { - white-space: nowrap; } - -p.rubric { - font-weight: bold; - font-size: larger; - color: maroon; - text-align: center; } - -p.sidebar-title { - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; - font-weight: bold; - font-size: larger; } - -p.sidebar-subtitle { - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; - font-weight: bold; } - -p.topic-title { - font-weight: bold; } - -pre.address { - margin-bottom: 0; - margin-top: 0; - font: inherit; } - -pre.literal-block, pre.doctest-block, pre.math, pre.code { - margin-left: 2em; - margin-right: 2em; } - -pre.code .ln { - color: grey; } - -/* line numbers */ -pre.code, code { - background-color: #eeeeee; } - -pre.code .comment, code .comment { - color: #5c6576; } - -pre.code .keyword, code .keyword { - color: #3B0D06; - font-weight: bold; } - -pre.code .literal.string, code .literal.string { - color: #0c5404; } - -pre.code .name.builtin, code .name.builtin { - color: #352b84; } - -pre.code .deleted, code .deleted { - background-color: #DEB0A1; } - -pre.code .inserted, code .inserted { - background-color: #A3D289; } - -span.classifier { - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; - font-style: oblique; } - -span.classifier-delimiter { - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; - font-weight: bold; } - -span.interpreted { - font-family: "Helvetica Neue", "HelveticaNeue", "Raleway", Helvetica, Arial, sans-serif; } - -span.option { - white-space: nowrap; } - -span.pre { - white-space: pre; } - -span.problematic { - color: #b30000; } - -span.section-subtitle { - /* font-size relative to parent (h1..h6 element) */ - font-size: 80%; } - -table.citation { - border-left: solid 1px #666666; - margin-left: 1px; } - -table.docinfo { - margin: 0em; - margin-top: 2em; - margin-bottom: 2em; - font-family: "Raleway", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif !important; - color: #444444; } - -table.docutils { - margin-top: 0.5em; - margin-bottom: 0.5em; } - -table.footnote { - border-left: solid 1px #2d2d2d; - margin-left: 1px; } - -table.docutils td, table.docutils th, -table.docinfo td, table.docinfo th { - padding-left: 0.5em; - padding-right: 0.5em; - vertical-align: top; } - -table.docutils th.field-name, table.docinfo th.docinfo-name { - font-weight: 700; - text-align: left; - white-space: nowrap; - padding-left: 0; } - -h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, -h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { - font-size: 100%; } - -ul.auto-toc { - list-style-type: none; } - -span.DecNumber { - color: #252dbe; } - -span.BinNumber { - color: #252dbe; } - -span.HexNumber { - color: #252dbe; } - -span.OctNumber { - color: #252dbe; } - -span.FloatNumber { - color: #252dbe; } - -span.Identifier { - color: #3b3b3b; } - -span.Keyword { - font-weight: 600; - color: #5e8f60; } - -span.StringLit { - color: #a4255b; } - -span.LongStringLit { - color: #a4255b; } - -span.CharLit { - color: #a4255b; } - -span.EscapeSequence { - color: black; } - -span.Operator { - color: black; } - -span.Punctuation { - color: black; } - -span.Comment, span.LongComment { - font-style: italic; - font-weight: 400; - color: #484a86; } - -span.RegularExpression { - color: darkviolet; } - -span.TagStart { - color: darkviolet; } - -span.TagEnd { - color: darkviolet; } - -span.Key { - color: #252dbe; } - -span.Value { - color: #252dbe; } - -span.RawData { - color: #a4255b; } - -span.Assembler { - color: #252dbe; } - -span.Preprocessor { - color: #252dbe; } - -span.Directive { - color: #252dbe; } - -span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference, -span.Other { - color: black; } - -/* Pop type, const, proc, and iterator defs in nim def blocks */ -dt pre > span.Identifier, dt pre > span.Operator { - color: #155da4; - font-weight: 700; } - -dt pre > span.Identifier ~ span.Identifier, dt pre > span.Operator ~ span.Identifier { - color: inherit; - font-weight: inherit; } - -dt pre > span.Operator ~ span.Identifier, dt pre > span.Operator ~ span.Operator { - color: inherit; - font-weight: inherit; } - -/* Nim sprite for the footer (taken from main page favicon) */ -.nim-sprite { - display: inline-block; - height: 12px; - width: 12px; - background-position: 0 0; - background-size: 12px 12px; - -webkit-filter: opacity(50%); - background-repeat: no-repeat; - background-image: url("data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAUAAAAF////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAIAAABbAAAAlQAAAKIAAACbAAAAmwAAAKIAAACVAAAAWwAAAAL///8A////AP///wD///8A////AAAAABQAAADAAAAAYwAAAA3///8A////AP///wD///8AAAAADQAAAGMAAADAAAAAFP///wD///8A////AP///wAAAACdAAAAOv///wD///8A////AP///wD///8A////AP///wD///8AAAAAOgAAAJ3///8A////AP///wAAAAAnAAAAcP///wAAAAAoAAAASv///wD///8A////AP///wAAAABKAAAAKP///wAAAABwAAAAJ////wD///8AAAAAgQAAABwAAACIAAAAkAAAAJMAAACtAAAAFQAAABUAAACtAAAAkwAAAJAAAACIAAAAHAAAAIH///8A////AAAAAKQAAACrAAAAaP///wD///8AAAAARQAAANIAAADSAAAARf///wD///8AAAAAaAAAAKsAAACk////AAAAADMAAACcAAAAnQAAABj///8A////AP///wAAAAAYAAAAGP///wD///8A////AAAAABgAAACdAAAAnAAAADMAAAB1AAAAwwAAAP8AAADpAAAAsQAAAE4AAAAb////AP///wAAAAAbAAAATgAAALEAAADpAAAA/wAAAMMAAAB1AAAAtwAAAOkAAAD/AAAA/wAAAP8AAADvAAAA3gAAAN4AAADeAAAA3gAAAO8AAAD/AAAA/wAAAP8AAADpAAAAtwAAAGUAAAA/AAAA3wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAADfAAAAPwAAAGX///8A////AAAAAEgAAADtAAAAvwAAAL0AAADGAAAA7wAAAO8AAADGAAAAvQAAAL8AAADtAAAASP///wD///8A////AP///wD///8AAAAAO////wD///8A////AAAAAIcAAACH////AP///wD///8AAAAAO////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//8AAP//AAD4HwAA7/cAAN/7AAD//wAAoYUAAJ55AACf+QAAh+EAAAAAAADAAwAA4AcAAP5/AAD//wAA//8AAA=="); - margin-bottom: -5px; } \ No newline at end of file diff --git a/lib/yaml/doc/index.txt b/lib/yaml/doc/index.txt deleted file mode 100644 index 887ee67..0000000 --- a/lib/yaml/doc/index.txt +++ /dev/null @@ -1,19 +0,0 @@ -======= -NimYAML -======= - -Introduction -============ - -**NimYAML** is a pure YAML implementation for Nim. It is able to read from and -write to YAML character streams, and to serialize from and construct to native -Nim types. It exclusively supports -`YAML 1.2 `_. - -Source code can be found on `GitHub `_. You can -install it with `Nimble `_: - -.. code-block:: bash - nimble install yaml - -%quickstart%0 diff --git a/lib/yaml/doc/processing.svg b/lib/yaml/doc/processing.svg deleted file mode 100644 index a312738..0000000 --- a/lib/yaml/doc/processing.svg +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Application - YAML - - - - - Native - Nim Types - - - - - Representation - - YamlDocument - - - - - - Serialization - - YamlStream - - - - - - Presentation - - Stream - - - - - - - - represent - - - - - - serialize - - - - - - - present - - - - - - construct - - - - - - compose - - - - - - - parse - - - - - - - - - represent - - - - - - construct - - - - - - - - - dump - - - - - - dumpDOM - - - - - - loadDOM - - - - - - load - - - - - \ No newline at end of file diff --git a/lib/yaml/doc/rstPreproc.nim b/lib/yaml/doc/rstPreproc.nim deleted file mode 100644 index e8efd29..0000000 --- a/lib/yaml/doc/rstPreproc.nim +++ /dev/null @@ -1,134 +0,0 @@ -## This is a tool for preprocessing rst files. Lines starting with ``%`` will -## get substituted by nicely layouted nim and yaml code included from file in -## the snippets tree. -## -## The syntax of substituted lines is ``'%' path '%' level``. *path* shall be -## a path relative to the *snippets* directory. *level* shall be the level depth -## of the first title that should be produced. -## -## Usage: -## -## rstPreproc -o:path -## -## *path* is the output path. If omitted, it will be equal to infile with its -## suffix substituted by ``.rst``. *infile* is the source rst file. -## -## The reason for this complex approach is to have all snippets used in the docs -## available as source files for automatic testing. This way, we can make sure -## that the code in the docs actually works. - -import parseopt2, streams, tables, strutils, os, options - -var - infile = "" - path = none(string) -for kind, key, val in getopt(): - case kind - of cmdArgument: - if infile == "": - if key == "": - echo "invalid input file with empty name!" - quit 1 - infile = key - else: - echo "Only one input file is supported!" - quit 1 - of cmdLongOption, cmdShortOption: - case key - of "out", "o": - if path.isNone: path = some(val) - else: - echo "Duplicate output path!" - quit 1 - else: - echo "Unknown option: ", key - quit 1 - of cmdEnd: assert(false) # cannot happen - -if infile == "": - echo "Missing input file!" - quit 1 - -if path.isNone: - for i in countdown(infile.len - 1, 0): - if infile[i] == '.': - if infile[i..^1] == ".rst": path = some(infile & ".rst") - else: path = some(infile[0..i] & "rst") - break - if path.isNone: path = some(infile & ".rst") - -var tmpOut = newFileStream(path.get(), fmWrite) - -proc append(s: string) = - tmpOut.writeLine(s) - -const headingChars = ['=', '-', '`', ':', '\''] - -proc outputExamples(curPath: string, level: int = 0) = - let titlePath = curPath / "title" - if fileExists(titlePath): - let titleFile = open(titlePath, fmRead) - defer: titleFile.close() - var title = "" - if titleFile.readLine(title): - let headingChar = if level >= headingChars.len: headingChars[^1] else: - headingChars[level] - append(title) - append(repeat(headingChar, title.len) & '\l') - - # process content files under this directory - - var codeFiles = newSeq[string]() - for kind, filePath in walkDir(curPath, true): - if kind == pcFile: - if filePath != "title": codeFiles.add(filePath) - case codeFiles.len - of 0: discard - of 1: - let (_, _, extension) = codeFiles[0].splitFile() - append(".. code:: " & extension[1..^1]) - append(" :file: " & (curPath / codeFiles[0]) & '\l') - of 2: - append(".. raw:: html") - append(" ") - for codeFile in codeFiles: - append(" ") - append(" \n
" & codeFile[3..^1] & "
\n") - - var first = true - for codeFile in codeFiles: - if first: first = false - else: append(".. raw:: html\n \n") - let (_, _, extension) = codeFile.splitFile() - append(".. code:: " & extension[1..^1]) - append(" :file: " & (curPath / codeFile) & '\l') - - append(".. raw:: html") - append("
\n") - else: - echo "Unexpected number of files in ", curPath, ": ", codeFiles.len - - # process child directories - - for kind, dirPath in walkDir(curPath): - if kind == pcDir: - outputExamples(dirPath, level + 1) - -var lineNum = 0 -for line in infile.lines(): - if line.len > 0 and line[0] == '%': - var - srcPath = none(string) - level = 0 - for i in 1..`_. - -Note that because the specification only defines that an implementation *should* -implement the failsafe schema, NimYAML is still compliant; it has valid reasons -not to implement the schema. - -This is a full list of all types defined in the YAML specification or the -`YAML type registry `_. It gives an overview of which -types are supported by NimYAML, which may be supported in the future and which -will never be supported. - -=============== ============================================ -YAML type Status -=============== ============================================ -``!!map`` Cannot be supported -``!!omap`` Cannot be supported -``!!pairs`` Cannot be supported -``!!set`` Cannot be supported -``!!seq`` Cannot be supported -``!!binary`` Currently not supported -``!!bool`` Maps to Nim's ``bool`` type -``!!float`` Not supported (user can choose) -``!!int`` Not supported (user can choose) -``!!merge`` Not supported and unlikely to be implemented -``!!null`` Used for reference types that are ``nil`` -``!!str`` Maps to Nim's ``string`` type -``!!timestamp`` Maps to Nim's ``Time`` type -``!!value`` Not supported and unlikely to be implemented -``!!yaml`` Not supported and unlikely to be implemented -=============== ============================================ - -``!!int`` and ``!!float`` are not supported out of the box to let the user -choose where to map them (for example, ``!!int`` may map to ``int32`` or -``int64``, or the the generic ``int`` whose size is platform-dependent). If one -wants to use ``!!int``or ``!!float``, the process is to create a ``distinct`` -type derived from the desired base type and then set its tag using -``setTagUri``. - -``!!merge`` and ``!!value`` are not supported because the semantics of these -types would make a multi-pass loading process necessary and if one takes the -tag system seriously, ``!!merge`` can only be used with YAML's collection types, -which, as explained above, cannot be supported. \ No newline at end of file diff --git a/lib/yaml/doc/serialization.txt b/lib/yaml/doc/serialization.txt deleted file mode 100644 index 3d91c1c..0000000 --- a/lib/yaml/doc/serialization.txt +++ /dev/null @@ -1,404 +0,0 @@ -====================== -Serialization Overview -====================== - -Introduction -============ - -NimYAML tries hard to make transforming YAML characters streams to native Nim -types and vice versa as easy as possible. In simple scenarios, you might not -need anything else than the two procs -`dump `_ -and `load `_. On the other side, the process -should be as customizable as possible to allow the user to tightly control how -the generated YAML character stream will look and how a YAML character stream is -interpreted. - -An important thing to remember in NimYAML is that unlike in interpreted -languages like Ruby, Nim cannot load a YAML character stream without knowing the -resulting type beforehand. For example, if you want to load this piece of YAML: - -.. code-block:: yaml - - %YAML 1.2 - --- !nim:system:seq(nim:system:int8) - - 1 - - 2 - - 3 - -You would need to know that it will load a ``seq[int8]`` *at compile time*. This -is not really a problem because without knowing which type you will load, you -cannot do anything useful with the result afterwards in the code. But it may be -unfamiliar for programmers who are used to the YAML libraries of Python or Ruby. - -Supported Types -=============== - -NimYAML supports a growing number of types of Nim's ``system`` module and -standard library, and it also supports user-defined object, tuple and enum types -out of the box. A complete list of explicitly supported types is available in -`Schema `_. - -**Important**: NimYAML currently does not support polymorphism. This may be -added in the future. - -This also means that NimYAML is generally able to work with object, tuple and -enum types defined in the standard library or a third-party library without -further configuration, given that all fields of the object are accessible at the -code point where NimYAML's facilities are invoked. - -Scalar Types ------------- - -The following integer types are supported by NimYAML: ``int``, ``int8``, -``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``. -Note that the ``int`` type has a variable size dependent on the target -operation system. To make sure that it round-trips properly between 32-bit and -64-bit operating systems, it will be converted to an ``int32`` during loading -and dumping. This will raise an exception for values outside of the range -``int32.low .. int32.high``! If you define the types you serialize yourself, -always consider using an integer type with explicit length. The same goes for -``uint``. - -The floating point types ``float``, ``float32`` and ``float64`` are also -supported. There is currently no problem with ``float``, because it is always a -``float64``. - -``string`` is supported and one of the few Nim types which directly map to a -standard YAML type. NimYAML is able to handle strings that are ``nil``, they -will be serialized with the special tag ``!nim:nil:string``. ``char`` is also -supported. - -To support new scalar types, you must implement the ``constructObject()`` and -``representObject()`` procs on that type (see below). - -Container Types ---------------- - -NimYAML supports Nim's ``array``, ``set``, ``seq``, ``Table``, ``OrderedTable`` -and ``Option`` types out of the box. While YAML's standard types ``!!seq`` and -``!!map`` allow arbitrarily typed content, in Nim the contained type must be -known at compile time. Therefore, Nim cannot load ``!!seq`` and ``!!map``. - -However, it doesn't need to. For example, if you have a YAML file like this: - -.. code-block:: yaml - - %YAML 1.2 - --- - - 1 - - 2 - -You can simply load it into a `seq[int]`. If your YAML file contains differently -typed values in the same collection, you can use an implicit variant object, see -below. - -A special case is ``Option[T]``: This type will either contain a value or not. -NimYAML maps ``!!null`` YAML scalars to the option's ``none(T)`` value. -This also works for ``ref`` types because ``Option`` for those types will use -``nil`` as its ``none(T)`` value. - -By default, ``Option`` fields must be given even if they are ``none(T)``. -You can circumvent this by putting the annotation ``{.sparse.}`` on the type -containing the ``Option`` field. - -Reference Types ---------------- - -A reference to any supported non-reference type (including user defined types, -see below) is supported by NimYAML. A reference type will be treated like its -base type, but NimYAML is able to detect multiple references to the same object -and dump the structure properly with anchors and aliases in place. It is -possible to dump and load cyclic data structures without further configuration. -It is possible for reference types to hold a ``nil`` value, which will be mapped -to the ``!!null`` YAML scalar type. - -``ptr`` types are not supported because it seems dangerous to automatically -allocate memory which the user must then manually deallocate. - -User Defined Types ------------------- - -For an object or tuple type to be directly usable with NimYAML, the following -conditions must be met: - -- Every type contained in the object/tuple must be supported -- All fields of an object type must be accessible from the code position where - you call NimYAML. If an object has non-public member fields, it can only be - processed in the module where it is defined. -- The object may not have a generic parameter - -NimYAML will present enum types as YAML scalars, and tuple and object types as -YAML maps. Some of the conditions above may be loosened in future releases. - -Variant Object Types -.................... - -A *variant object type* is an object type that contains one or more ``case`` -clauses. NimYAML supports variant object types. Only the currently accessible -fields of a variant object type are dumped, and only those may be present when -loading. - -The value of a discriminator field must be loaded before any value of a field -that depends on it. Therefore, a YAML mapping cannot be used to serialize -variant object types - the YAML specification explicitly states that the order -of key-value pairs in a mapping must not be used to convey content information. -So, any variant object type is serialized as a list of key-value pairs. - -For example, this type: - -.. code-block:: nim - type - AnimalKind = enum - akCat, akDog - - Animal = object - name: string - case kind: AnimalKind - of akCat: - purringIntensity: int - of akDog: - barkometer: int - -will be serialized as: - -.. code-block:: yaml - %YAML 1.2 - --- !nim:custom:Animal - - name: Bastet - - kind: akCat - - purringIntensity: 7 - -You can also use variant object types for processing heterogeneous data sets. -For example, if you have a YAML document which contains differently typed values -in the same list like this: - -.. code-block:: yaml - %YAML 1.2 - --- - - 42 - - this is a string - - !!null - -You can define a variant object type that can hold all types that occur in this -list in order to load it: - -.. code-block:: nim - import yaml - - type - ContainerKind = enum - ckInt, ckString, ckNone - Container {.implicit.} = object - case kind: ContainerKind - of ckInt: - intVal: int - of ckString: - strVal: string - of ckNone: - discard - - var - list: seq[Container] - s = newFileStream("in.yaml") - load(s, list) - -``{.implicit.}`` tells NimYAML that you want to use the type ``Container`` -implicitly, i.e. its fields are not visible in YAML, and are set dependent on -the value type that gets loaded into it. The type ``Container`` must fullfil the -following requirements: - -- It must contain exactly one ``case`` clause, and nothing else. -- Each branch of the ``case`` clause must contain exactly one field, with one - exception: There may be at most one branch that contains no field at all. -- It must not be a derived object type (this is currently not enforced) - -When loading the sequence, NimYAML writes the value into the first field that -can hold the value's type. All complex values (i.e. non-scalar values) *must* -have a tag in the YAML source, because NimYAML would otherwise be unable to -determine their type. The type of scalar values will be guessed if no tag is -available, but be aware that ``42`` can fit in both ``int8`` and ``int16``, so -in the case you have fields for both types, you should annotate the value. - -When dumping the sequence, NimYAML will always annotate a tag to each value it -outputs. This is to avoid possible ambiguity when loading. If a branch without -a field exists, it is represented as a ``!!null`` value. - -Tags -==== - -NimYAML uses local tags to represent Nim types that do not map directly to a -YAML type. For example, ``int8`` is presented with the tag ``!nim:system:int8``. -Tags are mostly unnecessary when loading YAML data because the user already -defines the target Nim type which usually defines all types of the structure. -However, there is one case where a tag is necessary: A reference type with the -value ``nil`` is represented in YAML as a ``!!null`` scalar. This will be -automatically detected by type guessing, but if it is for example a reference to -a string with the value ``"~"``, it must be tagged with ``!!string``, because -otherwise, it would be loaded as ``nil``. - -As you might have noticed in the example above, the YAML tag of a ``seq`` -depends on its generic type parameter. The same applies to ``Table``. So, a -table that maps ``int8`` to string sequences would be presented with the tag -``!n!tables:Table(tag:nimyaml.org,2016:int8,tag:nimyaml.org,2016:system:seq(tag:yaml.org,2002:string))``. -These tags are generated on the fly based on the types you instantiate -``Table`` or ``seq`` with. - -You may customize the tags used for your types by using the template -`setTagUri `_. It may not -be applied to scalar and collection types implemented by NimYAML, but you can -for example use it on a certain ``seq`` type: - -.. code-block:: nim - - setTagUri(seq[string], "!nim:my:seq") - -Customizing Field Handling -========================== - -NimYAML allows the user to specify special handling of certain object fields via -annotation pragmas. - -Transient Fields ----------------- - -It may happen that certain fields of an object type are transient, i.e. they are -used in a way that makes (de)serializing them unnecessary. Such fields can be -marked as transient. This will cause them not to be serialized to YAML. They -will also not be accepted when loading the object. - -Example: - -.. code-block:: nim - - type MyObject: object - storable: string - temporary {.transient.}: string - -Default Values --------------- - -When you load YAML, you might want to allow for the omission certain fields, -which should then be filled with a default value. You can do that like this: - -.. code-block:: nim - - type MyObject: object - required: string - optional {.defaultVal: "default value".}: string - -Whenever a value of type ``MyObject`` now is loaded and the input stream does -not contain the field ``optional``, that field will be set to the value -``"default value"``. - -Customize Serialization -======================= - -It is possible to customize the serialization of a type. For this, you need to -implement two procs, ``constructObject̀`` and ``representObject``. If you only -need to process the type in one direction (loading or dumping), you can omit -the other proc. - -constructObject ---------------- - -.. code-block:: nim - - proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var MyObject) - {.raises: [YamlConstructionError, YamlStreamError.} - -This proc should construct the type from a ``YamlStream``. Follow the following -guidelines when implementing a custom ``constructObject`` proc: - -- For constructing a value from a YAML scalar, consider using the - ``constructScalarItem`` template, which will automatically catch exceptions - and wrap them with a ``YamlConstructionError``, and also will assure that the - item you use for construction is a ``yamlScalar``. See below for an example. -- For constructing a value from a YAML sequence or map, you **must** use the - ``constructChild`` proc for child values if you want to use their - ``constructObject`` implementation. This will check their tag and anchor. - Always try to construct child values that way. -- For non-scalars, make sure that the last value you remove from the stream is - the object's ending event (``yamlEndMap`` or ``yamlEndSequence``) -- Use `peek `_ for inspecting the next event in - the ``YamlStream`` without removing it. -- Never write a ``constructObject`` proc for a ``ref`` type. ``ref`` types are - always handled by NimYAML itself. You can only customize the construction of - the underlying object. - -The following example for constructing from a YAML scalar value is the actual -implementation of constructing ``int`` types: - -.. code-block:: nim - - proc constructObject*[T: int8|int16|int32|int64]( - s: var YamlStream, c: ConstructionContext, result: var T) - {.raises: [YamlConstructionError, YamlStreamError].} = - var item: YamlStreamEvent - constructScalarItem(s, item, name(T)): - result = T(parseBiggestInt(item.scalarContent)) - -The following example for constructiong from a YAML non-scalar is the actual -implementation of constructing ``seq`` types: - -.. code-block:: nim - - proc constructObject*[T](s: var YamlStream, c: ConstructionContext, - result: var seq[T]) - {.raises: [YamlConstructionError, YamlStreamError].} = - let event = s.next() - if event.kind != yamlStartSequence: - raise newException(YamlConstructionError, "Expected sequence start") - result = newSeq[T]() - while s.peek().kind != yamlEndSequence: - var item: T - constructChild(s, c, item) - result.add(item) - discard s.next() - -representObject ---------------- - -.. code-block:: nim - - proc representObject*(value: MyObject, ts: TagStyle = tsNone, - c: SerializationContext, tag: TagId): {.raises: [].} - -This proc should push a list of tokens that represent the type into the -serialization context via ``c.put``. Follow the following guidelines when -implementing a custom ``representObject`` proc: - -- You can use the helper template - `presentTag `_ for outputting the - tag. -- Always output the first token with a ``yAnchorNone``. Anchors will be set - automatically by ``ref`` type handling. -- When outputting non-scalar types, you should use the ``representObject`` - implementation of the child types, if possible. -- Always use the ``tag`` parameter as tag for the first token you generate. -- Never write a ``representObject`` proc for ``ref`` types. - -The following example for representing to a YAML scalar is the actual -implementation of representing ``int`` types: - -.. code-block:: nim - - proc representObject*[T: int8|int16|int32|int64](value: T, ts: TagStyle, - c: SerializationContext, tag: TagId) {.raises: [].} = - ## represents an integer value as YAML scalar - c.put(scalarEvent($value, tag, yAnchorNone)) - -The following example for representing to a YAML non-scalar is the actual -implementation of representing ``seq`` and ``set`` types: - -.. code-block:: nim - - proc representObject*[T](value: seq[T]|set[T], ts: TagStyle, - c: SerializationContext, tag: TagId) {.raises: [YamlStreamError].} = - ## represents a Nim seq as YAML sequence - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startSeqEvent(tag)) - for item in value: - representChild(item, childTagStyle, c) - c.put(endSeqEvent()) \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/00/00-code.nim b/lib/yaml/doc/snippets/quickstart/00/00-code.nim deleted file mode 100644 index 710b8a6..0000000 --- a/lib/yaml/doc/snippets/quickstart/00/00-code.nim +++ /dev/null @@ -1,12 +0,0 @@ -import yaml/serialization, streams -type Person = object - name : string - age : int32 - -var personList = newSeq[Person]() -personList.add(Person(name: "Karl Koch", age: 23)) -personList.add(Person(name: "Peter Pan", age: 12)) - -var s = newFileStream("out.yaml", fmWrite) -dump(personList, s) -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/00/01-out.yaml b/lib/yaml/doc/snippets/quickstart/00/01-out.yaml deleted file mode 100644 index ae95158..0000000 --- a/lib/yaml/doc/snippets/quickstart/00/01-out.yaml +++ /dev/null @@ -1,9 +0,0 @@ -%YAML 1.2 -%TAG !n! tag:nimyaml.org,2016: ---- !n!system:seq(tag:nimyaml.org;2016:custom:Person) -- - name: Karl Koch - age: 23 -- - name: Peter Pan - age: 12 diff --git a/lib/yaml/doc/snippets/quickstart/00/title b/lib/yaml/doc/snippets/quickstart/00/title deleted file mode 100644 index fd45668..0000000 --- a/lib/yaml/doc/snippets/quickstart/00/title +++ /dev/null @@ -1 +0,0 @@ -Dumping Nim objects as YAML diff --git a/lib/yaml/doc/snippets/quickstart/01/00-code.nim b/lib/yaml/doc/snippets/quickstart/01/00-code.nim deleted file mode 100644 index 58a791d..0000000 --- a/lib/yaml/doc/snippets/quickstart/01/00-code.nim +++ /dev/null @@ -1,9 +0,0 @@ -import yaml/serialization, streams -type Person = object - name : string - age : int32 - -var personList: seq[Person] -var s = newFileStream("in.yaml") -load(s, personList) -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/01/01-in.yaml b/lib/yaml/doc/snippets/quickstart/01/01-in.yaml deleted file mode 100644 index b918cbf..0000000 --- a/lib/yaml/doc/snippets/quickstart/01/01-in.yaml +++ /dev/null @@ -1,4 +0,0 @@ -%YAML 1.2 ---- -- { name: Karl Koch, age: 23 } -- { name: Peter Pan, age: 12 } \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/01/title b/lib/yaml/doc/snippets/quickstart/01/title deleted file mode 100644 index 96a5007..0000000 --- a/lib/yaml/doc/snippets/quickstart/01/title +++ /dev/null @@ -1 +0,0 @@ -Loading Nim objects from YAML diff --git a/lib/yaml/doc/snippets/quickstart/02/00-code.nim b/lib/yaml/doc/snippets/quickstart/02/00-code.nim deleted file mode 100644 index d0ceefa..0000000 --- a/lib/yaml/doc/snippets/quickstart/02/00-code.nim +++ /dev/null @@ -1,16 +0,0 @@ -import yaml/serialization, yaml/presenter, streams -type Person = object - name: string - age: int32 - -var personList = newSeq[Person]() -personList.add(Person(name: "Karl Koch", age: 23)) -personList.add(Person(name: "Peter Pan", age: 12)) - -var s = newFileStream("out.yaml", fmWrite) -dump(personList, s, options = defineOptions( - style = psCanonical, - indentationStep = 3, - newlines = nlLF, - outputVersion = ov1_1)) -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/02/01-out.yaml b/lib/yaml/doc/snippets/quickstart/02/01-out.yaml deleted file mode 100644 index c2919ff..0000000 --- a/lib/yaml/doc/snippets/quickstart/02/01-out.yaml +++ /dev/null @@ -1,17 +0,0 @@ -%YAML 1.1 -%TAG !n! tag:nimyaml.org,2016: ---- -!n!system:seq(tag:nimyaml.org;2016:custom:Person) [ - !n!custom:Person { - ? !n!field "name" - : !!str "Karl Koch", - ? !n!field "age" - : !n!system:int32 "23" - }, - !n!custom:Person { - ? !n!field "name" - : !!str "Peter Pan", - ? !n!field "age" - : !n!system:int32 "12" - } -] diff --git a/lib/yaml/doc/snippets/quickstart/02/title b/lib/yaml/doc/snippets/quickstart/02/title deleted file mode 100644 index 944d448..0000000 --- a/lib/yaml/doc/snippets/quickstart/02/title +++ /dev/null @@ -1 +0,0 @@ -Customizing output style diff --git a/lib/yaml/doc/snippets/quickstart/03/00-code.nim b/lib/yaml/doc/snippets/quickstart/03/00-code.nim deleted file mode 100644 index 890b52f..0000000 --- a/lib/yaml/doc/snippets/quickstart/03/00-code.nim +++ /dev/null @@ -1,20 +0,0 @@ -import yaml/serialization, streams -type - Node = ref NodeObj - NodeObj = object - name: string - left, right: Node - -var node1, node2, node3: Node -new(node1); new(node2); new(node3) -node1.name = "Node 1" -node2.name = "Node 2" -node3.name = "Node 3" -node1.left = node2 -node1.right = node3 -node2.right = node3 -node3.left = node1 - -var s = newFileStream("out.yaml", fmWrite) -dump(node1, s) -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/03/01-out.yaml b/lib/yaml/doc/snippets/quickstart/03/01-out.yaml deleted file mode 100644 index ee3adbd..0000000 --- a/lib/yaml/doc/snippets/quickstart/03/01-out.yaml +++ /dev/null @@ -1,12 +0,0 @@ -%YAML 1.2 -%TAG !n! tag:nimyaml.org,2016: ---- !n!custom:NodeObj &a -name: Node 1 -left: - name: Node 2 - left: !!null ~ - right: &b - name: Node 3 - left: *a - right: !!null ~ -right: *b diff --git a/lib/yaml/doc/snippets/quickstart/03/title b/lib/yaml/doc/snippets/quickstart/03/title deleted file mode 100644 index 4ffce07..0000000 --- a/lib/yaml/doc/snippets/quickstart/03/title +++ /dev/null @@ -1 +0,0 @@ -Dumping reference types and cyclic structures diff --git a/lib/yaml/doc/snippets/quickstart/04/00-code.nim b/lib/yaml/doc/snippets/quickstart/04/00-code.nim deleted file mode 100644 index 7d37aa6..0000000 --- a/lib/yaml/doc/snippets/quickstart/04/00-code.nim +++ /dev/null @@ -1,12 +0,0 @@ -import yaml/serialization, streams -type - Node = ref NodeObj - NodeObj = object - name: string - left, right: Node - -var node1: Node - -var s = newFileStream("in.yaml") -load(s, node1) -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/04/01-in.yaml b/lib/yaml/doc/snippets/quickstart/04/01-in.yaml deleted file mode 100644 index 9c99c16..0000000 --- a/lib/yaml/doc/snippets/quickstart/04/01-in.yaml +++ /dev/null @@ -1,12 +0,0 @@ -%YAML 1.2 -%TAG !n! tag:nimyaml.org,2016: ---- !n!custom:NodeObj &a -name: Node 1 -left: - name: Node 2 - left: ~ - right: &b - name: Node 3 - left: *a - right: ~ -right: *b diff --git a/lib/yaml/doc/snippets/quickstart/04/title b/lib/yaml/doc/snippets/quickstart/04/title deleted file mode 100644 index 225029d..0000000 --- a/lib/yaml/doc/snippets/quickstart/04/title +++ /dev/null @@ -1 +0,0 @@ -Loading reference types and cyclic structures diff --git a/lib/yaml/doc/snippets/quickstart/05/00-code.nim b/lib/yaml/doc/snippets/quickstart/05/00-code.nim deleted file mode 100644 index a39f9d5..0000000 --- a/lib/yaml/doc/snippets/quickstart/05/00-code.nim +++ /dev/null @@ -1,13 +0,0 @@ -import yaml, streams -type Mob = object - level, experience: int32 - drops: seq[string] - -setTag(Mob, Tag("!Mob")) -setTag(seq[string], Tag("!Drops")) - -var mob = Mob(level: 42, experience: 1800, drops: - @["Sword of Mob Slaying"]) -var s = newFileStream("out.yaml", fmWrite) -dump(mob, s, tagStyle = tsAll) -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/05/01-out.yaml b/lib/yaml/doc/snippets/quickstart/05/01-out.yaml deleted file mode 100644 index 16710fc..0000000 --- a/lib/yaml/doc/snippets/quickstart/05/01-out.yaml +++ /dev/null @@ -1,6 +0,0 @@ -%YAML 1.2 -%TAG !n! tag:nimyaml.org,2016: ---- !Mob -!n!field level: !n!system:int32 42 -!n!field experience: !n!system:int32 1800 -!n!field drops: !Drops [!!str Sword of Mob Slaying] diff --git a/lib/yaml/doc/snippets/quickstart/05/title b/lib/yaml/doc/snippets/quickstart/05/title deleted file mode 100644 index dda14d4..0000000 --- a/lib/yaml/doc/snippets/quickstart/05/title +++ /dev/null @@ -1 +0,0 @@ -Defining a custom tag uri for a type diff --git a/lib/yaml/doc/snippets/quickstart/06/00-code.nim b/lib/yaml/doc/snippets/quickstart/06/00-code.nim deleted file mode 100644 index b22a8eb..0000000 --- a/lib/yaml/doc/snippets/quickstart/06/00-code.nim +++ /dev/null @@ -1,13 +0,0 @@ -import yaml/serialization, yaml/presenter, streams -type Person = object - name : string - age : int32 - -var personList = newSeq[Person]() -personList.add(Person(name: "Karl Koch", age: 23)) -personList.add(Person(name: "Peter Pan", age: 12)) - -var s = newFileStream("out.yaml", fmWrite) -dump(personList, s, - options = defineOptions(style = psJson)) -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/06/01-out.yaml b/lib/yaml/doc/snippets/quickstart/06/01-out.yaml deleted file mode 100644 index 06befc2..0000000 --- a/lib/yaml/doc/snippets/quickstart/06/01-out.yaml +++ /dev/null @@ -1,11 +0,0 @@ - -[ - { - "name": "Karl Koch", - "age": 23 - }, - { - "name": "Peter Pan", - "age": 12 - } -] diff --git a/lib/yaml/doc/snippets/quickstart/06/title b/lib/yaml/doc/snippets/quickstart/06/title deleted file mode 100644 index 21eb8cf..0000000 --- a/lib/yaml/doc/snippets/quickstart/06/title +++ /dev/null @@ -1 +0,0 @@ -Dumping Nim objects as JSON diff --git a/lib/yaml/doc/snippets/quickstart/07/00-code.nim b/lib/yaml/doc/snippets/quickstart/07/00-code.nim deleted file mode 100644 index ba619ab..0000000 --- a/lib/yaml/doc/snippets/quickstart/07/00-code.nim +++ /dev/null @@ -1,10 +0,0 @@ -import yaml/serialization, streams -type Person = object - name : string - age : int32 - -var personList: seq[Person] - -var s = newFileStream("in.yaml") -load(s, personList) -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/07/01-in.yaml b/lib/yaml/doc/snippets/quickstart/07/01-in.yaml deleted file mode 100644 index 3be727c..0000000 --- a/lib/yaml/doc/snippets/quickstart/07/01-in.yaml +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "name": "Karl Koch", - "age": 23 - }, - { - "name": "Peter Pan", - "age": 12 - } -] \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/07/title b/lib/yaml/doc/snippets/quickstart/07/title deleted file mode 100644 index 5fb44c7..0000000 --- a/lib/yaml/doc/snippets/quickstart/07/title +++ /dev/null @@ -1 +0,0 @@ -Loading Nim objects from JSON diff --git a/lib/yaml/doc/snippets/quickstart/08/00/00-code.nim b/lib/yaml/doc/snippets/quickstart/08/00/00-code.nim deleted file mode 100644 index f8c0ff3..0000000 --- a/lib/yaml/doc/snippets/quickstart/08/00/00-code.nim +++ /dev/null @@ -1,36 +0,0 @@ -import yaml, streams -type - Person = object - name: string - - ContainerKind = enum - ckString, ckInt, ckBool, ckPerson, ckNone - - # {.implicit.} tells NimYAML to use Container - # as implicit type. - # only possible with variant object types where - # each branch contains at most one object. - Container {.implicit.} = object - case kind: ContainerKind - of ckString: - strVal: string - of ckInt: - intVal: int - of ckBool: - boolVal: bool - of ckPerson: - personVal: Person - of ckNone: - discard - -setTag(Person, nimTag("demo:Person")) - -var list: seq[Container] - -var s = newFileStream("in.yaml") -load(s, list) -s.close() - -assert(list[0].kind == ckString) -assert(list[0].strVal == "this is a string") -# and so on \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/08/00/01-in.yaml b/lib/yaml/doc/snippets/quickstart/08/00/01-in.yaml deleted file mode 100644 index 7923272..0000000 --- a/lib/yaml/doc/snippets/quickstart/08/00/01-in.yaml +++ /dev/null @@ -1,9 +0,0 @@ -%YAML 1.2 -%TAG !n! tag:nimyaml.org,2016: ---- -- this is a string -- 42 -- false -- !!str 23 -- !n!demo:Person {name: Trillian} -- !!null \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/08/00/title b/lib/yaml/doc/snippets/quickstart/08/00/title deleted file mode 100644 index 237f9a9..0000000 --- a/lib/yaml/doc/snippets/quickstart/08/00/title +++ /dev/null @@ -1 +0,0 @@ -… With variant objects diff --git a/lib/yaml/doc/snippets/quickstart/08/01/00-code.nim b/lib/yaml/doc/snippets/quickstart/08/01/00-code.nim deleted file mode 100644 index b403502..0000000 --- a/lib/yaml/doc/snippets/quickstart/08/01/00-code.nim +++ /dev/null @@ -1,52 +0,0 @@ -import yaml, yaml/data, streams -type Person = object - name: string - -setTag(Person, nimTag("demo:Person"), yTagPerson) - -var - s = newFileStream("in.yaml", fmRead) - context = newConstructionContext() - parser = initYamlParser() - events = parser.parse(s) - -assert events.next().kind == yamlStartStream -assert events.next().kind == yamlStartDoc -assert events.next().kind == yamlStartSeq -var nextEvent = events.peek() -while nextEvent.kind != yamlEndSeq: - var curTag = nextEvent.properties().tag - if curTag == yTagQuestionMark: - # we only support implicitly tagged scalars - assert nextEvent.kind == yamlScalar - case guessType(nextEvent.scalarContent) - of yTypeInteger: curTag = yTagInteger - of yTypeBoolTrue, yTypeBoolFalse: - curTag = yTagBoolean - of yTypeUnknown: curTag = yTagString - else: assert false, "Type not supported!" - elif curTag == yTagExclamationMark: - curTag = yTagString - case curTag - of yTagString: - var s: string - events.constructChild(context, s) - echo "got string: ", s - of yTagInteger: - var i: int32 - events.constructChild(context, i) - echo "got integer: ", i - of yTagBoolean: - var b: bool - events.constructChild(context, b) - echo "got boolean: ", b - of yTagPerson: - var p: Person - events.constructChild(context, p) - echo "got Person with name: ", p.name - else: assert false, "unsupported tag: " & $curTag - nextEvent = events.peek() -assert events.next().kind == yamlEndSeq -assert events.next().kind == yamlEndDoc -assert events.next().kind == yamlEndStream -s.close() \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/08/01/01-in.yaml b/lib/yaml/doc/snippets/quickstart/08/01/01-in.yaml deleted file mode 100644 index 10fff1b..0000000 --- a/lib/yaml/doc/snippets/quickstart/08/01/01-in.yaml +++ /dev/null @@ -1,8 +0,0 @@ -%YAML 1.2 -%TAG !n! tag:nimyaml.org,2016: ---- !!seq -- this is a string -- 42 -- false -- !!str 23 -- !n!demo:Person {name: Trillian} \ No newline at end of file diff --git a/lib/yaml/doc/snippets/quickstart/08/01/title b/lib/yaml/doc/snippets/quickstart/08/01/title deleted file mode 100644 index 99176f2..0000000 --- a/lib/yaml/doc/snippets/quickstart/08/01/title +++ /dev/null @@ -1 +0,0 @@ -… With the Sequential API diff --git a/lib/yaml/doc/snippets/quickstart/08/title b/lib/yaml/doc/snippets/quickstart/08/title deleted file mode 100644 index d413d92..0000000 --- a/lib/yaml/doc/snippets/quickstart/08/title +++ /dev/null @@ -1 +0,0 @@ -Processing a Sequence of Heterogeneous Items diff --git a/lib/yaml/doc/snippets/quickstart/title b/lib/yaml/doc/snippets/quickstart/title deleted file mode 100644 index ddddbf8..0000000 --- a/lib/yaml/doc/snippets/quickstart/title +++ /dev/null @@ -1 +0,0 @@ -Quickstart diff --git a/lib/yaml/doc/style.css b/lib/yaml/doc/style.css deleted file mode 100644 index 513492f..0000000 --- a/lib/yaml/doc/style.css +++ /dev/null @@ -1,175 +0,0 @@ -header { - position: fixed; - top: 0; - left: 0; - right: 0; - height: 50px; - background: #111; - margin: 0; - padding: 0; - z-index: 1; -} - -header a { - display: inline-block; - line-height: 50px; - font-size: large; - padding-left: 5px; - padding-right: 5px; -} - -header a.active { - background: #877 !important; - color: black !important; -} - -header span { - display: inline-block; - line-height: 50px; - font-size: large; - color: white; - padding-left: 15px; - padding-right: 5px; -} - -header span a { - display: block; -} - -header span ul { - display: none; - position: absolute; - top: 100%; - list-style: none; - background: #111; - margin: 0; -} - -header span ul:after { - content: ""; clear: both; display: block; -} - -header span:hover > ul { - display: block; -} - -header span ul a { - padding: 0 10px; - line-height: 40px; -} - -header span ul.monospace a { - font-size: smaller; - font-family: "Source Code Pro", Menlo, "Courier New", Courier, monospace; -} - -header a:link, -header a:visited { - background: inherit; - color: #aaa; -} - -header a:hover { - background: inherit; - color: white; - text-decoration: inherit; -} - -header a:active { - background: #222; - color: white; - text-decoration: inherit; -} - -a.pagetitle:link, -a.pagetitle:hover, -a.pagetitle:active, -a.pagetitle:visited { - background: inherit; - color: white; - text-decoration: inherit; -} - -body { - margin-left: 0; - margin-right: 0; - margin-top: 55px; - margin-bottom: 5px; - padding: 0; -} - -html { - background-color: rgba(252, 248, 244, 0.75); -} - -/* necessary for links to scroll to the right position */ -dt a:before { - margin-top: -50px; - height: 50px; - content: ' '; - display: block; - visibility: hidden; -} - -#testingground { - margin-left: -50px; - margin-right: -50px; -} - -#testingground textarea { - width: 100%; - height: 100%; -} -#testingground textarea, -#testingground pre { - font-family: "Source Code Pro", Menlo, "Courier New", Courier, monospace; - margin: 0; -} -#testingground pre { - font-size: small; -} -#testingground #style-options { - margin-top: 10px; - width: 100%; - text-align: center; -} -#testingground .style-option { - display: inline-block; - margin-right: 20px; -} - -object { - margin-left: auto; - margin-right: auto; - display: block; -} - -.quickstart-example { - border-collapse: collapse; - border: 1px solid #e8e8e8; - width: 100%; -} - -.quickstart-example th { - background: #e8e8e8; -} - -.quickstart-example td { - width: 50%; - vertical-align: top; - padding: 0; - background: whitesmoke; -} - -.quickstart-example td:first-child { - border-right: 1px solid #e8e8e8; -} - -.quickstart-example pre { - border: 0; - margin: 0; - display: block; - border-radius: 0; - -moz-border-radius: 0; - -webkit-border-radius: 0; -} \ No newline at end of file diff --git a/lib/yaml/doc/testing.rst b/lib/yaml/doc/testing.rst deleted file mode 100644 index 4aadb55..0000000 --- a/lib/yaml/doc/testing.rst +++ /dev/null @@ -1,120 +0,0 @@ -============== -Testing Ground -============== - -Input is being processed on the fly by a friendly web service and output is -updated as you type. - -.. raw:: html -
- - - - - - - - - - - - - -
InputOutput
- - -
-
-            
-
-
-
Output style:
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- diff --git a/lib/yaml/nimdoc.cfg b/lib/yaml/nimdoc.cfg deleted file mode 100644 index 0a34f56..0000000 --- a/lib/yaml/nimdoc.cfg +++ /dev/null @@ -1,151 +0,0 @@ -# This is the config file for the documentation generator. -# (c) 2012 Andreas Rumpf -# Feel free to edit the templates as you need. If you modify this file, it -# might be worth updating the hardcoded values in packages/docutils/rstgen.nim - -split.item.toc = "20" -# too long entries in the table of contents wrap around -# after this number of characters - -doc.section = """ -
-

$sectionTitle

-
-$content -
-""" - -doc.section.toc = """ -
  • - $sectionTitle -
      - $content -
    -
  • -""" - -# Chunk of HTML emitted for each entry in the HTML table of contents. -# Available variables are: -# * $desc: the actual docstring of the item. -# * $header: the full version of name, including types, pragmas, tags, etc. -# * $header_plain: like header but without HTML, for attribute embedding. -# * $itemID: numerical unique entry of the item in the HTML. -# * $itemSym: short symbolic name of the item for easier hyperlinking. -# * $itemSymEnc: quoted version for URLs or attributes. -# * $itemSymOrID: the symbolic name or the ID if that is not unique. -# * $itemSymOrIDEnc: quoted version for URLs or attributes. -# * $name: reduced name of the item. -# * $seeSrc: generated HTML from doc.item.seesrc (if some switches are used). - -doc.item = """ -
    $header
    -
    -$desc -$seeSrc -
    -""" - -# Chunk of HTML emitted for each entry in the HTML table of contents. -# See doc.item for available substitution variables. -doc.item.toc = """ -
  • $name
  • -""" - -# HTML rendered for doc.item's seeSrc variable. Note that this will render to -# the empty string if you don't pass anything through --docSeeSrcURL. Available -# substitutaion variables here are: -# * $path: relative path to the file being processed. -# * $line: line of the item in the original source file. -# * $url: whatever you did pass through the --docSeeSrcUrl switch (which also -# gets variables path/line replaced!) -doc.item.seesrc = """  Source""" - -doc.toc = """ -
      -$content -
    -""" - -doc.body_toc = """ -
    -
    - $tableofcontents -
    -
    -

    $moduledesc

    - $content -
    -
    -""" - -doc.body_no_toc = """ -$moduledesc -$content -""" - -doc.listing_start = "
    "
    -doc.listing_end = "
    " - -doc.file = """ - - - - - NimYAML - $title - - - - - - - - -Fork me on GitHub -
    - NimYAML - Home - Testing Ground - Docs: - Overview - - Serialization - - - - Modules - - -
    -
    -
    -

    $title

    - $content -
    - -
    -
    -
    - - -""" diff --git a/lib/yaml/server/server.nim b/lib/yaml/server/server.nim deleted file mode 100644 index e469550..0000000 --- a/lib/yaml/server/server.nim +++ /dev/null @@ -1,88 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2015 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import jester, asyncdispatch, json, streams, strutils -import packages/docutils/rstgen, packages/docutils/highlite, options -import ../yaml - -routes: - get "/": - resp(Http200, [("Content-Type", "text/plain")], "I am a friendly NimYAML parser webservice.") - post "/": - var - style: PresentationStyle - resultNode = newJObject() - msg: string - retStatus = Http200 - contentType = "application/json" - headers = @[("Access-Control-Allow-Origin", "*"), ("Pragma", "no-cache"), - ("Cache-Control", "no-cache"), ("Expires", "0")] - try: - case @"style" - of "minimal": style = psMinimal - of "canonical": style = psCanonical - of "default": style = psDefault - of "json": style = psJson - of "block": style = psBlockOnly - of "tokens": - var - output = "+STR\n" - parser = initYamlParser(false) - events = parser.parse(newStringStream(@"input")) - for event in events: output.add(parser.display(event) & "\n") - output &= "-STR" - resultNode["code"] = %0 - resultNode["output"] = %output - msg = resultNode.pretty - else: - retStatus = Http400 - msg = "Invalid style: " & escape(@"style") - contentType = "text/plain;charset=utf8" - if len(msg) == 0: - var - output = newStringStream() - highlighted = "" - transform(newStringStream(@"input"), output, defineOptions(style), true) - - # syntax highlighting (stolen and modified from stlib's rstgen) - var g: GeneralTokenizer - g.initGeneralTokenizer(output.data) - while true: - g.getNextToken(langYaml) - case g.kind - of gtEof: break - of gtNone, gtWhitespace: - highlighted.add(substr(output.data, g.start, g.length + g.start - 1)) - else: - highlighted.addf("$1", - esc(outHtml, substr(output.data, g.start, g.length+g.start-1)), - tokenClassToStr[g.kind]) - - resultNode["code"] = %0 - resultNode["output"] = %highlighted - msg = resultNode.pretty - except YamlParserError: - let e = (ref YamlParserError)(getCurrentException()) - resultNode["code"] = %1 - resultNode["line"] = %e.mark.line - resultNode["column"] = %e.mark.column - resultNode["message"] = %e.msg - resultNode["detail"] = %e.lineContent - msg = resultNode.pretty - except YamlPresenterJsonError: - let e = getCurrentException() - resultNode["code"] = %2 - resultNode["message"] = %e.msg - msg = resultNode.pretty - except: - let e = getCurrentException() - msg = "Name: " & $e.name & "\nMessage: " & e.msg & - "\nTrace:\n" & e.getStackTrace - retStatus = Http500 - contentType = "text/plain;charset=utf-8" - headers.add(("Content-Type", contentType)) - resp retStatus, headers, msg -runForever() diff --git a/lib/yaml/test/commonTestUtils.nim b/lib/yaml/test/commonTestUtils.nim deleted file mode 100644 index 2fc6b46..0000000 --- a/lib/yaml/test/commonTestUtils.nim +++ /dev/null @@ -1,74 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2015 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import ../yaml, ../yaml/data - -proc escapeNewlines(s: string): string = - result = "" - for c in s: - case c - of '\l': result.add("\\n") - of '\t': result.add("\\t") - of '\\': result.add("\\\\") - else: result.add(c) - -proc printDifference(entity: string, expected, actual: Properties): bool = - result = false - if expected.tag != actual.tag: - echo "[", entity, ".tag] expected ", $expected.tag, ", got ", $actual.tag - result = true - if expected.anchor != actual.anchor: - echo "[", entity, ".anchor] expected ", $expected.anchor, ", got ", $actual.anchor - result = true - -proc printDifference*(expected, actual: Event) = - if expected.kind != actual.kind: - echo "expected ", expected.kind, ", got ", $actual.kind - else: - case expected.kind - of yamlScalar: - if not printDifference("scalar", expected.scalarProperties, actual.scalarProperties): - if expected.scalarContent != actual.scalarContent: - let msg = "[scalarEvent] content mismatch!\nexpected: " & - escapeNewlines(expected.scalarContent) & - "\ngot : " & escapeNewlines(actual.scalarContent) - if expected.scalarContent.len != actual.scalarContent.len: - echo msg, "\n(length does not match)" - else: - for i in 0..expected.scalarContent.high: - if expected.scalarContent[i] != actual.scalarContent[i]: - echo msg, "\n(first different char at pos ", i, ": expected ", - cast[int](expected.scalarContent[i]), ", got ", - cast[int](actual.scalarContent[i]), ")" - break - else: echo "[scalar] Unknown difference" - of yamlStartMap: - if not printDifference("map", expected.mapProperties, actual.mapProperties): - echo "[map] Unknown difference" - of yamlStartSeq: - if not printDifference("seq", expected.seqProperties, actual.seqProperties): - 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[Event]) {.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 event #" & $i & ":" - printDifference(expected[i], token) - fail() - break - i.inc() \ No newline at end of file diff --git a/lib/yaml/test/tannotations.nim b/lib/yaml/test/tannotations.nim deleted file mode 100644 index 7b10b93..0000000 --- a/lib/yaml/test/tannotations.nim +++ /dev/null @@ -1,73 +0,0 @@ -import "../yaml" -import unittest - -type - Config = ref object - docs_root* {.defaultVal: "~/.example".}: string - drafts_root*: string - - Stuff = ref object - a {.transient.}: string - b: string - - Part {.ignore: ["a", "b"].} = ref object - c: string - - IgnoreAnything {.ignore: [].} = ref object - warbl: int - - ContainerKind = enum - ckString, ckInt - - Container {.implicit.} = object - case kind: ContainerKind - of ckString: - strVal: string - of ckInt: - intVal: int - - Sparse {.sparse.} = ref object of RootObj - name*: Option[string] - description*: Option[string] - -suite "Serialization Annotations": - test "load default value": - let input = "drafts_root: foo" - var result: Config - load(input, result) - assert result.docs_root == "~/.example", "docs_root is " & result.docs_root - assert result.drafts_root == "foo", "drafts_root is " & result.drafts_root - - test "load into object with transient fields": - let input = "b: warbl" - var result: Stuff - load(input, result) - assert result.b == "warbl" - assert result.a == "" - - test "load into object with ignored keys": - let input = "{a: foo, c: bar, b: baz}" - var result: Part - load(input, result) - assert result.c == "bar" - - test "load into object ignoring all other keys": - let input = "{tuirae: fg, rtuco: fgh, warbl: 1}" - var result: IgnoreAnything - load(input, result) - assert result.warbl == 1 - - test "load implicit variant object": - let input = "[foo, 13]" - var result: seq[Container] - load(input, result) - assert len(result) == 2 - assert result[0].kind == ckString - assert result[1].kind == ckInt - - test "load sparse type": - let input = "{}" - var result: Sparse - load(input, result) - assert result.name.isNone - assert result.description.isNone \ No newline at end of file diff --git a/lib/yaml/test/tdom.nim b/lib/yaml/test/tdom.nim deleted file mode 100644 index d4d03b4..0000000 --- a/lib/yaml/test/tdom.nim +++ /dev/null @@ -1,97 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2015 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import "../yaml" -import unittest, commonTestUtils, streams, tables - -suite "DOM": - test "Composing simple Scalar": - let - input = newStringStream("scalar") - result = loadDOM(input) - assert result.root.kind == yScalar - assert result.root.content == "scalar" - assert result.root.tag == yTagQuestionMark - test "Serializing simple Scalar": - let input = initYamlDoc(newYamlNode("scalar")) - var result = serialize(input) - ensure(result, startStreamEvent(), startDocEvent(), scalarEvent("scalar"), - endDocEvent(), endStreamEvent()) - test "Composing sequence": - let - input = newStringStream("- !!str a\n- !!bool no") - result = loadDOM(input) - assert result.root.kind == ySequence - assert result.root.tag == yTagQuestionMark - assert result.root.len == 2 - assert result.root[0].kind == yScalar - assert result.root[0].tag == yTagString - assert result.root[0].content == "a" - assert result.root[1].kind == yScalar - assert result.root[1].tag == yTagBoolean - assert result.root[1].content == "no" - test "Serializing sequence": - let input = initYamlDoc(newYamlNode([ - newYamlNode("a", yTagString), - newYamlNode("no", yTagBoolean)])) - var result = serialize(input) - ensure(result, startStreamEvent(), startDocEvent(), startSeqEvent(), - scalarEvent("a", yTagString), scalarEvent("no", yTagBoolean), - endSeqEvent(), endDocEvent(), endStreamEvent()) - test "Composing mapping": - let - input = newStringStream("--- !!map\n!foo bar: [a, b]") - result = loadDOM(input) - assert result.root.kind == yMapping - assert result.root.tag == yTagMapping - assert result.root.fields.len == 1 - for key, value in result.root.fields.pairs: - assert key.kind == yScalar - assert $key.tag == "!foo" - assert key.content == "bar" - assert value.kind == ySequence - assert value.len == 2 - test "Serializing mapping": - let input = initYamlDoc(newYamlNode([ - (key: newYamlNode("bar"), value: newYamlNode([newYamlNode("a"), - newYamlNode("b")]))])) - var result = serialize(input) - ensure(result, startStreamEvent(), startDocEvent(), startMapEvent(), - scalarEvent("bar"), startSeqEvent(), scalarEvent("a"), scalarEvent("b"), - endSeqEvent(), endMapEvent(), endDocEvent(), endStreamEvent()) - test "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.len == 4 - assert result.root[0].kind == yScalar - assert result.root[0].content == "foo" - assert result.root[1].kind == yScalar - assert result.root[1].content == "bar" - assert cast[pointer](result.root[0]) == cast[pointer](result.root[2]) - assert cast[pointer](result.root[1]) == cast[pointer](result.root[3]) - test "Serializing with anchors": - let - a = newYamlNode("a") - b = newYamlNode("b") - input = initYamlDoc(newYamlNode([a, b, newYamlNode("c"), a, b])) - var result = serialize(input) - ensure(result, startStreamEvent(), startDocEvent(), startSeqEvent(), - scalarEvent("a", anchor="a".Anchor), - scalarEvent("b", anchor="b".Anchor), scalarEvent("c"), - aliasEvent("a".Anchor), aliasEvent("b".Anchor), endSeqEvent(), - endDocEvent(), endStreamEvent()) - test "Serializing with all anchors": - let - a = newYamlNode("a") - input = initYamlDoc(newYamlNode([a, newYamlNode("b"), a])) - var result = serialize(input, asAlways) - ensure(result, startStreamEvent(), startDocEvent(), - startSeqEvent(anchor="a".Anchor), - scalarEvent("a", anchor = "b".Anchor), - scalarEvent("b", anchor="c".Anchor), aliasEvent("b".Anchor), - endSeqEvent(), endDocEvent(), endStreamEvent()) \ No newline at end of file diff --git a/lib/yaml/test/testEventParser.nim b/lib/yaml/test/testEventParser.nim deleted file mode 100644 index 1700b46..0000000 --- a/lib/yaml/test/testEventParser.nim +++ /dev/null @@ -1,291 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import ../yaml, ../yaml/data -import lexbase, streams, tables, strutils - -type - LexerToken = enum - plusStr, minusStr, plusDoc, minusDoc, plusMap, minusMap, plusSeq, minusSeq, - mapBraces, seqBrackets, - eqVal, eqAli, chevTag, andAnchor, starAnchor, colonContent, sqContent, - dqContent, litContent, foContent, - explDirEnd, explDocEnd, noToken - - StreamPos = enum - beforeStream, inStream, afterStream - - EventLexer = object of BaseLexer - content: string - - EventStreamError = object of ValueError - -proc nextToken(lex: var EventLexer): LexerToken = - while true: - case lex.buf[lex.bufpos] - of ' ', '\t': lex.bufpos.inc() - of '\r': lex.bufpos = lex.handleCR(lex.bufpos) - of '\l': lex.bufpos = lex.handleLF(lex.bufpos) - else: break - if lex.buf[lex.bufpos] == EndOfFile: return noToken - case lex.buf[lex.bufpos] - of ':', '"', '\'', '|', '>': - let t = case lex.buf[lex.bufpos] - of ':': colonContent - of '"': dqContent - of '\'': sqContent - of '|': litContent - of '>': foContent - else: colonContent - - lex.content = "" - lex.bufpos.inc() - while true: - case lex.buf[lex.bufpos] - of EndOfFile: break - of '\c': - lex.bufpos = lex.handleCR(lex.bufpos) - break - of '\l': - lex.bufpos = lex.handleLF(lex.bufpos) - break - of '\\': - lex.bufpos.inc() - case lex.buf[lex.bufpos] - of 'n': lex.content.add('\l') - of 'r': lex.content.add('\r') - of '0': lex.content.add('\0') - of 'b': lex.content.add('\b') - of 't': lex.content.add('\t') - of '\\': lex.content.add('\\') - else: raise newException(EventStreamError, - "Unknown escape character: " & lex.buf[lex.bufpos]) - else: lex.content.add(lex.buf[lex.bufpos]) - lex.bufpos.inc() - result = t - of '<': - lex.content = "" - lex.bufpos.inc() - while lex.buf[lex.bufpos] != '>': - lex.content.add(lex.buf[lex.bufpos]) - lex.bufpos.inc() - if lex.buf[lex.bufpos] == EndOfFile: - raise newException(EventStreamError, "Unclosed tag URI!") - result = chevTag - lex.bufpos.inc() - of '&': - lex.content = "" - lex.bufpos.inc() - while lex.buf[lex.bufpos] notin {' ', '\t', '\r', '\l', EndOfFile}: - lex.content.add(lex.buf[lex.bufpos]) - lex.bufpos.inc() - result = andAnchor - of '*': - lex.content = "" - lex.bufpos.inc() - while lex.buf[lex.bufpos] notin {' ', '\t', '\r', '\l', EndOfFile}: - lex.content.add(lex.buf[lex.bufpos]) - lex.bufpos.inc() - result = starAnchor - of '{': - lex.bufpos.inc() - if lex.buf[lex.bufpos] == '}': - result = mapBraces - else: raise newException(EventStreamError, "Invalid token: {" & lex.buf[lex.bufpos]) - lex.bufpos.inc() - of '[': - lex.bufpos.inc() - if lex.buf[lex.bufpos] == ']': - result = seqBrackets - else: raise newException(EventStreamError, "Invalid token: [" & lex.buf[lex.bufpos]) - lex.bufpos.inc() - else: - lex.content = "" - while lex.buf[lex.bufpos] notin {' ', '\t', '\r', '\l', EndOfFile}: - lex.content.add(lex.buf[lex.bufpos]) - lex.bufpos.inc() - case lex.content - of "+STR": result = plusStr - of "-STR": result = minusStr - of "+DOC": result = plusDoc - of "-DOC": result = minusDoc - of "+MAP": result = plusMap - of "-MAP": result = minusMap - of "+SEQ": result = plusSeq - of "-SEQ": result = minusSeq - of "=VAL": result = eqVal - of "=ALI": result = eqAli - of "---": result = explDirEnd - of "...": result = explDocEnd - else: raise newException(EventStreamError, "Invalid token: " & lex.content) - -template assertInEvent(name: string) {.dirty.} = - if not inEvent: - raise newException(EventStreamError, "Illegal token: " & name) - -template yieldEvent() {.dirty.} = - if inEvent: - yield curEvent - inEvent = false - -template setTag(t: Tag) {.dirty.} = - case curEvent.kind - of yamlStartSeq: curEvent.seqProperties.tag = t - of yamlStartMap: curEvent.mapProperties.tag = t - of yamlScalar: curEvent.scalarProperties.tag = t - else: discard - -template setAnchor(a: Anchor) {.dirty.} = - case curEvent.kind - of yamlStartSeq: curEvent.seqProperties.anchor = a - of yamlStartMap: curEvent.mapProperties.anchor = a - of yamlScalar: curEvent.scalarProperties.anchor = a - of yamlAlias: curEvent.aliasTarget = a - else: discard - -template curTag(): Tag = - var foo: Tag - case curEvent.kind - of yamlStartSeq: foo = curEvent.seqProperties.tag - of yamlStartMap: foo = curEvent.mapProperties.tag - of yamlScalar: foo = curEvent.scalarProperties.tag - else: raise newException(EventStreamError, - $curEvent.kind & " may not have a tag") - foo - -template setCurTag(val: Tag) = - case curEvent.kind - of yamlStartSeq: curEvent.seqProperties.tag = val - of yamlStartMap: curEvent.mapProperties.tag = val - of yamlScalar: curEvent.scalarProperties.tag = val - else: raise newException(EventStreamError, - $curEvent.kind & " may not have a tag") - -template curAnchor(): Anchor = - var foo: Anchor - case curEvent.kind - of yamlStartSeq: foo = curEvent.seqProperties.anchor - of yamlStartMap: foo = curEvent.mapProperties.anchor - of yamlScalar: foo = curEvent.scalarProperties.anchor - of yamlAlias: foo = curEvent.aliasTarget - else: raise newException(EventStreamError, - $curEvent.kind & "may not have an anchor") - foo - -template setCurAnchor(val: Anchor) = - case curEvent.kind - of yamlStartSeq: curEvent.seqProperties.anchor = val - of yamlStartMap: curEvent.mapProperties.anchor = val - of yamlScalar: curEvent.scalarProperties.anchor = val - of yamlAlias: curEvent.aliasTarget = val - else: raise newException(EventStreamError, - $curEvent.kind & " may not have an anchor") - -template eventStart(k: EventKind) {.dirty.} = - if streamPos == beforeStream: - yield Event(kind: yamlStartStream) - streamPos = inStream - else: yieldEvent() - curEvent = Event(kind: k) - setTag(yTagQuestionMark) - setAnchor(yAnchorNone) - inEvent = true - -proc parseEventStream*(input: Stream): YamlStream = - var backend = iterator(): Event = - var lex: EventLexer - lex.open(input) - var - inEvent = false - curEvent: Event - streamPos: StreamPos = beforeStream - while lex.buf[lex.bufpos] != EndOfFile: - let token = lex.nextToken() - case token - of plusStr: - if streamPos != beforeStream: - raise newException(EventStreamError, "Illegal +STR") - streamPos = inStream - eventStart(yamlStartStream) - of minusStr: - if streamPos != inStream: - raise newException(EventStreamError, "Illegal -STR") - streamPos = afterStream - eventStart(yamlEndStream) - of plusDoc: eventStart(yamlStartDoc) - of minusDoc: eventStart(yamlEndDoc) - of plusMap: eventStart(yamlStartMap) - of minusMap: eventStart(yamlEndMap) - of plusSeq: eventStart(yamlStartSeq) - of minusSeq: eventStart(yamlEndSeq) - of eqVal: eventStart(yamlScalar) - of eqAli: eventStart(yamlAlias) - of mapBraces: - assertInEvent("braces") - curEvent.mapStyle = csFlow - of seqBrackets: - assertInEvent("brackets") - curEvent.seqStyle = csFlow - of chevTag: - assertInEvent("tag") - if curTag() != yTagQuestionMark: - raise newException(EventStreamError, - "Duplicate tag in " & $curEvent.kind) - setCurTag(Tag(lex.content)) - of andAnchor: - assertInEvent("anchor") - if curAnchor() != yAnchorNone: - raise newException(EventStreamError, - "Duplicate anchor in " & $curEvent.kind) - setCurAnchor(lex.content.Anchor) - of starAnchor: - assertInEvent("alias") - if curEvent.kind != yamlAlias: - raise newException(EventStreamError, "Unexpected alias: " & - escape(lex.content)) - elif curEvent.aliasTarget != yAnchorNone: - raise newException(EventStreamError, "Duplicate alias target: " & - escape(lex.content)) - else: - curEvent.aliasTarget = lex.content.Anchor - of colonContent: - assertInEvent("scalar content") - curEvent.scalarContent = lex.content - if curEvent.kind != yamlScalar: - raise newException(EventStreamError, - "scalar content in non-scalar tag") - of sqContent: - assertInEvent("scalar content") - curEvent.scalarContent = lex.content - if curTag() == yTagQuestionMark: setCurTag(yTagExclamationMark) - curEvent.scalarStyle = ssSingleQuoted - of dqContent: - assertInEvent("scalar content") - curEvent.scalarContent = lex.content - if curTag() == yTagQuestionMark: setCurTag(yTagExclamationMark) - curEvent.scalarStyle = ssDoubleQuoted - of litContent: - assertInEvent("scalar content") - curEvent.scalarContent = lex.content - curEvent.scalarStyle = ssLiteral - of foContent: - assertInEvent("scalar content") - curEvent.scalarContent = lex.content - curEvent.scalarStyle = ssFolded - of explDirEnd: - assertInEvent("explicit directives end") - if curEvent.kind != yamlStartDoc: - raise newException(EventStreamError, - "Unexpected explicit directives end") - of explDocEnd: - if curEvent.kind != yamlEndDoc: - raise newException(EventStreamError, - "Unexpected explicit document end") - of noToken: discard - yieldEvent() - if streamPos == inStream: - yield Event(kind: yamlEndStream) - result = initYamlStream(backend) \ No newline at end of file diff --git a/lib/yaml/test/tests.nim b/lib/yaml/test/tests.nim deleted file mode 100644 index 1a0746d..0000000 --- a/lib/yaml/test/tests.nim +++ /dev/null @@ -1,11 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2015 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - - -import tlex, tjson, tserialization, tparser, tquickstart, tannotations - -when not defined(gcArc) or defined(gcOrc): - import tdom \ No newline at end of file diff --git a/lib/yaml/test/tjson.nim b/lib/yaml/test/tjson.nim deleted file mode 100644 index 5826b34..0000000 --- a/lib/yaml/test/tjson.nim +++ /dev/null @@ -1,58 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2015 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import "../yaml" - -import unittest, json - -proc ensureEqual(yamlIn, jsonIn: string) = - try: - var - parser = initYamlParser(true) - s = parser.parse(yamlIn) - yamlResult = constructJson(s) - jsonResult = parseJson(jsonIn) - assert yamlResult.len == 1 - assert(jsonResult == yamlResult[0], "Expected: " & $jsonResult & ", got: " & - $yamlResult[0]) - except YamlStreamError: - let e = (ref YamlParserError)(getCurrentException().parent) - echo "error occurred: " & e.msg - echo "line: ", e.mark.line, ", column: ", e.mark.column - echo e.lineContent - raise e - -suite "Constructing JSON": - test "Simple Sequence": - ensureEqual("- 1\n- 2\n- 3", "[1, 2, 3]") - - test "Simple Map": - ensureEqual("a: b\nc: d", """{"a": "b", "c": "d"}""") - - test "Complex Structure": - ensureEqual(""" -%YAML 1.2 ---- -Foo: - - - a - - b - - c - - bla: blubb -Numbers, bools, special values: - - 1 - - true - - ~ - - 42.23 - - no -""", """{ -"Foo": [ - [ "a", "b", "c"], - { "bla": "blubb"} -], -"Numbers, bools, special values": [ - 1, true, null, 42.23, false -] -}""") \ No newline at end of file diff --git a/lib/yaml/test/tlex.nim b/lib/yaml/test/tlex.nim deleted file mode 100644 index b14d19e..0000000 --- a/lib/yaml/test/tlex.nim +++ /dev/null @@ -1,231 +0,0 @@ -import ../yaml/private/lex - -import unittest, strutils - -const - tokensWithValue = - {Token.Plain, Token.SingleQuoted, Token.DoubleQuoted, Token.Literal, - Token.Folded, Token.Suffix, Token.VerbatimTag, - Token.UnknownDirective} - tokensWithFullLexeme = - {Token.DirectiveParam, Token.TagHandle} - tokensWithShortLexeme = {Token.Anchor, Token.Alias} - - -type - TokenWithValue = object - case kind: Token - of tokensWithValue: - value: string - of tokensWithFullLexeme: - lexeme: string - of tokensWithShortLexeme: - slexeme: string - of Indentation: - indentation: int - else: discard - -proc actualRepr(lex: Lexer, t: Token): string = - result = $t - case t - of tokensWithValue + {Token.TagHandle}: - result.add("(" & escape(lex.evaluated) & ")") - of Indentation: - result.add("(" & $lex.currentIndentation() & ")") - else: discard - -proc assertEquals(input: string, expected: varargs[TokenWithValue]) = - var - lex: Lexer - i = 0 - lex.init(input) - for expectedToken in expected: - inc(i) - try: - lex.next() - doAssert lex.cur == expectedToken.kind, "Wrong token kind at #" & $i & - ": Expected " & $expectedToken.kind & ", got " & - lex.actualRepr(lex.cur) - case expectedToken.kind - of tokensWithValue: - doAssert lex.evaluated == expectedToken.value, "Wrong token content at #" & - $i & ": Expected " & escape(expectedToken.value) & - ", got " & escape(lex.evaluated) - of tokensWithFullLexeme: - doAssert lex.fullLexeme() == expectedToken.lexeme, "Wrong token lexeme at #" & - $i & ": Expected" & escape(expectedToken.lexeme) & - ", got " & escape(lex.fullLexeme()) - of tokensWithShortLexeme: - doAssert lex.shortLexeme() == expectedToken.slexeme, "Wrong token slexeme at #" & - $i & ": Expected" & escape(expectedToken.slexeme) & - ", got " & escape(lex.shortLexeme()) - of Indentation: - doAssert lex.currentIndentation() == expectedToken.indentation, - "Wrong indentation length at #" & $i & ": Expected " & - $expectedToken.indentation & ", got " & $lex.currentIndentation() - else: discard - except LexerError: - let e = (ref LexerError)(getCurrentException()) - echo "Error at line", e.line, ", column", e.column, ":", e.msg - echo e.lineContent - assert false - -proc i(indent: int): TokenWithValue = - TokenWithValue(kind: Token.Indentation, indentation: indent) -proc pl(v: string): TokenWithValue = - TokenWithValue(kind: Token.Plain, value: v) -proc sq(v: string): TokenWithValue = - TokenWithValue(kind: Token.SingleQuoted, value: v) -proc dq(v: string): TokenWithValue = - TokenWithValue(kind: Token.DoubleQuoted, value: v) -proc e(): TokenWithValue = TokenWithValue(kind: Token.StreamEnd) -proc mk(): TokenWithValue = TokenWithValue(kind: Token.MapKeyInd) -proc mv(): TokenWithValue = TokenWithValue(kind: Token.MapValueInd) -proc si(): TokenWithValue = TokenWithValue(kind: Token.SeqItemInd) -proc dy(): TokenWithValue = TokenWithValue(kind: Token.YamlDirective) -proc dt(): TokenWithValue = TokenWithValue(kind: Token.TagDirective) -proc du(v: string): TokenWithValue = - TokenWithValue(kind: Token.UnknownDirective, value: v) -proc dp(v: string): TokenWithValue = - TokenWithValue(kind: Token.DirectiveParam, lexeme: v) -proc th(v: string): TokenWithValue = - TokenWithValue(kind: Token.TagHandle, lexeme: v) -proc ts(v: string): TokenWithValue = - TokenWithValue(kind: Token.Suffix, value: v) -proc tv(v: string): TokenWithValue = - TokenWithValue(kind: Token.VerbatimTag, value: v) -proc dirE(): TokenWithValue = TokenWithValue(kind: Token.DirectivesEnd) -proc docE(): TokenWithValue = TokenWithValue(kind: Token.DocumentEnd) -proc ls(v: string): TokenWithValue = TokenWithValue(kind: Token.Literal, value: v) -proc fs(v: string): TokenWithValue = TokenWithValue(kind: Token.Folded, value: v) -proc ss(): TokenWithValue = TokenWithValue(kind: Token.SeqStart) -proc se(): TokenWithValue = TokenWithValue(kind: Token.SeqEnd) -proc ms(): TokenWithValue = TokenWithValue(kind: Token.MapStart) -proc me(): TokenWithValue = TokenWithValue(kind: Token.MapEnd) -proc sep(): TokenWithValue = TokenWithValue(kind: Token.SeqSep) -proc an(v: string): TokenWithValue = TokenWithValue(kind: Token.Anchor, slexeme: v) -proc al(v: string): TokenWithValue = TokenWithValue(kind: Token.Alias, slexeme: v) - -suite "Lexer": - test "Empty document": - assertEquals("", e()) - - test "Single-line scalar": - assertEquals("scalar", i(0), pl("scalar"), e()) - - test "Multiline scalar": - assertEquals("scalar\l line two", i(0), pl("scalar line two"), e()) - - test "Single-line mapping": - assertEquals("key: value", i(0), pl("key"), mv(), pl("value"), e()) - - test "Multiline mapping": - assertEquals("key:\n value", i(0), pl("key"), mv(), i(2), pl("value"), - e()) - - test "Explicit mapping": - assertEquals("? key\n: value", i(0), mk(), pl("key"), i(0), mv(), - pl("value"), e()) - - test "Sequence": - assertEquals("- a\n- b", i(0), si(), pl("a"), i(0), si(), pl("b"), e()) - - test "Single-line single-quoted scalar": - assertEquals("'quoted scalar'", i(0), sq("quoted scalar"), e()) - - test "Multiline single-quoted scalar": - assertEquals("'quoted\l multi line \l\lscalar'", i(0), - sq("quoted multi line\lscalar"), e()) - - test "Single-line double-quoted scalar": - assertEquals("\"quoted scalar\"", i(0), dq("quoted scalar"), e()) - - test "Multiline double-quoted scalar": - assertEquals("\"quoted\l multi line \l\lscalar\"", i(0), - dq("quoted multi line\lscalar"), e()) - - test "Escape sequences": - assertEquals(""""\n\x31\u0032\U00000033"""", i(0), dq("\l123"), e()) - - test "Directives": - assertEquals("%YAML 1.2\n---\n%TAG\n...\n\n%TAG ! example.html", - dy(), dp("1.2"), dirE(), i(0), pl("%TAG"), docE(), dt(), - th("!"), ts("example.html"), e()) - - test "Markers and Unknown Directive": - assertEquals("---\n---\n...\n%UNKNOWN warbl", dirE(), dirE(), - docE(), du("UNKNOWN"), dp("warbl"), e()) - - test "Block scalar": - assertEquals("|\l a\l\l b\l # comment", i(0), ls("a\l\lb\l"), e()) - - test "Block Scalars": - assertEquals("one : >2-\l foo\l bar\ltwo: |+\l bar\l baz", i(0), - pl("one"), mv(), fs(" foo\nbar"), i(0), pl("two"), mv(), - ls("bar\l baz"), e()) - - test "Flow indicators": - assertEquals("bla]: {c: d, [e]: f}", i(0), pl("bla]"), mv(), ms(), pl("c"), - mv(), pl("d"), sep(), ss(), pl("e"), se(), mv(), pl("f"), me(), e()) - - test "Adjacent map values in flow style": - assertEquals("{\"foo\":bar, [1]\l :egg}", i(0), ms(), dq("foo"), mv(), - pl("bar"), sep(), ss(), pl("1"), se(), mv(), pl("egg"), me(), e()) - - test "Tag handles": - assertEquals("- !!str string\l- !local local\l- !e! e", i(0), si(), - th("!!"), ts("str"), pl("string"), i(0), si(), th("!"), ts("local"), - pl("local"), i(0), si(), th("!e!"), ts(""), pl("e"), e()) - - test "Literal tag handle": - assertEquals("! string", i(0), - tv("tag:yaml.org,2002:str"), pl("string"), e()) - - test "Anchors and aliases": - assertEquals("&a foo: {&b b: *a, *b : c}", i(0), an("a"), pl("foo"), mv(), - ms(), an("b"), pl("b"), mv(), al("a"), sep(), al("b"), mv(), pl("c"), - me(), e()) - - test "Space at implicit key": - assertEquals("foo :\n bar", i(0), pl("foo"), mv(), i(2), pl("bar"), e()) - - test "inline anchor at implicit key": - assertEquals("top6: \l &anchor6 'key6' : scalar6", i(0), pl("top6"), mv(), - i(2), an("anchor6"), sq("key6"), mv(), pl("scalar6"), e()) - - test "adjacent anchors": - assertEquals("foo: &a\n &b bar", i(0), pl("foo"), mv(), an("a"), i(2), - an("b"), pl("bar"), e()) - - test "comment at empty key/value pair": - assertEquals(": # foo\nbar:", i(0), mv(), i(0), pl("bar"), mv(), e()) - - test "Map in Sequence": - assertEquals("""- - a: b - c: d -""", i(0), si(), i(2), pl("a"), mv(), pl("b"), i(2), pl("c"), mv(), pl("d"), e()) - - test "dir end after multiline scalar": - assertEquals("foo:\n bar\n baz\n---\nderp", i(0), pl("foo"), mv(), i(2), - pl("bar baz"), dirE(), i(0), pl("derp"), e()) - - test "Sequence with compact maps": - assertEquals("- a: drzw\n- b", i(0), si(), pl("a"), mv(), pl("drzw"), i(0), si(), pl("b"), e()) - - test "Empty lines": - assertEquals("""block: foo - - bar - - baz -flow: { - foo - - bar: baz - - - mi -}""", i(0), pl("block"), mv(), pl("foo\nbar\nbaz"), - i(0), pl("flow"), mv(), ms(), pl("foo\nbar"), mv(), - pl("baz\n\nmi"), me(), e()) diff --git a/lib/yaml/test/tparser.nim b/lib/yaml/test/tparser.nim deleted file mode 100644 index fcd152f..0000000 --- a/lib/yaml/test/tparser.nim +++ /dev/null @@ -1,93 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import os, terminal, strutils, streams, macros, unittest, sets -import testEventParser, commonTestUtils -import ../yaml, ../yaml/data - -const - testSuiteFolder = "yaml-test-suite" - -proc echoError(msg: string) = - styledWriteLine(stdout, fgRed, "[error] ", fgWhite, msg, resetStyle) - - -proc parserTest(path: string, errorExpected : bool): bool = - var - parser: YamlParser - parser.init() - var - actualIn = newFileStream(path / "in.yaml") - actual = parser.parse(actualIn) - expectedIn = newFileStream(path / "test.event") - expected = parseEventStream(expectedIn) - defer: - actualIn.close() - expectedIn.close() - var i = 1 - try: - while true: - let actualEvent = actual.next() - let expectedEvent = expected.next() - if expectedEvent != actualEvent: - result = errorExpected - if not result: - echoError("At event #" & $i & - ": Actual events do not match expected events") - echo ".. expected event:" - echo " ", expectedEvent - echo ".. actual event:" - echo " ", actualEvent - echo ".. difference:" - stdout.write(" ") - printDifference(expectedEvent, actualEvent) - - return - i.inc() - if actualEvent.kind == yamlEndStream: - break - result = not errorExpected - if not result: - echo "Expected error, but parsed without error." - except: - result = errorExpected - if not result: - echoError("Caught an exception at event #" & $i & - " test was not successful") - let e = getCurrentException() - if e.parent of YamlParserError: - let pe = (ref YamlParserError)(e.parent) - echo "line ", pe.mark.line, ", column ", pe.mark.column, ": ", pe.msg - echo pe.lineContent - else: echo e.msg - -macro genTests(): untyped = - let - pwd = staticExec("pwd").strip - absolutePath = '"' & (pwd / testSuiteFolder) & '"' - echo "[tparser] Generating tests from " & absolutePath - discard staticExec("git submodule init && git submodule update --remote") - - let errorTests = toHashSet(staticExec("cd " & (absolutePath / "tags" / "error") & - " && ls -1d *").splitLines()) - var ignored = toHashSet([".git", "name", "tags", "meta"]) - - result = newStmtList() - # walkDir for some crude reason does not work with travis build - let dirItems = staticExec("ls -1d " & absolutePath / "*") - for dirPath in dirItems.splitLines(): - if dirPath.strip.len == 0: continue - let testId = dirPath[^4..^1] - if ignored.contains(testId): continue - let title = slurp(dirPath / "===") - - result.add(newCall("test", - newLit(strip(title) & " [" & - testId & ']'), newCall("doAssert", newCall("parserTest", - newLit(dirPath), newLit(errorTests.contains(testId)))))) - result = newCall("suite", newLit("Parser Tests (from yaml-test-suite)"), result) - -genTests() diff --git a/lib/yaml/test/tquickstart.nim b/lib/yaml/test/tquickstart.nim deleted file mode 100644 index d922100..0000000 --- a/lib/yaml/test/tquickstart.nim +++ /dev/null @@ -1,134 +0,0 @@ -import unittest, os, osproc, macros, strutils, streams - -const baseDir = parentDir(staticExec("pwd")) -let (nimPathRaw, nimPathRet) = - execCmdEx("which nim", {poStdErrToStdOut, poUsePath}) -if nimPathRet != 0: quit "could not locate nim executable:\n" & nimPathRaw -let nimPath = - if nimPathRaw[0] == '/': nimPathRaw.strip else: baseDir / nimPathRaw.strip - -proc inputTest(basePath, path: string): bool = - let - absolutePath = basePath / path - inFileOrig = absolutePath / "01-in.yaml" - inFileDest = absolutePath / "in.yaml" - codeFileOrig = absolutePath / "00-code.nim" - codeFileDest = absolutePath / "code.nim" - exeFileDest = when defined(windows): absolutePath / "code.exe" else: - absolutePath / "code" - copyFile(inFileOrig, inFileDest) - copyFile(codeFileOrig, codeFileDest) - defer: - removeFile(inFileDest) - removeFile(codeFileDest) - var process = startProcess(nimPath & " c --hints:off -p:" & escape(basePath) & - " code.nim", absolutePath, [], nil, {poStdErrToStdOut, poEvalCommand}) - defer: - process.close() - if process.waitForExit() != 0: - echo "compiler output:" - echo "================\n" - echo process.outputStream().readAll() - result = false - else: - defer: removeFile(exeFileDest) - process.close() - process = startProcess(absolutePath / "code", absolutePath, [], nil, - {poStdErrToStdOut, poEvalCommand}) - if process.waitForExit() != 0: - echo "executable output:" - echo "==================\n" - echo process.outputStream().readAll() - result = false - else: result = true - -proc outputTest(basePath, path: string): bool = - let - absolutePath = basePath / path - codeFileOrig = absolutePath / "00-code.nim" - codeFileDest = absolutePath / "code.nim" - exeFileDest = when defined(windows): absolutePath / "code.exe" else: - absolutePath / "code" - outFileExpected = absolutePath / "01-out.yaml" - outFileActual = absolutePath / "out.yaml" - copyFile(codeFileOrig, codeFileDest) - defer: removeFile(codeFileDest) - var process = startProcess(nimPath & " c --hints:off -p:" & escape(basePath) & - " code.nim", absolutePath, [], nil, {poStdErrToStdOut, poEvalCommand}) - defer: process.close() - if process.waitForExit() != 0: - echo "compiler output:" - echo "================\n" - echo process.outputStream().readAll() - result = false - else: - defer: removeFile(exeFileDest) - process.close() - process = startProcess(absolutePath / "code", absolutePath, [], nil, - {poStdErrToStdOut, poEvalCommand}) - if process.waitForExit() != 0: - echo "executable output:" - echo "==================\n" - echo process.outputStream().readAll() - result = false - else: - defer: removeFile(outFileActual) - var - expected = open(outFileExpected, fmRead) - actual = open(outFileActual, fmRead) - lineNumber = 1 - defer: - expected.close() - actual.close() - var - expectedLine = "" - actualLine = "" - while true: - if expected.readLine(expectedLine): - if actual.readLine(actualLine): - if expectedLine != actualLine: - echo "difference at line #", lineNumber, ':' - echo "expected: ", escape(expectedLine) - echo " actual: ", escape(actualLine) - return false - else: - echo "actual output has fewer lines than expected; ", - "first missing line: #", lineNumber - echo "expected: ", escape(expectedLine) - return false - else: - if actual.readLine(actualLine): - echo "actual output has more lines than expected; ", - "first unexpected line: #", lineNumber - echo "content: ", escape(actualLine) - return false - else: break - lineNumber.inc() - result = true - -proc testsFor(path: string, root: bool = true, titlePrefix: string = ""): - NimNode {.compileTime.} = - result = newStmtList() - let - title = titlePrefix & slurp(baseDir / path / "title").splitLines()[0] - if fileExists(path / "00-code.nim"): - var test = newCall("test", newLit(title)) - if fileExists(path / "01-in.yaml"): - test.add(newCall("doAssert", newCall("inputTest", newLit(baseDir), - newLit(path)))) - elif fileExists(path / "01-out.yaml"): - test.add(newCall("doAssert", newCall("outputTest", newLit(baseDir), - newLit(path)))) - else: - error("Error: neither 01-in.yaml nor 01-out.yaml exists in " & path & '!') - result.add(test) - for kind, childPath in walkDir(path): - if kind == pcDir: - if childPath != path / "nimcache": - result.add(testsFor(childPath, false, if root: "" else: title & ' ')) - if root: - result = newCall("suite", newLit(title), result) - -macro genTests(): untyped = testsFor("doc/snippets/quickstart") - -genTests() \ No newline at end of file diff --git a/lib/yaml/test/tserialization.nim b/lib/yaml/test/tserialization.nim deleted file mode 100644 index c0bbcde..0000000 --- a/lib/yaml/test/tserialization.nim +++ /dev/null @@ -1,655 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2015 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import "../yaml" -import unittest, strutils, tables, times, math, options - -type - MyTuple = tuple - str: string - i: int32 - b: bool - - TrafficLight = enum - tlGreen, tlYellow, tlRed - - Person = object - firstnamechar: char - surname: string - age: int32 - - Node = object - value: string - next: ref Node - - BetterInt = distinct int - - AnimalKind = enum - akCat, akDog - - Animal = object - name: string - case kind: AnimalKind - of akCat: - purringIntensity: int - of akDog: barkometer: int - - DumbEnum = enum - deA, deB, deC - - NonVariantWithTransient = object - a {.transient.}, b, c {.transient.}, d: string - - VariantWithTransient = object - gStorable: string - gTemporary {.transient.}: string - case kind: DumbEnum - of deA: - cStorable: string - cTemporary {.transient.}: string - of deB: - alwaysThere: int - of deC: - neverThere {.transient.}: int - - WithDefault = object - a, b {.defaultVal: "b".}, c, d {.defaultVal: "d".}: string - - WithIgnoredField {.ignore: ["z"].} = object - x, y: int - -proc `$`(v: BetterInt): string {.borrow.} -proc `==`(left, right: BetterInt): bool {.borrow.} - -setTag(TrafficLight, Tag("!tl")) -setTag(Node, Tag("!example.net:Node")) -setTag(BetterInt, Tag("!test:BetterInt")) - -const yamlDirs = "%YAML 1.2\n%TAG !n! tag:nimyaml.org,2016:\n--- " - -proc representObject*(value: BetterInt, ts: TagStyle = tsNone, - c: SerializationContext, tag: Tag) {.raises: [].} = - var - val = $value - i = val.len - 3 - while i > 0: - val.insert("_", i) - i -= 3 - c.put(scalarEvent(val, tag, yAnchorNone)) - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var BetterInt) - {.raises: [YamlConstructionError, YamlStreamError].} = - constructScalarItem(s, item, BetterInt): - result = BetterInt(parseBiggestInt(item.scalarContent) + 1) - -template assertStringEqual(expected, actual: string) = - if expected != actual: - # if they are unequal, walk through the strings and check each - # character for a better error message - if expected.len != actual.len: - echo "Expected and actual string's length differs.\n" - echo "Expected length: ", expected.len, "\n" - echo "Actual length: ", actual.len, "\n" - # check length up to smaller of the two strings - for i in countup(0, min(expected.high, actual.high)): - if expected[i] != actual[i]: - echo "string mismatch at character #", i, "(expected:\'", - expected[i], "\', was \'", actual[i], "\'):\n" - echo "expected:\n", expected, "\nactual:\n", actual, "\n" - assert(false) - # if we haven't raised an assertion error here, the problem is that - # one string is longer than the other - let minInd = min(expected.len, actual.len) # len instead of high to continue - # after shorter string - if expected.high > actual.high: - echo "Expected continues with: '", expected[minInd .. ^1], "'" - assert false - else: - echo "Actual continues with: '", actual[minInd .. ^1], "'" - assert false - -template expectConstructionError(li, co: int, message: string, body: typed) = - try: - body - echo "Expected YamlConstructionError, but none was raised!" - fail() - except YamlConstructionError: - let e = (ref YamlConstructionError)(getCurrentException()) - doAssert li == e.mark.line, "Expected error line " & $li & ", was " & $e.mark.line - doAssert co == e.mark.column, "Expected error column " & $co & ", was " & $e.mark.column - doAssert message == e.msg, "Expected error message \n" & escape(message) & - ", got \n" & escape(e.msg) - -proc newNode(v: string): ref Node = - new(result) - result.value = v - result.next = nil - -let blockOnly = defineOptions(style=psBlockOnly) - -suite "Serialization": - test "Load integer without fixed length": - var input = "-4247" - var result: int - load(input, result) - assert result == -4247, "result is " & $result - - input = $(int64(int32.high) + 1'i64) - var gotException = false - try: load(input, result) - except: gotException = true - assert gotException, "Expected exception, got none." - - test "Dump integer without fixed length": - var input = -4247 - var output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\n\"-4247\"", output - - when sizeof(int) == sizeof(int64): - input = int(int32.high) + 1 - var gotException = false - try: output = dump(input, tsNone, asTidy, blockOnly) - except: gotException = true - assert gotException, "Expected exception, got none." - - test "Load Hex byte (0xFF)": - let input = "0xFF" - var result: byte - load(input, result) - assert(result == 255) - - test "Load Hex byte (0xC)": - let input = "0xC" - var result: byte - load(input, result) - assert(result == 12) - - test "Load Octal byte (0o14)": - let input = "0o14" - var result: byte - load(input, result) - assert(result == 12) - - test "Load byte (14)": - let input = "14" - var result: byte - load(input, result) - assert(result == 14) - - test "Load Hex int (0xFF)": - let input = "0xFF" - var result: int - load(input, result) - assert(result == 255) - - test "Load Hex int (0xC)": - let input = "0xC" - var result: int - load(input, result) - assert(result == 12) - - test "Load Octal int (0o14)": - let input = "0o14" - var result: int - load(input, result) - assert(result == 12) - - test "Load int (14)": - let input = "14" - var result: int - load(input, result) - assert(result == 14) - - test "Load floats": - let input = "[6.8523015e+5, 685.230_15e+03, 685_230.15, -.inf, .NaN]" - var result: seq[float] - load(input, result) - for i in 0..2: - assert result[i] == 6.8523015e+5 - assert result[3] == NegInf - assert classify(result[4]) == fcNan - - test "Load timestamps": - let input = "[2001-12-15T02:59:43.1Z, 2001-12-14t21:59:43.10-05:00, 2001-12-14 21:59:43.10-5]" - var result: seq[Time] - load(input, result) - assert result.len() == 3 - # currently, there is no good way of checking the result content, because - # the parsed Time may have any timezone offset. - - test "Load string sequence": - let input = " - a\n - b" - var result: seq[string] - load(input, result) - assert result.len == 2 - assert result[0] == "a" - assert result[1] == "b" - - test "Dump string sequence": - var input = @["a", "b"] - var output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\n- a\n- b", output - - test "Load char set": - let input = "- a\n- b" - var result: set[char] - load(input, result) - assert result.card == 2 - assert 'a' in result - assert 'b' in result - - test "Dump char set": - var input = {'a', 'b'} - var output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\n- a\n- b", output - - test "Load array": - let input = "- 23\n- 42\n- 47" - var result: array[0..2, int32] - load(input, result) - assert result[0] == 23 - assert result[1] == 42 - assert result[2] == 47 - - test "Dump array": - let input = [23'i32, 42'i32, 47'i32] - var output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\n- 23\n- 42\n- 47", output - - test "Load Option": - let input = "- Some\n- !!null ~" - var result: array[0..1, Option[string]] - load(input, result) - assert result[0].isSome - assert result[0].get() == "Some" - assert not result[1].isSome - - test "Dump Option": - let input = [none(int32), some(42'i32), none(int32)] - let output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\n- !!null ~\n- 42\n- !!null ~", output - - test "Load Table[int, string]": - let input = "23: dreiundzwanzig\n42: zweiundvierzig" - var result: Table[int32, string] - load(input, result) - assert result.len == 2 - assert result[23] == "dreiundzwanzig" - assert result[42] == "zweiundvierzig" - - test "Dump Table[int, string]": - var input = initTable[int32, string]() - input[23] = "dreiundzwanzig" - input[42] = "zweiundvierzig" - var output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual(yamlDirs & "\n23: dreiundzwanzig\n42: zweiundvierzig", - output) - - test "Load OrderedTable[tuple[int32, int32], string]": - let input = "- {a: 23, b: 42}: drzw\n- {a: 13, b: 47}: drsi" - var result: OrderedTable[tuple[a, b: int32], string] - load(input, result) - var i = 0 - for key, value in result.pairs: - case i - of 0: - assert key == (a: 23'i32, b: 42'i32) - assert value == "drzw" - of 1: - assert key == (a: 13'i32, b: 47'i32) - assert value == "drsi" - else: assert false - i.inc() - - test "Dump OrderedTable[tuple[int32, int32], string]": - var input = initOrderedTable[tuple[a, b: int32], string]() - input[(a: 23'i32, b: 42'i32)] = "dreiundzwanzigzweiundvierzig" - input[(a: 13'i32, b: 47'i32)] = "dreizehnsiebenundvierzig" - var output = dump(input, tsRootOnly, asTidy, blockOnly) - assertStringEqual(yamlDirs & - "!n!tables:OrderedTable(tag:nimyaml.org;2016:tuple(tag:nimyaml.org;2016:system:int32;tag:nimyaml.org;2016:system:int32);tag:yaml.org;2002:str) \n" & - "- \n" & - " ? \n" & - " a: 23\n" & - " b: 42\n" & - " : dreiundzwanzigzweiundvierzig\n" & - "- \n" & - " ? \n" & - " a: 13\n" & - " b: 47\n" & - " : dreizehnsiebenundvierzig", output) - - test "Load Sequences in Sequence": - let input = " - [1, 2, 3]\n - [4, 5]\n - [6]" - var result: seq[seq[int32]] - load(input, result) - assert result.len == 3 - assert result[0] == @[1.int32, 2.int32, 3.int32] - assert result[1] == @[4.int32, 5.int32] - assert result[2] == @[6.int32] - - test "Dump Sequences in Sequence": - let input = @[@[1.int32, 2.int32, 3.int32], @[4.int32, 5.int32], @[6.int32]] - var output = dump(input, tsNone) - assertStringEqual yamlDirs & "\n- [1, 2, 3]\n- [4, 5]\n- [6]", output - - test "Load Enum": - let input = - "!\n- !tl tlRed\n- tlGreen\n- tlYellow" - var result: seq[TrafficLight] - load(input, result) - assert result.len == 3 - assert result[0] == tlRed - assert result[1] == tlGreen - assert result[2] == tlYellow - - test "Dump Enum": - let input = @[tlRed, tlGreen, tlYellow] - var output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\n- tlRed\n- tlGreen\n- tlYellow", output - - test "Load Tuple": - let input = "str: value\ni: 42\nb: true" - var result: MyTuple - load(input, result) - assert result.str == "value" - assert result.i == 42 - assert result.b == true - - test "Dump Tuple": - let input = (str: "value", i: 42.int32, b: true) - var output = dump(input, tsNone) - assertStringEqual yamlDirs & "\nstr: value\ni: 42\nb: true", output - - test "Load Tuple - unknown field": - let input = "str: value\nfoo: bar\ni: 42\nb: true" - var result: MyTuple - expectConstructionError(2, 1, "While constructing MyTuple: Unknown field: \"foo\""): - load(input, result) - - test "Load Tuple - missing field": - let input = "str: value\nb: true" - var result: MyTuple - expectConstructionError(1, 1, "While constructing MyTuple: Missing field: \"i\""): - load(input, result) - - test "Load Tuple - duplicate field": - let input = "str: value\ni: 42\nb: true\nb: true" - var result: MyTuple - expectConstructionError(4, 1, "While constructing MyTuple: Duplicate field: \"b\""): - load(input, result) - - test "Load Multiple Documents": - let input = "1\n---\n2" - var result: seq[int] - loadMultiDoc(input, result) - assert(result.len == 2) - assert result[0] == 1 - assert result[1] == 2 - - test "Load Multiple Documents (Single Doc)": - let input = "1" - var result: seq[int] - loadMultiDoc(input, result) - assert(result.len == 1) - assert result[0] == 1 - - test "Load custom object": - let input = "firstnamechar: P\nsurname: Pan\nage: 12" - var result: Person - load(input, result) - assert result.firstnamechar == 'P' - assert result.surname == "Pan" - assert result.age == 12 - - test "Dump custom object": - let input = Person(firstnamechar: 'P', surname: "Pan", age: 12) - var output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual(yamlDirs & - "\nfirstnamechar: P\nsurname: Pan\nage: 12", output) - - test "Load custom object - unknown field": - let input = " firstnamechar: P\n surname: Pan\n age: 12\n occupation: free" - var result: Person - expectConstructionError(4, 3, "While constructing Person: Unknown field: \"occupation\""): - load(input, result) - - test "Load custom object - missing field": - let input = "surname: Pan\nage: 12\n " - var result: Person - expectConstructionError(1, 1, "While constructing Person: Missing field: \"firstnamechar\""): - load(input, result) - - test "Load custom object - duplicate field": - let input = "firstnamechar: P\nsurname: Pan\nage: 12\nsurname: Pan" - var result: Person - expectConstructionError(4, 1, "While constructing Person: Duplicate field: \"surname\""): - load(input, result) - - test "Load sequence with explicit tags": - let input = yamlDirs & "!n!system:seq(" & - "tag:yaml.org;2002:str)\n- !!str one\n- !!str two" - var result: seq[string] - load(input, result) - assert result[0] == "one" - assert result[1] == "two" - - test "Dump sequence with explicit tags": - let input = @["one", "two"] - var output = dump(input, tsAll, asTidy, blockOnly) - assertStringEqual(yamlDirs & "!n!system:seq(" & - "tag:yaml.org;2002:str) \n- !!str one\n- !!str two", output) - - test "Load custom object with explicit root tag": - let input = - "--- !\nfirstnamechar: P\nsurname: Pan\nage: 12" - var result: Person - load(input, result) - assert result.firstnamechar == 'P' - assert result.surname == "Pan" - assert result.age == 12 - - test "Dump custom object with explicit root tag": - let input = Person(firstnamechar: 'P', surname: "Pan", age: 12) - var output = dump(input, tsRootOnly, asTidy, blockOnly) - assertStringEqual(yamlDirs & - "!n!custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12", output) - - test "Load custom variant object": - let input = - "---\n- - name: Bastet\n - kind: akCat\n - purringIntensity: 7\n" & - "- - name: Anubis\n - kind: akDog\n - barkometer: 13" - var result: seq[Animal] - load(input, result) - assert result.len == 2 - assert result[0].name == "Bastet" - assert result[0].kind == akCat - assert result[0].purringIntensity == 7 - assert result[1].name == "Anubis" - assert result[1].kind == akDog - assert result[1].barkometer == 13 - - test "Dump custom variant object": - let input = @[Animal(name: "Bastet", kind: akCat, purringIntensity: 7), - Animal(name: "Anubis", kind: akDog, barkometer: 13)] - var output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\n" & - "- \n" & - " - \n" & - " name: Bastet\n" & - " - \n" & - " kind: akCat\n" & - " - \n" & - " purringIntensity: 7\n" & - "- \n" & - " - \n" & - " name: Anubis\n" & - " - \n" & - " kind: akDog\n" & - " - \n" & - " barkometer: 13", output - - test "Load custom variant object - missing field": - let input = "[{name: Bastet}, {kind: akCat}]" - var result: Animal - expectConstructionError(1, 1, "While constructing Animal: Missing field: \"purringIntensity\""): - load(input, result) - - test "Load non-variant object with transient fields": - let input = "{b: b, d: d}" - var result: NonVariantWithTransient - load(input, result) - assert result.a.len == 0 - assert result.b == "b" - assert result.c.len == 0 - assert result.d == "d" - - test "Load non-variant object with transient fields - unknown field": - let input = "{b: b, c: c, d: d}" - var result: NonVariantWithTransient - expectConstructionError(1, 8, "While constructing NonVariantWithTransient: Field \"c\" is transient and may not occur in input"): - load(input, result) - - test "Dump non-variant object with transient fields": - let input = NonVariantWithTransient(a: "a", b: "b", c: "c", d: "d") - let output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\nb: b\nd: d", output - - test "Load variant object with transient fields": - let input = "[[gStorable: gs, kind: deA, cStorable: cs], [gStorable: a, kind: deC]]" - var result: seq[VariantWithTransient] - load(input, result) - assert result.len == 2 - assert result[0].kind == deA - assert result[0].gStorable == "gs" - assert result[0].cStorable == "cs" - assert result[1].kind == deC - assert result[1].gStorable == "a" - - test "Load variant object with transient fields, error": - let input = "[gStorable: gc, kind: deC, neverThere: foo]" - var result: VariantWithTransient - expectConstructionError(1, 28, "While constructing VariantWithTransient: Field \"neverThere\" is transient and may not occur in input"): - load(input, result) - - test "Dump variant object with transient fields": - let input = @[VariantWithTransient(kind: deA, gStorable: "gs", - gTemporary: "gt", cStorable: "cs", cTemporary: "ct"), - VariantWithTransient(kind: deC, gStorable: "a", gTemporary: "b", - neverThere: 42)] - let output = dump(input, tsNone, asTidy, blockOnly) - assertStringEqual yamlDirs & "\n" & - "- \n" & - " - \n" & - " gStorable: gs\n" & - " - \n" & - " kind: deA\n" & - " - \n" & - " cStorable: cs\n" & - "- \n" & - " - \n" & - " gStorable: a\n" & - " - \n" & - " kind: deC", output - - test "Load object with ignored key": - let input = "[{x: 1, y: 2}, {x: 3, z: 4, y: 5}, {z: [1, 2, 3], x: 4, y: 5}]" - var result: seq[WithIgnoredField] - load(input, result) - assert result.len == 3 - assert result[0].x == 1 - assert result[0].y == 2 - assert result[1].x == 3 - assert result[1].y == 5 - assert result[2].x == 4 - assert result[2].y == 5 - - test "Load object with ignored key - unknown field": - let input = "{x: 1, y: 2, zz: 3}" - var result: WithIgnoredField - expectConstructionError(1, 14, "While constructing WithIgnoredField: Unknown field: \"zz\""): - load(input, result) - - when not defined(JS): - test "Dump cyclic data structure": - var - a = newNode("a") - b = newNode("b") - c = newNode("c") - a.next = b - b.next = c - c.next = a - var output = dump(a, tsRootOnly, asTidy, blockOnly) - assertStringEqual yamlDirs & "!example.net:Node &a \n" & - "value: a\n" & - "next: \n" & - " value: b\n" & - " next: \n" & - " value: c\n" & - " next: *a", output - - test "Load cyclic data structure": - let input = yamlDirs & """!n!system:seq(example.net:Node) - - &a - value: a - next: &b - value: b - next: &c - value: c - next: *a - - *b - - *c - """ - var result: seq[ref Node] - try: load(input, result) - except YamlConstructionError: - let ex = (ref YamlConstructionError)(getCurrentException()) - echo "line ", ex.mark.line, ", column ", ex.mark.column, ": ", ex.msg - echo ex.lineContent - raise ex - - assert(result.len == 3) - assert(result[0].value == "a") - assert(result[1].value == "b") - assert(result[2].value == "c") - assert(result[0].next == result[1]) - assert(result[1].next == result[2]) - assert(result[2].next == result[0]) - - test "Load object with default values": - let input = "a: abc\nc: dce" - var result: WithDefault - load(input, result) - assert result.a == "abc" - assert result.b == "b" - assert result.c == "dce" - assert result.d == "d" - - test "Load object with partly default values": - let input = "a: abc\nb: bcd\nc: cde" - var result: WithDefault - load(input, result) - assert result.a == "abc" - assert result.b == "bcd" - assert result.c == "cde" - assert result.d == "d" - - test "Custom constructObject": - let input = "- 1\n- !test:BetterInt 2" - var result: seq[BetterInt] - load(input, result) - assert(result.len == 2) - assert(result[0] == 2.BetterInt) - assert(result[1] == 3.BetterInt) - - test "Custom representObject": - let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt] - var output = dump(input, tsAll, asTidy, blockOnly) - assertStringEqual yamlDirs & "!n!system:seq(test:BetterInt) \n" & - "- !test:BetterInt 1\n" & - "- !test:BetterInt 9_998_887\n" & - "- !test:BetterInt 98_312", output diff --git a/lib/yaml/tools/testSuiteEvents.nim b/lib/yaml/tools/testSuiteEvents.nim deleted file mode 100644 index b4e5c84..0000000 --- a/lib/yaml/tools/testSuiteEvents.nim +++ /dev/null @@ -1,49 +0,0 @@ -import ../yaml/stream, ../yaml/parser, ../yaml/taglib, streams - -var - tags = initExtendedTagLibrary() - p = newYamlParser(tags) - events = p.parse(newFileStream(stdin)) - -proc start(name: string, tag: TagId, anchor: AnchorId, finish: bool = true) = - stdout.write(name) - if tag != yTagQuestionMark: stdout.write(" <" & tags.uri(tag) & ">") - if anchor != yAnchorNone: stdout.write(" &" & p.anchorName(anchor)) - if finish: stdout.write("\n") - -proc writeEscaped(str: string) = - for c in str: - case c - of '\\': stdout.write("\\\\") - of '\l': stdout.write("\\n") - of '\r': stdout.write("\\r") - of '\0': stdout.write("\\0") - of '\b': stdout.write("\\b") - of '\t': stdout.write("\\t") - else: stdout.write(c) - -stdout.write("+STR\n") -while not(events.finished()): - let cur = events.next() - case cur.kind - of yamlStartDoc: stdout.write("+DOC\n") - of yamlStartMap: start("+MAP", cur.mapTag, cur.mapAnchor) - of yamlStartSeq: start("+SEQ", cur.seqTag, cur.seqAnchor) - of yamlEndMap: stdout.write("-MAP\n") - of yamlEndSeq: stdout.write("-SEQ\n") - of yamlEndDoc: stdout.write("-DOC\n") - of yamlScalar: - var - isQuoted = false - tag = cur.scalartag - if cur.scalarTag == yTagExclamationMark: - isQuoted = true - tag = yTagQuestionMark - start("=VAL", tag, cur.scalarAnchor, false) - if isQuoted: stdout.write(" \"") - else: stdout.write(" :") - writeEscaped(cur.scalarContent) - stdout.write("\n") - of yamlAlias: - stdout.write("=ALI *" & p.anchorName(cur.aliasTarget) & "\n") -stdout.write("-STR\n") \ No newline at end of file diff --git a/lib/yaml/yaml.nim b/lib/yaml/yaml.nim deleted file mode 100644 index 60fba4e..0000000 --- a/lib/yaml/yaml.nim +++ /dev/null @@ -1,51 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## This is the parent module of NimYAML, a package that provides facilities to -## generate and interpret `YAML `_ character streams. Importing -## this package will import everything from all subpackages. -## -## There are three high-level APIs which are probably most useful: -## -## * The serialization API in `serialization `_ enables -## you to load YAML data directly into native Nim types, and reversely dump -## native Nim types as YAML. -## * The DOM API in `dom `_ parses YAML files in a tree structure -## which you can navigate. -## * The JSON API in `tojson `_ parses YAML files into the -## Nim stdlib's JSON structure, which may be useful if you have other modules -## which expect JSON input. Note that the serialization API is able to write -## and load JSON; you do not need the JSON API for that. -## -## Apart from those high-level APIs, NimYAML implements a low-level API which -## enables you to process YAML input as data stream which does not need to be -## loaded into RAM completely at once. It consists of the following modules: -## -## * The stream API in `stream `_ defines the central type for -## stream processing, ``YamlStream``. It also contains definitions and -## constructor procs for stream events. -## * The parser API in `parser `_ gives you direct access to -## the YAML parser's output. -## * The presenter API in `presenter `_ gives you direct -## access to the presenter, i.e. the module that renders a YAML character -## stream. -## * The taglib API in `taglib `_ provides a data structure -## for keeping track of YAML tags that are generated by the parser or used in -## the presenter. -## * The hints API in `hints `_ provides a simple proc for -## guessing the type of a scalar value. - -import yaml / [hints, parser, presenter, annotations, - serialization, stream, taglib, tojson] - -when not defined(gcArc) or defined(gcOrc): - # YAML DOM may contain cycles and therefore will leak memory if used with - # ARC but without ORC. In that case it won't be available. - import yaml/dom - export dom - -export hints, parser, presenter, annotations, - serialization, stream, taglib, tojson diff --git a/lib/yaml/yaml.nimble b/lib/yaml/yaml.nimble deleted file mode 100644 index d123545..0000000 --- a/lib/yaml/yaml.nimble +++ /dev/null @@ -1,11 +0,0 @@ -# Package - -version = "0.16.0" -author = "Felix Krause" -description = "YAML 1.2 implementation for Nim" -license = "MIT" -skipDirs = @["bench", "doc", "server", "test", "tools"] - -# Dependencies - -requires "nim >= 1.4.0" diff --git a/lib/yaml/yaml/annotations.nim b/lib/yaml/yaml/annotations.nim deleted file mode 100644 index cf3128f..0000000 --- a/lib/yaml/yaml/annotations.nim +++ /dev/null @@ -1,84 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016-2020 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ======================= -## Module yaml/annotations -## ======================= -## -## This module provides annotations for object fields that customize -## (de)serialization behavior of those fields. - -template defaultVal*(value : typed) {.pragma.} - ## This annotation can be put on an object field. During deserialization, - ## if no value for this field is given, the ``value`` parameter of this - ## annotation is used as value. - ## - ## Example usage: - ## - ## .. code-block:: - ## type MyObject = object - ## a {.defaultVal: "foo".}: string - ## c {.defaultVal: (1,2).}: tuple[x, y: int] - -template sparse*() {.pragma.} - ## This annotation can be put on an object type. During deserialization, - ## the input may omit any field that has an ``Option[T]`` type (for any - ## concrete ``T``) and that field will be treated as if it had the annotation - ## ``{.defaultVal: none(T).}``. Fields of ``none(T)`` value are omitted - ## during serialization. - ## - ## Example usage: - ## - ## .. code-block:: - ## type MyObject {.sparse.} = object - ## a: Option[string] - ## b: Option[int] - -template transient*() {.pragma.} - ## This annotation can be put on an object field. Any object field - ## carrying this annotation will not be serialized to YAML and cannot be given - ## a value when deserializing. Giving a value for this field during - ## deserialization is an error. - ## - ## Example usage: - ## - ## .. code-block:: - ## type MyObject = object - ## a {.transient.}, b: string - ## c {.transient.}: int - -template ignore*(keys : openarray[string]) {.pragma.} - ## This annotation can be put on an object type. All keys with the given - ## names in the input YAML mapping will be ignored when deserializing a value - ## of this type. This can be used to ignore parts of the YAML structure. - ## - ## You may use it with an empty list (``{.ignore: [].}``) to ignore *all* - ## unknown keys. - ## - ## Example usage: - ## - ## .. code-block:: - ## type MyObject {.ignore: ["c"].} = object - ## a, b: string - -template implicit*() {.pragma.} - ## This annotation declares a variant object type as implicit. - ## This requires the type to consist of nothing but a case expression and each - ## branch of the case expression containing exactly one field - with the - ## exception that one branch may contain zero fields. - ## - ## Example usage: - ## - ## .. code-block:: - ## ContainerKind = enum - ## ckString, ckInt - ## - ## type MyObject {.implicit.} = object - ## case kind: ContainerKind - ## of ckString: - ## strVal: string - ## of ckInt: - ## intVal: int diff --git a/lib/yaml/yaml/data.nim b/lib/yaml/yaml/data.nim deleted file mode 100644 index e1843b5..0000000 --- a/lib/yaml/yaml/data.nim +++ /dev/null @@ -1,274 +0,0 @@ -import hashes -import private/escaping - -type - Anchor* = distinct string ## \ - ## An ``Anchor`` identifies an anchor in the current document. - ## It is not necessarily unique and references to an anchor must be - ## resolved immediately on occurrence. - ## - ## Anchor provides the operator `$` for converting to string, `==` for - ## comparison, and `hash` for usage in a hashmap. - - Tag* = distinct string ## \ - ## A ``Tag`` contains an URI, like for example ``"tag:yaml.org,2002:str"``. - - ScalarStyle* = enum - ## Original style of the scalar (for input), - ## or desired style of the scalar (for output). - ssAny, ssPlain, ssSingleQuoted, ssDoubleQuoted, ssLiteral, ssFolded - - CollectionStyle* = enum - csAny, csBlock, csFlow, csPair - - EventKind* = enum - ## Kinds of YAML events that may occur in an ``YamlStream``. Event kinds - ## are discussed in `YamlStreamEvent <#YamlStreamEvent>`_. - yamlStartStream, yamlEndStream, - yamlStartDoc, yamlEndDoc, yamlStartMap, yamlEndMap, - yamlStartSeq, yamlEndSeq, yamlScalar, yamlAlias - - Event* = object - ## An element from a `YamlStream <#YamlStream>`_. Events that start an - ## object (``yamlStartMap``, ``yamlStartSeq``, ``yamlScalar``) have - ## an optional anchor and a tag associated with them. The anchor will be - ## set to ``yAnchorNone`` if it doesn't exist. - ## - ## A missing tag in the YAML character stream generates - ## the non-specific tags ``?`` or ``!`` according to the YAML - ## specification. These are by convention mapped to the ``TagId`` s - ## ``yTagQuestionMark`` and ``yTagExclamationMark`` respectively. - ## Mapping is done by a `TagLibrary <#TagLibrary>`_. - ## - ## ``startPos`` and ``endPos`` are only relevant for events from an input - ## stream - they are generally ignored if used with events that generate - ## output. - startPos*, endPos*: Mark - case kind*: EventKind - of yamlStartStream, yamlEndStream: discard - of yamlStartMap: - mapProperties*: Properties - mapStyle*: CollectionStyle - of yamlStartSeq: - seqProperties*: Properties - seqStyle*: CollectionStyle - of yamlScalar: - scalarProperties*: Properties - scalarStyle* : ScalarStyle - scalarContent*: string - of yamlStartDoc: - explicitDirectivesEnd*: bool - version*: string - handles*: seq[tuple[handle, uriPrefix: string]] - of yamlEndDoc: - explicitDocumentEnd*: bool - of yamlEndMap, yamlEndSeq: discard - of yamlAlias: - aliasTarget* : Anchor - - Mark* = tuple[line, column: Positive] - - Properties* = tuple[anchor: Anchor, tag: Tag] - -const - yamlTagRepositoryPrefix* = "tag:yaml.org,2002:" - nimyamlTagRepositoryPrefix* = "tag:nimyaml.org,2016:" - -proc defineTag*(uri: string): Tag = - ## defines a tag. Use this to optimize away copies of globally defined - ## Tags. - result = uri.Tag - #shallow(result.string) # doesn't work at compile-time - -proc defineCoreTag*(name: string): Tag = - ## defines a tag in YAML's core namespace, ``tag:yaml.org,2002:`` - result = defineTag(yamlTagRepositoryPrefix & name) - -const - yAnchorNone*: Anchor = "".Anchor ## \ - ## yielded when no anchor was defined for a YAML node - - defaultMark: Mark = (1.Positive, 1.Positive) ## \ - ## used for events that are not generated from input. - - yTagExclamationMark*: Tag = defineTag("!") - yTagQuestionMark* : Tag = defineTag("?") - - # failsafe schema - - yTagString* = defineCoreTag("str") - yTagSequence* = defineCoreTag("seq") - yTagMapping* = defineCoreTag("map") - - # json & core schema - - yTagNull* = defineCoreTag("null") - yTagBoolean* = defineCoreTag("bool") - yTagInteger* = defineCoreTag("int") - yTagFloat* = defineCoreTag("float") - - # other language-independent YAML types (from http://yaml.org/type/ ) - - yTagOrderedMap* = defineCoreTag("omap") - yTagPairs* = defineCoreTag("pairs") - yTagSet* = defineCoreTag("set") - yTagBinary* = defineCoreTag("binary") - yTagMerge* = defineCoreTag("merge") - yTagTimestamp* = defineCoreTag("timestamp") - yTagValue* = defineCoreTag("value") - yTagYaml* = defineCoreTag("yaml") - - # NimYAML specific tags - - yTagNimField* = defineTag(nimyamlTagRepositoryPrefix & "field") - -proc properties*(event: Event): Properties = - ## returns the tag of the given event - case event.kind - of yamlStartMap: result = event.mapProperties - of yamlStartSeq: result = event.seqProperties - of yamlScalar: result = event.scalarProperties - else: raise newException(FieldDefect, "Event " & $event.kind & " has no properties") - -proc collectionStyle*(event: Event): CollectionStyle = - ## returns the style of the given collection start event - case event.kind - of yamlStartMap: result = event.mapStyle - of yamlStartSeq: result = event.seqStyle - else: raise (ref FieldDefect)(msg: "Event " & $event.kind & " has no collectionStyle") - -proc startStreamEvent*(): Event = - return Event(startPos: defaultMark, endPos: defaultMark, kind: yamlStartStream) - -proc endStreamEvent*(): Event = - return Event(startPos: defaultMark, endPos: defaultMark, kind: yamlEndStream) - -proc startDocEvent*(explicit: bool = false, version: string = "", - handles: seq[tuple[handle, uriPrefix: string]] = @[], - startPos, endPos: Mark = defaultMark): Event - {.inline, raises: [].} = - ## creates a new event that marks the start of a YAML document - result = Event(startPos: startPos, endPos: endPos, - kind: yamlStartDoc, version: version, handles: handles, - explicitDirectivesEnd: explicit) - -proc endDocEvent*(explicit: bool = false, startPos, endPos: Mark = defaultMark): Event - {.inline, raises: [].} = - ## creates a new event that marks the end of a YAML document - result = Event(startPos: startPos, endPos: endPos, - kind: yamlEndDoc, explicitDocumentEnd: explicit) - -proc startMapEvent*(style: CollectionStyle, props: Properties, - startPos, endPos: Mark = defaultMark): Event {.inline, raises: [].} = - ## creates a new event that marks the start of a YAML mapping - result = Event(startPos: startPos, endPos: endPos, - kind: yamlStartMap, mapProperties: props, - mapStyle: style) - -proc startMapEvent*(style: CollectionStyle = csAny, - tag: Tag = yTagQuestionMark, - anchor: Anchor = yAnchorNone, - startPos, endPos: Mark = defaultMark): Event {.inline.} = - return startMapEvent(style, (anchor, tag), startPos, endPos) - -proc endMapEvent*(startPos, endPos: Mark = defaultMark): Event {.inline, raises: [].} = - ## creates a new event that marks the end of a YAML mapping - result = Event(startPos: startPos, endPos: endPos, kind: yamlEndMap) - -proc startSeqEvent*(style: CollectionStyle, - props: Properties, - startPos, endPos: Mark = defaultMark): Event {.inline, raises: [].} = - ## creates a new event that marks the beginning of a YAML sequence - result = Event(startPos: startPos, endPos: endPos, - kind: yamlStartSeq, seqProperties: props, - seqStyle: style) - -proc startSeqEvent*(style: CollectionStyle = csAny, - tag: Tag = yTagQuestionMark, - anchor: Anchor = yAnchorNone, - startPos, endPos: Mark = defaultMark): Event {.inline.} = - return startSeqEvent(style, (anchor, tag), startPos, endPos) - -proc endSeqEvent*(startPos, endPos: Mark = defaultMark): Event {.inline, raises: [].} = - ## creates a new event that marks the end of a YAML sequence - result = Event(startPos: startPos, endPos: endPos, kind: yamlEndSeq) - -proc scalarEvent*(content: string, props: Properties, - style: ScalarStyle = ssAny, - startPos, endPos: Mark = defaultMark): Event {.inline, raises: [].} = - ## creates a new event that represents a YAML scalar - result = Event(startPos: startPos, endPos: endPos, - kind: yamlScalar, scalarProperties: props, - scalarContent: content, scalarStyle: style) - -proc scalarEvent*(content: string = "", tag: Tag = yTagQuestionMark, - anchor: Anchor = yAnchorNone, - style: ScalarStyle = ssAny, - startPos, endPos: Mark = defaultMark): Event {.inline.} = - return scalarEvent(content, (anchor, tag), style, startPos, endPos) - -proc aliasEvent*(target: Anchor, startPos, endPos: Mark = defaultMark): Event {.inline, raises: [].} = - ## creates a new event that represents a YAML alias - result = Event(startPos: startPos, endPos: endPos, kind: yamlAlias, aliasTarget: target) - -proc `==`*(left, right: Anchor): bool {.borrow.} -proc `$`*(id: Anchor): string {.borrow.} -proc hash*(id: Anchor): Hash {.borrow.} - -proc `==`*(left, right: Tag): bool {.borrow.} -proc `$`*(tag: Tag): string {.borrow.} -proc hash*(tag: Tag): Hash {.borrow.} - -proc `==`*(left: Event, right: Event): bool {.raises: [].} = - ## compares all existing fields of the given items - if left.kind != right.kind: return false - case left.kind - of yamlStartStream, yamlEndStream, yamlStartDoc, yamlEndDoc, yamlEndMap, yamlEndSeq: - result = true - of yamlStartMap: - result = left.mapProperties == right.mapProperties - of yamlStartSeq: - result = left.seqProperties == right.seqProperties - of yamlScalar: - result = left.scalarProperties == right.scalarProperties and - left.scalarContent == right.scalarContent - of yamlAlias: result = left.aliasTarget == right.aliasTarget - -proc renderAttrs*(props: Properties, isPlain: bool = true): string = - result = "" - if props.anchor != yAnchorNone: result &= " &" & $props.anchor - case props.tag - of yTagQuestionMark: discard - of yTagExclamationMark: - if isPlain: result &= " " - else: - result &= " <" & $props.tag & ">" - -proc `$`*(event: Event): string {.raises: [].} = - ## outputs a human-readable string describing the given event. - ## This string is compatible to the format used in the yaml test suite. - case event.kind - of yamlStartStream: result = "+STR" - of yamlEndStream: result = "-STR" - of yamlEndMap: result = "-MAP" - of yamlEndSeq: result = "-SEQ" - of yamlStartDoc: - result = "+DOC" - if event.explicitDirectivesEnd: result &= " ---" - of yamlEndDoc: - result = "-DOC" - if event.explicitDocumentEnd: result &= " ..." - of yamlStartMap: result = "+MAP" & renderAttrs(event.mapProperties) - of yamlStartSeq: result = "+SEQ" & renderAttrs(event.seqProperties) - of yamlScalar: - result = "=VAL" & renderAttrs(event.scalarProperties, - event.scalarStyle == ssPlain or - event.scalarStyle == ssAny) - case event.scalarStyle - of ssPlain, ssAny: result &= " :" - of ssSingleQuoted: result &= " \'" - of ssDoubleQuoted: result &= " \"" - of ssLiteral: result &= " |" - of ssFolded: result &= " >" - result &= yamlTestSuiteEscape(event.scalarContent) - of yamlAlias: result = "=ALI *" & $event.aliasTarget \ No newline at end of file diff --git a/lib/yaml/yaml/dom.nim b/lib/yaml/yaml/dom.nim deleted file mode 100644 index 942dade..0000000 --- a/lib/yaml/yaml/dom.nim +++ /dev/null @@ -1,367 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## =============== -## Module yaml/dom -## =============== -## -## This is the DOM API, which enables you to load YAML into a tree-like -## structure. It can also dump the structure back to YAML. Formally, it -## represents the *Representation Graph* as defined in the YAML specification. -## -## The main interface of this API are ``loadDom`` and ``dumpDom``. The other -## exposed procs are low-level and useful if you want to load or generate parts -## of a ``YamlStream``. -## -## The ``YamlNode`` objects in the DOM can be used similarly to the ``JsonNode`` -## objects of Nim's `json module `_. - -import tables, streams, hashes, sets, strutils -import data, stream, taglib, serialization, private/internal, parser, - presenter - -when defined(gcArc) and not defined(gcOrc): - {.error: "NimYAML's DOM API only supports ORC because ARC can't deal with cycles".} - -when defined(nimNoNil): - {.experimental: "notnil".} -type - YamlNodeKind* = enum - yScalar, yMapping, ySequence - - YamlNode* = ref YamlNodeObj not nil - ## Represents a node in a ``YamlDocument``. - - YamlNodeObj* = object - tag*: Tag - case kind*: YamlNodeKind - of yScalar: content*: string - of ySequence: elems*: seq[YamlNode] - of yMapping: fields*: TableRef[YamlNode, YamlNode] - # compiler does not like Table[YamlNode, YamlNode] - - YamlDocument* = object - ## Represents a YAML document. - root*: YamlNode - -proc hash*(o: YamlNode): Hash = - result = o.tag.hash - case o.kind - of yScalar: result = result !& o.content.hash - of yMapping: - for key, value in o.fields.pairs: - result = result !& key.hash !& value.hash - of ySequence: - for item in o.elems: - result = result !& item.hash - result = !$result - -proc eqImpl(x, y: YamlNode, alreadyVisited: var HashSet[pointer]): bool = - template compare(a, b: YamlNode) {.dirty.} = - if cast[pointer](a) != cast[pointer](b): - if cast[pointer](a) in alreadyVisited and - cast[pointer](b) in alreadyVisited: - # prevent infinite loop! - return false - elif a != b: return false - - if x.kind != y.kind or x.tag != y.tag: return false - alreadyVisited.incl(cast[pointer](x)) - alreadyVisited.incl(cast[pointer](y)) - case x.kind - of yScalar: result = x.content == y.content - of ySequence: - if x.elems.len != y.elems.len: return false - for i in 0.. " - case n.kind - of yScalar: result.add(escape(n.content)) - of ySequence: - result.add('[') - for item in n.elems: - result.add($item) - result.add(", ") - result.setLen(result.len - 1) - result[^1] = ']' - of yMapping: - result.add('{') - for key, value in n.fields.pairs: - result.add($key) - result.add(": ") - result.add($value) - result.add(", ") - result.setLen(result.len - 1) - result[^1] = '}' - -proc newYamlNode*(content: string, tag: Tag = yTagQuestionMark): YamlNode = - YamlNode(kind: yScalar, content: content, tag: tag) - -proc newYamlNode*(elems: openarray[YamlNode], tag: Tag = yTagQuestionMark): - YamlNode = - YamlNode(kind: ySequence, elems: @elems, tag: tag) - -proc newYamlNode*(fields: openarray[(YamlNode, YamlNode)], - tag: Tag = yTagQuestionMark): YamlNode = - YamlNode(kind: yMapping, fields: newTable(fields), tag: tag) - -proc initYamlDoc*(root: YamlNode): YamlDocument = - result = YamlDocument(root: root) - -proc composeNode(s: var YamlStream, c: ConstructionContext): - YamlNode {.raises: [YamlStreamError, YamlConstructionError].} = - template addAnchor(c: ConstructionContext, target: Anchor) = - if target != yAnchorNone: - yAssert(not c.refs.hasKey(target)) - c.refs[target] = (tag: yamlTag(YamlNode), p: cast[pointer](result)) - - var start: Event - shallowCopy(start, s.next()) - new(result) - try: - case start.kind - of yamlStartMap: - result = YamlNode(tag: start.mapProperties.tag, - kind: yMapping, - fields: newTable[YamlNode, YamlNode]()) - while s.peek().kind != yamlEndMap: - let - key = composeNode(s, c) - value = composeNode(s, c) - if result.fields.hasKeyOrPut(key, value): - raise newException(YamlConstructionError, - "Duplicate key: " & $key) - discard s.next() - addAnchor(c, start.mapProperties.anchor) - of yamlStartSeq: - result = YamlNode(tag: start.seqProperties.tag, - kind: ySequence, - elems: newSeq[YamlNode]()) - while s.peek().kind != yamlEndSeq: - result.elems.add(composeNode(s, c)) - addAnchor(c, start.seqProperties.anchor) - discard s.next() - of yamlScalar: - result = YamlNode(tag: start.scalarProperties.tag, - kind: yScalar) - shallowCopy(result.content, start.scalarContent) - addAnchor(c, start.scalarProperties.anchor) - of yamlAlias: - result = cast[YamlNode](c.refs[start.aliasTarget].p) - else: internalError("Malformed YamlStream") - except KeyError: - raise newException(YamlConstructionError, - "Wrong tag library: TagId missing") - -proc compose*(s: var YamlStream): YamlDocument - {.raises: [YamlStreamError, YamlConstructionError].} = - var context = newConstructionContext() - var n: Event - shallowCopy(n, s.next()) - yAssert n.kind == yamlStartDoc - result = YamlDocument(root: composeNode(s, context)) - n = s.next() - yAssert n.kind == yamlEndDoc - -proc loadDom*(s: Stream | string): YamlDocument - {.raises: [IOError, OSError, YamlParserError, YamlConstructionError].} = - var - parser = initYamlParser() - events = parser.parse(s) - e: Event - try: - e = events.next() - yAssert(e.kind == yamlStartStream) - result = compose(events) - e = events.next() - if e.kind != yamlEndStream: - raise newYamlConstructionError(events, e.startPos, "stream contains multiple documents") - except YamlStreamError: - let ex = getCurrentException() - if ex.parent of YamlParserError: - raise (ref YamlParserError)(ex.parent) - elif ex.parent of IOError: - raise (ref IOError)(ex.parent) - elif ex.parent of OSError: - raise (ref OSError)(ex.parent) - else: internalError("Unexpected exception: " & ex.parent.repr) - -proc loadMultiDom*(s: Stream | string): seq[YamlDocument] - {.raises: [IOError, OSError, YamlParserError, YamlConstructionError].} = - var - parser = initYamlParser(tagLib) - events = parser.parse(s) - e: Event - try: - e = events.next() - yAssert(e.kind == yamlStartStream) - while events.peek().kind == yamlStartDoc: - result.add(compose(events, tagLib)) - e = events.next() - yAssert(e.kind != yamlEndStream) - except YamlStreamError: - let ex = getCurrentException() - if ex.parent of YamlParserError: - raise (ref YamlParserError)(ex.parent) - elif ex.parent of IOError: - raise (ref IOError)(ex.parent) - elif ex.parent of OSError: - raise (ref OSError)(ex.parent) - else: internalError("Unexpected exception: " & ex.parent.repr) - -proc serializeNode(n: YamlNode, c: SerializationContext, a: AnchorStyle) - {.raises: [].}= - var anchor = yAnchorNone - let p = cast[pointer](n) - if a != asNone and c.refs.hasKey(p): - anchor = c.refs.getOrDefault(p).a - c.refs[p] = (anchor, true) - c.put(aliasEvent(anchor)) - return - if a != asNone: - anchor = c.nextAnchorId.Anchor - c.refs[p] = (c.nextAnchorId.Anchor, false) - nextAnchor(c.nextAnchorId, len(c.nextAnchorId) - 1) - - case n.kind - of yScalar: c.put(scalarEvent(n.content, n.tag, anchor)) - of ySequence: - c.put(startSeqEvent(csBlock, (anchor, n.tag))) - for item in n.elems: - serializeNode(item, c, a) - c.put(endSeqEvent()) - of yMapping: - c.put(startMapEvent(csBlock, (anchor, n.tag))) - for key, value in n.fields.pairs: - serializeNode(key, c, a) - serializeNode(value, c, a) - c.put(endMapEvent()) - -proc serialize*(doc: YamlDocument, a: AnchorStyle = asTidy): - YamlStream {.raises: [].} = - var - bys = newBufferYamlStream() - c = newSerializationContext(a, proc(e: Event) {.raises: [].} = - bys.put(e) - ) - c.put(startStreamEvent()) - c.put(startDocEvent()) - serializeNode(doc.root, c, a) - c.put(endDocEvent()) - c.put(endStreamEvent()) - if a == asTidy: - var ctx = initAnchorContext() - for event in bys.mitems(): - case event.kind - of yamlScalar: ctx.process(event.scalarProperties, c.refs) - of yamlStartMap: ctx.process(event.mapProperties, c.refs) - of yamlStartSeq: ctx.process(event.seqProperties, c.refs) - of yamlAlias: - event.aliasTarget = ctx.map(event.aliasTarget) - else: discard - result = bys - -proc dumpDom*(doc: YamlDocument, target: Stream, - anchorStyle: AnchorStyle = asTidy, - options: PresentationOptions = defaultPresentationOptions) - {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, - YamlStreamError].} = - ## Dump a YamlDocument as YAML character stream. - var - events = serialize(doc, - if options.style == psJson: asNone else: anchorStyle) - present(events, target, options) - -proc `[]`*(node: YamlNode, i: int): YamlNode = - ## Get the node at index *i* from a sequence. *node* must be a *ySequence*. - assert node.kind == ySequence - node.elems[i] - -proc `[]=`*(node: var YamlNode, i: int, val: YamlNode) = - ## Set the node at index *i* of a sequence. *node* must be a *ySequence*. - assert node.kind == ySequence - node.elems[i] = val - -proc `[]`*(node: YamlNode, key: YamlNode): YamlNode = - ## Get the value for a key in a mapping. *node* must be a *yMapping*. - assert node.kind == yMapping - node.fields[key] - -proc `[]=`*(node: YamlNode, key: YamlNode, value: YamlNode) = - ## Set the value for a key in a mapping. *node* must be a *yMapping*. - node.fields[key] = value - -proc `[]`*(node: YamlNode, key: string): YamlNode = - ## Get the value for a string key in a mapping. *node* must be a *yMapping*. - ## This searches for a scalar key with content *key* and either no explicit - ## tag or the explicit tag ``!!str``. - assert node.kind == yMapping - var keyNode = YamlNode(kind: yScalar, tag: yTagExclamationMark, content: key) - result = node.fields.getOrDefault(keyNode) - if isNil(result): - keyNode.tag = yTagQuestionMark - result = node.fields.getOrDefault(keyNode) - if isNil(result): - keyNode.tag = nimTag(yamlTagRepositoryPrefix & "str") - result = node.fields.getOrDefault(keyNode) - if isNil(result): - raise newException(KeyError, "No key " & escape(key) & " exists!") - -proc len*(node: YamlNode): int = - ## If *node* is a *yMapping*, return the number of key-value pairs. If *node* - ## is a *ySequence*, return the number of elements. Else, return ``0`` - case node.kind - of yMapping: result = node.fields.len - of ySequence: result = node.elems.len - of yScalar: result = 0 - -iterator items*(node: YamlNode): YamlNode = - ## Iterates over all items of a sequence. *node* must be a *ySequence*. - assert node.kind == ySequence - for item in node.elems: yield item - -iterator mitems*(node: var YamlNode): YamlNode = - ## Iterates over all items of a sequence. *node* must be a *ySequence*. - ## Values can be modified. - assert node.kind == ySequence - for item in node.elems.mitems: yield item - -iterator pairs*(node: YamlNode): tuple[key, value: YamlNode] = - ## Iterates over all key-value pairs of a mapping. *node* must be a - ## *yMapping*. - assert node.kind == yMapping - for key, value in node.fields: yield (key, value) - -iterator mpairs*(node: var YamlNode): - tuple[key: YamlNode, value: var YamlNode] = - ## Iterates over all key-value pairs of a mapping. *node* must be a - ## *yMapping*. Values can be modified. - doAssert node.kind == yMapping - for key, value in node.fields.mpairs: yield (key, value) \ No newline at end of file diff --git a/lib/yaml/yaml/hints.nim b/lib/yaml/yaml/hints.nim deleted file mode 100644 index 26b5159..0000000 --- a/lib/yaml/yaml/hints.nim +++ /dev/null @@ -1,279 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================= -## Module yaml/hints -## ================= -## -## The hints API enables you to guess the type of YAML scalars. - -import macros -import private/internal - -type - TypeHint* = enum - ## A type hint can be computed from scalar content and tells you what - ## NimYAML thinks the scalar's type is. It is generated by - ## `guessType <#guessType,string>`_ The first matching RegEx - ## in the following table will be the type hint of a scalar string. - ## - ## You can use it to determine the type of YAML scalars that have a '?' - ## non-specific tag, but using this feature is completely optional. - ## - ## ================== ========================= - ## Name RegEx - ## ================== ========================= - ## ``yTypeInteger`` ``0 | -? [1-9] [0-9]*`` - ## ``yTypeFloat`` ``-? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )?`` - ## ``yTypeFloatInf`` ``-? \. (inf | Inf | INF)`` - ## ``yTypeFloatNaN`` ``-? \. (nan | NaN | NAN)`` - ## ``yTypeBoolTrue`` ``y|Y|yes|Yes|YES|true|True|TRUE|on|On|ON`` - ## ``yTypeBoolFalse`` ``n|N|no|No|NO|false|False|FALSE|off|Off|OFF`` - ## ``yTypeNull`` ``~ | null | Null | NULL`` - ## ``yTypeTimestamp`` see `here `_. - ## ``yTypeUnknown`` ``*`` - ## ================== ========================= - yTypeInteger, yTypeFloat, yTypeFloatInf, yTypeFloatNaN, yTypeBoolTrue, - yTypeBoolFalse, yTypeNull, yTypeUnknown, yTypeTimestamp - - YamlTypeHintState = enum - ythInitial, - ythF, ythFA, ythFAL, ythFALS, ythFALSE, - ythN, ythNU, ythNUL, ythNULL, - ythNO, - ythO, ythON, - ythOF, ythOFF, - ythT, ythTR, ythTRU, ythTRUE, - ythY, ythYE, ythYES, - - ythPoint, ythPointI, ythPointIN, ythPointINF, - ythPointN, ythPointNA, ythPointNAN, - - ythLowerFA, ythLowerFAL, ythLowerFALS, - ythLowerNU, ythLowerNUL, - ythLowerOF, - ythLowerTR, ythLowerTRU, - ythLowerYE, - - ythPointLowerIN, ythPointLowerN, ythPointLowerNA, - - ythMinus, yth0, ythInt1, ythInt1Zero, ythInt2, ythInt2Zero, ythInt3, - ythInt3Zero, ythInt4, ythInt4Zero, ythInt, - ythDecimal, ythNumE, ythNumEPlusMinus, ythExponent, - - ythYearMinus, ythMonth1, ythMonth2, ythMonthMinus, ythMonthMinusNoYmd, - ythDay1, ythDay1NoYmd, ythDay2, ythDay2NoYmd, - ythAfterDayT, ythAfterDaySpace, ythHour1, ythHour2, ythHourColon, - ythMinute1, ythMinute2, ythMinuteColon, ythSecond1, ythSecond2, ythFraction, - ythAfterTimeSpace, ythAfterTimeZ, ythAfterTimePlusMinus, ythTzHour1, - ythTzHour2, ythTzHourColon, ythTzMinute1, ythTzMinute2 - -macro typeHintStateMachine(c: untyped, content: varargs[untyped]) = - yAssert content.kind == nnkArgList - result = newNimNode(nnkCaseStmt, content).add(copyNimNode(c)) - for branch in content.children: - yAssert branch.kind == nnkOfBranch - var - charBranch = newNimNode(nnkOfBranch, branch) - i = 0 - stateBranches = newNimNode(nnkCaseStmt, branch).add( - newIdentNode("typeHintState")) - while branch[i].kind != nnkStmtList: - charBranch.add(copyNimTree(branch[i])) - inc(i) - for rule in branch[i].children: - yAssert rule.kind == nnkInfix - yAssert rule[0].strVal == "=>" - var stateBranch = newNimNode(nnkOfBranch, rule) - case rule[1].kind - of nnkBracket: - for item in rule[1].children: stateBranch.add(item) - of nnkIdent: stateBranch.add(rule[1]) - else: internalError("Invalid rule kind: " & $rule[1].kind) - if rule[2].kind == nnkNilLit: - stateBranch.add(newStmtList(newNimNode(nnkDiscardStmt).add( - newEmptyNode()))) - else: - stateBranch.add(newStmtList(newAssignment( - newIdentNode("typeHintState"), copyNimTree(rule[2])))) - stateBranches.add(stateBranch) - stateBranches.add(newNimNode(nnkElse).add(newStmtList( - newNimNode(nnkReturnStmt).add(newIdentNode("yTypeUnknown"))))) - charBranch.add(newStmtList(stateBranches)) - result.add(charBranch) - result.add(newNimNode(nnkElse).add(newStmtList( - newNimNode(nnkReturnStmt).add(newIdentNode("yTypeUnknown"))))) - -template advanceTypeHint(ch: char) {.dirty.} = - typeHintStateMachine ch: - of '~': ythInitial => ythNULL - of '.': - [yth0, ythInt1Zero, ythInt1, ythInt2, ythInt3, ythInt4, ythInt] => ythDecimal - [ythInitial, ythMinus] => ythPoint - ythSecond2 => ythFraction - of '+': - ythNumE => ythNumEPlusMinus - [ythFraction, ythSecond2] => ythAfterTimePlusMinus - of '-': - ythInitial => ythMinus - ythNumE => ythNumEPlusMinus - [ythInt4, ythInt4Zero] => ythYearMinus - ythMonth1 => ythMonthMinusNoYmd - ythMonth2 => ythMonthMinus - [ythFraction, ythSecond2] => ythAfterTimePlusMinus - of '_': - [ythInt1, ythInt2, ythInt3, ythInt4] => ythInt - [ythInt, ythDecimal] => nil - of ':': - [ythHour1, ythHour2] => ythHourColon - ythMinute2 => ythMinuteColon - [ythTzHour1, ythTzHour2] => ythTzHourColon - of '0': - ythInitial => ythInt1Zero - ythMinus => yth0 - [ythNumE, ythNumEPlusMinus] => ythExponent - ythInt1 => ythInt2 - ythInt1Zero => ythInt2Zero - ythInt2 => ythInt3 - ythInt2Zero => ythInt3Zero - ythInt3 => ythInt4 - ythInt3Zero => ythInt4Zero - ythInt4 => ythInt - ythYearMinus => ythMonth1 - ythMonth1 => ythMonth2 - ythMonthMinus => ythDay1 - ythMonthMinusNoYmd => ythDay1NoYmd - ythDay1 => ythDay2 - ythDay1NoYmd => ythDay2NoYmd - [ythAfterDaySpace, ythAfterDayT] => ythHour1 - ythHour1 => ythHour2 - ythHourColon => ythMinute1 - ythMinute1 => ythMinute2 - ythMinuteColon => ythSecond1 - ythSecond1 => ythSecond2 - ythAfterTimePlusMinus => ythTzHour1 - ythTzHour1 => ythTzHour2 - ythTzHourColon => ythTzMinute1 - ythTzMinute1 => ythTzMinute2 - [ythInt, ythDecimal, ythExponent, ythFraction] => nil - of '1'..'9': - ythInitial => ythInt1 - ythInt1 => ythInt2 - ythInt1Zero => ythInt2Zero - ythInt2 => ythInt3 - ythInt2Zero => ythInt3Zero - ythInt3 => ythInt4 - ythInt3Zero => ythInt4Zero - [ythInt4, ythMinus] => ythInt - [ythNumE, ythNumEPlusMinus] => ythExponent - ythYearMinus => ythMonth1 - ythMonth1 => ythMonth2 - ythMonthMinus => ythDay1 - ythMonthMinusNoYmd => ythDay1NoYmd - ythDay1 => ythDay2 - ythDay1NoYmd => ythDay2NoYmd - [ythAfterDaySpace, ythAfterDayT] => ythHour1 - ythHour1 => ythHour2 - ythHourColon => ythMinute1 - ythMinute1 => ythMinute2 - ythMinuteColon => ythSecond1 - ythSecond1 => ythSecond2 - ythAfterTimePlusMinus => ythTzHour1 - ythTzHour1 => ythTzHour2 - ythTzHourColon => ythTzMinute1 - ythTzMinute1 => ythTzMinute2 - [ythInt, ythDecimal, ythExponent, ythFraction] => nil - of 'a': - ythF => ythLowerFA - ythPointN => ythPointNA - ythPointLowerN => ythPointLowerNA - of 'A': - ythF => ythFA - ythPointN => ythPointNA - of 'e': - [yth0, ythInt, ythDecimal] => ythNumE - ythLowerFALS => ythFALSE - ythLowerTRU => ythTRUE - ythY => ythLowerYE - of 'E': - [yth0, ythInt, ythDecimal] => ythNumE - ythFALS => ythFALSE - ythTRU => ythTRUE - ythY => ythYE - of 'f': - ythInitial => ythF - ythO => ythLowerOF - ythLowerOF => ythOFF - ythPointLowerIN => ythPointINF - of 'F': - ythInitial => ythF - ythO => ythOF - ythOF => ythOFF - ythPointIN => ythPointINF - of 'i', 'I': ythPoint => ythPointI - of 'l': - ythLowerNU => ythLowerNUL - ythLowerNUL => ythNULL - ythLowerFA => ythLowerFAL - of 'L': - ythNU => ythNUL - ythNUL => ythNULL - ythFA => ythFAL - of 'n': - ythInitial => ythN - ythO => ythON - ythPoint => ythPointLowerN - ythPointI => ythPointLowerIN - ythPointLowerNA => ythPointNAN - of 'N': - ythInitial => ythN - ythO => ythON - ythPoint => ythPointN - ythPointI => ythPointIN - ythPointNA => ythPointNAN - of 'o', 'O': - ythInitial => ythO - ythN => ythNO - of 'r': ythT => ythLowerTR - of 'R': ythT => ythTR - of 's': - ythLowerFAL => ythLowerFALS - ythLowerYE => ythYES - of 'S': - ythFAL => ythFALS - ythYE => ythYES - of 't', 'T': - ythInitial => ythT - [ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDayT - of 'u': - ythN => ythLowerNU - ythLowerTR => ythLowerTRU - of 'U': - ythN => ythNU - ythTR => ythTRU - of 'y', 'Y': ythInitial => ythY - of 'Z': [ythSecond2, ythFraction, ythAfterTimeSpace] => ythAfterTimeZ - of ' ', '\t': - [ythSecond2, ythFraction] => ythAfterTimeSpace - [ythDay1, ythDay2, ythDay1NoYmd, ythDay2NoYmd] => ythAfterDaySpace - [ythAfterTimeSpace, ythAfterDaySpace] => nil - -proc guessType*(scalar: string): TypeHint {.raises: [].} = - ## Parse scalar string according to the RegEx table documented at - ## `TypeHint <#TypeHind>`_. - var typeHintState: YamlTypeHintState = ythInitial - for c in scalar: advanceTypeHint(c) - case typeHintState - of ythNULL, ythInitial: result = yTypeNull - of ythTRUE, ythON, ythYES, ythY: result = yTypeBoolTrue - of ythFALSE, ythOFF, ythNO, ythN: result = yTypeBoolFalse - of ythInt1, ythInt2, ythInt3, ythInt4, ythInt, yth0, ythInt1Zero: result = yTypeInteger - of ythDecimal, ythExponent: result = yTypeFloat - of ythPointINF: result = yTypeFloatInf - of ythPointNAN: result = yTypeFloatNaN - of ythDay2, ythSecond2, ythFraction, ythAfterTimeZ, ythTzHour1, ythTzHour2, - ythTzMinute1, ythTzMinute2: result = yTypeTimestamp - else: result = yTypeUnknown diff --git a/lib/yaml/yaml/parser.nim b/lib/yaml/yaml/parser.nim deleted file mode 100644 index 20309b6..0000000 --- a/lib/yaml/yaml/parser.nim +++ /dev/null @@ -1,1071 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================== -## Module yaml/parser -## ================== -## -## This is the low-level parser API. A ``YamlParser`` enables you to parse any -## non-nil string or Stream object as YAML character stream. - -import tables, strutils, macros, streams -import stream, private/lex, private/internal, private/escaping, data - -when defined(nimNoNil): - {.experimental: "notnil".} - -type - YamlParser* = object - ## 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). - issueWarnings: bool - - State = proc(c: Context, e: var Event): bool {.gcSafe.} - - Level = object - state: State - indentation: int - - Context = ref object of YamlStream - handles: seq[tuple[handle, uriPrefix: string]] - issueWarnings: bool - lex: Lexer - levels: seq[Level] - keyCache: seq[Event] - keyCachePos: int - caching: bool - - headerProps, inlineProps: Properties - headerStart, inlineStart: Mark - blockIndentation: int - - YamlLoadingError* = object of ValueError - ## Base class for all exceptions that may be raised during the process - ## of loading a YAML character stream. - mark*: Mark ## position at which the error has occurred. - 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. - -const defaultProperties = (yAnchorNone, yTagQuestionMark) - -# parser states - -{.push gcSafe, .} -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 -proc mergePropsOnNewline(c: Context, e: var Event): bool -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 -proc beforeFlowItem(c: Context, e: var Event): bool -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 -proc emitCached(c: Context, e: var Event): bool -{.pop.} - -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() - -proc resolveHandle(c: Context, handle: string): string {.raises: [].} = - for item in c.handles: - if item.handle == handle: - return item.uriPrefix - return "" - -proc init[T](c: Context, p: YamlParser, source: T) {.inline.} = - c.pushLevel(atStreamStart, -2) - c.nextImpl = proc(s: YamlStream, e: var Event): bool = - let c = Context(s) - return c.levels[^1].state(c, e) - c.lastTokenContextImpl = proc(s: YamlStream, lineContent: var string): bool = - lineContent = Context(s).lex.currentLine() - return true - c.headerProps = defaultProperties - c.inlineProps = defaultProperties - c.issueWarnings = p.issueWarnings - c.lex.init(source) - c.keyCachePos = 0 - c.caching = false - -# interface - -proc init*(p: var YamlParser, issueWarnings: bool = false) = - ## Initializes a YAML parser. - p.issueWarnings = issueWarnings - -proc initYamlParser*(issueWarnings: bool = false): YamlParser = - ## Creates an initializes YAML parser and returns it - result.issueWarnings = issueWarnings - -proc parse*(p: YamlParser, s: Stream): YamlStream = - let c = new(Context) - c.init(p, s) - return c - -proc parse*(p: YamlParser, s: string): YamlStream = - let c = new(Context) - c.init(p, s) - return c - -# implementation - -proc isEmpty(props: Properties): bool = - result = props.anchor == yAnchorNone and - props.tag == yTagQuestionMark - -proc generateError(c: Context, message: string): - ref YamlParserError {.raises: [], .} = - result = (ref YamlParserError)( - msg: message, parent: nil, mark: c.lex.curStartPos, - lineContent: c.lex.currentLine()) - -proc parseTag(c: Context): Tag = - let handle = c.lex.fullLexeme() - var uri = c.resolveHandle(handle) - 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) - return Tag(uri) - -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) - -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 - -proc autoScalarTag(props: Properties, t: Token): Properties = - result = props - if t in {Token.SingleQuoted, Token.DoubleQuoted} and - props.tag == yTagQuestionMark: - result.tag = yTagExclamationMark - -proc atStreamStart(c: Context, e: var Event): bool = - c.transition(atStreamEnd) - c.pushLevel(beforeDoc, -1) - e = Event(startPos: c.lex.curStartPos, endPos: c.lex.curStartPos, kind: yamlStartStream) - c.lex.next() - resetHandles(c.handles) - 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: - e = startDocEvent(true, version, c.handles, c.lex.curStartPos, c.lex.curEndPos) - c.lex.next() - c.transition(beforeDocEnd) - c.pushLevel(afterDirectivesEnd, -1) - return true - of StreamEnd: - if seenDirectives: - raise c.generateError("Missing `---` after directives") - c.popLevel() - return false - of Indentation: - e = startDocEvent(false, version, c.handles, c.lex.curStartPos, c.lex.curEndPos) - c.transition(beforeDocEnd) - c.pushLevel(beforeImplicitRoot, -1) - 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() - if version != "1.2" and c.issueWarnings: - 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) - discard registerHandle(c.handles, tagHandle, c.lex.evaluated) - 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) - -proc afterDirectivesEnd(c: Context, e: var Event): bool = - case c.lex.cur - of nodePropertyKind: - c.inlineStart = c.lex.curStartPos - c.pushLevel(beforeNodeProperties) - return false - of Indentation: - c.headerStart = c.inlineStart - c.transition(atBlockIndentation) - c.pushLevel(beforeBlockIndentation) - return false - of DocumentEnd, DirectivesEnd, StreamEnd: - e = scalarEvent("", c.inlineProps, ssPlain, c.lex.curStartPos, c.lex.curEndPos) - c.popLevel() - return true - of scalarTokenKind: - e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur), - toStyle(c.lex.cur), c.lex.curStartPos, c.lex.curEndPos) - c.popLevel() - c.lex.next() - return true - else: - 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 - c.headerStart = c.lex.curEndPos - c.updateIndentation(c.lex.recentIndentation()) - c.lex.next() - case c.lex.cur - of SeqItemInd, MapKeyInd, MapValueInd: - c.transition(afterCompactParent) - return false - of scalarTokenKind, MapStart, SeqStart: - c.transition(atBlockIndentationProps) - return false - of nodePropertyKind: - c.transition(atBlockIndentationProps) - c.pushLevel(beforeNodeProperties) - else: - raise c.generateError("Unexpected token (expected collection start): " & $c.lex.cur) - -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): - e = scalarEvent("", c.headerProps, ssPlain, - c.headerStart, c.headerStart) - c.headerProps = defaultProperties - c.popLevel() - c.popLevel() - return true - c.inlineStart = c.lex.curStartPos - c.updateIndentation(c.lex.recentIndentation()) - case c.lex.cur - of nodePropertyKind: - if isEmpty(c.headerProps): - c.transition(mergePropsOnNewline) - else: - c.transition(atBlockIndentationProps) - c.pushLevel(beforeNodeProperties) - return false - of SeqItemInd: - e = startSeqEvent(csBlock, c.headerProps, - c.headerStart, c.lex.curEndPos) - c.headerProps = defaultProperties - c.transition(inBlockSeq, c.lex.recentIndentation()) - c.pushLevel(beforeBlockIndentation) - c.pushLevel(afterCompactParent, c.lex.recentIndentation()) - c.lex.next() - return true - of MapKeyInd: - e = startMapEvent(csBlock, c.headerProps, - c.headerStart, c.lex.curEndPos) - c.headerProps = defaultProperties - c.transition(beforeBlockMapValue, c.lex.recentIndentation()) - c.pushLevel(beforeBlockIndentation) - c.pushLevel(afterCompactParent, c.lex.recentIndentation()) - c.lex.next() - return true - of Plain, SingleQuoted, DoubleQuoted: - c.updateIndentation(c.lex.recentIndentation()) - let scalarToken = c.lex.cur - 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 - e.scalarProperties = autoScalarTag(defaultProperties, scalarToken) - c.keyCache.add(move(e)) - e = startMapEvent(csBlock, props, c.headerStart, headerEnd) - c.transition(afterImplicitKey) - c.pushLevel(emitCached) - else: - e.scalarProperties = autoScalarTag(e.scalarProperties, scalarToken) - c.popLevel() - 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: - c.keyCache.add(move(e)) - e = startMapEvent(csBlock, c.headerProps, c.headerStart, headerEnd) - c.headerProps = defaultProperties - c.transition(afterImplicitKey) - c.pushLevel(emitCached) - elif not isEmpty(c.headerProps): - raise c.generateError("Alias may not have properties") - else: - c.popLevel() - return true - else: - c.transition(atBlockIndentationProps) - return false - -proc atBlockIndentationProps(c: Context, e: var Event): bool = - c.updateIndentation(c.lex.recentIndentation()) - case c.lex.cur - of MapValueInd: - c.keyCache.add(scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curEndPos)) - c.inlineProps = defaultProperties - e = startMapEvent(csBlock, c.headerProps, c.lex.curStartPos, c.lex.curEndPos) - c.headerProps = defaultProperties - c.transition(afterImplicitKey) - c.pushLevel(emitCached) - return true - of Plain, SingleQuoted, DoubleQuoted: - e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur), - toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos) - 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") - c.keyCache.add(move(e)) - e = startMapEvent(csBlock, c.headerProps, c.headerStart, headerEnd) - c.headerProps = defaultProperties - c.transition(afterImplicitKey) - c.pushLevel(emitCached) - else: - c.mergeProps(c.headerProps, e.scalarProperties) - c.popLevel() - return true - of MapStart, SeqStart: - let - startPos = c.lex.curStartPos - indent = c.lex.currentIndentation() - levelDepth = c.levels.len - c.transition(beforeFlowItemProps) - c.caching = true - while c.levels.len >= levelDepth: - c.keyCache.add(c.next()) - c.caching = false - if c.lex.cur == Token.MapValueInd: - c.pushLevel(afterImplicitKey, indent) - c.pushLevel(emitCached) - 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: - c.pushLevel(emitCached) - 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) - c.headerProps = defaultProperties - c.lex.next() - c.popLevel() - return true - of Indentation: - c.lex.next() - c.transition(atBlockIndentation) - return false - else: - raise c.generateError("Unexpected token (expected block content): " & $c.lex.cur) - -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") - c.inlineProps.tag = Tag(move(c.lex.evaluated)) - 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: - c.mergeProps(c.inlineProps, c.headerProps) - c.popLevel() - return false - of Alias: - raise c.generateError("Alias may not have node properties") - else: - c.popLevel() - return false - c.lex.next() - return false - -proc afterCompactParent(c: Context, e: var Event): bool = - c.inlineStart = c.lex.curStartPos - case c.lex.cur - of nodePropertyKind: - c.transition(afterCompactParentProps) - c.pushLevel(beforeNodeProperties) - of SeqItemInd: - e = startSeqEvent(csBlock, c.headerProps, c.headerStart, c.lex.curEndPos) - c.headerProps = defaultProperties - c.transition(inBlockSeq, c.lex.recentIndentation()) - c.pushLevel(beforeBlockIndentation) - c.pushLevel(afterCompactParent, c.lex.recentIndentation()) - c.lex.next() - return true - of MapKeyInd: - e = startMapEvent(csBlock, c.headerProps, c.headerStart, c.lex.curEndPos) - c.headerProps = defaultProperties - c.transition(beforeBlockMapValue, c.lex.recentIndentation()) - c.pushLevel(beforeBlockIndentation) - c.pushLevel(afterCompactParent, c.lex.recentIndentation) - c.lex.next() - return true - else: - c.transition(afterCompactParentProps) - return false - -proc afterCompactParentProps(c: Context, e: var Event): bool = - c.updateIndentation(c.lex.recentIndentation()) - case c.lex.cur - of nodePropertyKind: - c.pushLevel(beforeNodeProperties) - return false - of Indentation: - c.headerStart = c.inlineStart - c.transition(atBlockIndentation, c.levels[^3].indentation) - c.pushLevel(beforeBlockIndentation) - return false - of StreamEnd, DocumentEnd, DirectivesEnd: - e = scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curStartPos) - c.inlineProps = defaultProperties - c.popLevel() - return true - of MapValueInd: - c.keyCache.add(scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curStartPos)) - c.inlineProps = defaultProperties - e = startMapEvent(csBlock, defaultProperties, c.lex.curStartPos, c.lex.curStartPos) - c.transition(afterImplicitKey) - c.pushLevel(emitCached) - 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: - c.keyCache.add(move(e)) - e = startMapEvent(csBlock, defaultProperties, headerEnd, headerEnd) - c.transition(afterImplicitKey) - c.pushLevel(emitCached) - else: - c.popLevel() - return true - of scalarTokenKind: - e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur), - toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos) - c.inlineProps = defaultProperties - let headerEnd = c.lex.curStartPos - c.updateIndentation(c.lex.recentIndentation()) - c.lex.next() - if c.lex.cur == Token.MapValueInd: - if c.lex.lastScalarWasMultiline(): - raise c.generateError("Implicit mapping key may not be multiline") - c.keyCache.add(move(e)) - e = startMapEvent(csBlock, defaultProperties, headerEnd, headerEnd) - c.transition(afterImplicitKey) - c.pushLevel(emitCached) - else: - c.popLevel() - return true - of MapStart, SeqStart: - c.transition(atBlockIndentationProps) - return false - else: - raise c.generateError("Unexpected token (expected newline or flow item start: " & $c.lex.cur) - -proc afterBlockParent(c: Context, e: var Event): bool = - c.inlineStart = c.lex.curStartPos - case c.lex.cur - of nodePropertyKind: - c.transition(afterBlockParentProps) - c.pushLevel(beforeNodeProperties) - of SeqItemInd, MapKeyInd: - raise c.generateError("Compact notation not allowed after implicit key") - else: - c.transition(afterBlockParentProps) - return false - -proc afterBlockParentProps(c: Context, e: var Event): bool = - c.updateIndentation(c.lex.recentIndentation()) - case c.lex.cur - of nodePropertyKind: - c.pushLevel(beforeNodeProperties) - return false - of MapValueInd: - raise c.generateError("Compact notation not allowed after implicit key") - of scalarTokenKind: - e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur), - toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos) - c.inlineProps = defaultProperties - c.lex.next() - if c.lex.cur == Token.MapValueInd: - raise c.generateError("Compact notation not allowed after implicit key") - c.popLevel() - return true - else: - c.transition(afterCompactParentProps) - return false - -proc mergePropsOnNewline(c: Context, e: var Event): bool = - c.updateIndentation(c.lex.recentIndentation()) - if c.lex.cur == Token.Indentation: - c.mergeProps(c.inlineProps, c.headerProps) - c.transition(afterCompactParentProps) - return false - -proc beforeDocEnd(c: Context, e: var Event): bool = - case c.lex.cur - of DocumentEnd: - e = endDocEvent(true, c.lex.curStartPos, c.lex.curEndPos) - c.transition(beforeDoc) - c.lex.next() - resetHandles(c.handles) - of StreamEnd: - e = endDocEvent(false, c.lex.curStartPos, c.lex.curEndPos) - c.popLevel() - of DirectivesEnd: - e = endDocEvent(false, c.lex.curStartPos, c.lex.curStartPos) - c.transition(beforeDoc) - resetHandles(c.handles) - else: - raise c.generateError("Unexpected token (expected document end): " & $c.lex.cur) - return true - -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() - c.pushLevel(beforeBlockIndentation) - c.pushLevel(afterCompactParent, c.blockIndentation) - return false - else: - if c.levels[^3].indentation == c.levels[^1].indentation: - e = endSeqEvent(c.lex.curStartPos, c.lex.curEndPos) - c.popLevel() - c.popLevel() - return true - else: - raise c.generateError("Illegal token (expected block sequence indicator): " & $c.lex.cur) - -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) - c.inlineStart = c.lex.curStartPos - case c.lex.cur - of MapKeyInd: - c.transition(beforeBlockMapValue) - c.pushLevel(beforeBlockIndentation) - c.pushLevel(afterCompactParent, c.blockIndentation) - c.lex.next() - return false - of nodePropertyKind: - c.transition(atBlockMapKeyProps) - c.pushLevel(beforeNodeProperties) - return false - of Plain, SingleQuoted, DoubleQuoted: - c.transition(atBlockMapKeyProps) - return false - of Alias: - e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos) - c.lex.next() - c.transition(afterImplicitKey) - return true - of MapValueInd: - e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curEndPos) - c.transition(beforeBlockMapValue) - return true - else: - raise c.generateError("Unexpected token (expected mapping key): " & $c.lex.cur) - -proc atBlockMapKeyProps(c: Context, e: var Event): bool = - case c.lex.cur - of nodePropertyKind: - c.pushLevel(beforeNodeProperties) - of Alias: - e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos) - of Plain, SingleQuoted, DoubleQuoted: - e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur), - toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos) - 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 - c.transition(afterImplicitKey) - return true - else: - raise c.generateError("Unexpected token (expected implicit mapping key): " & $c.lex.cur) - c.lex.next() - c.transition(afterImplicitKey) - 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() - c.transition(beforeBlockMapKey) - c.pushLevel(beforeBlockIndentation) - c.pushLevel(afterBlockParent, max(0, c.levels[^2].indentation)) - return false - -proc beforeBlockMapValue(c: Context, e: var Event): bool = - if c.blockIndentation > c.levels[^1].indentation: - raise c.generateError("Invalid indentation") - case c.lex.cur - of MapValueInd: - c.transition(beforeBlockMapKey) - c.pushLevel(beforeBlockIndentation) - c.pushLevel(afterCompactParent, c.blockIndentation) - 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) - c.transition(beforeBlockMapKey) - return true - else: - raise c.generateError("Unexpected token (expected mapping value): " & $c.lex.cur) - -proc beforeBlockIndentation(c: Context, e: var Event): bool = - proc endBlockNode(e: var Event) = - 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) - c.transition(beforeBlockMapKey) - c.pushLevel(beforeBlockIndentation) - 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") - else: - raise c.generateError("Internal error (please report this bug): unexpected state at endBlockNode") - c.popLevel() - c.popLevel() - case c.lex.cur - of Indentation: - c.blockIndentation = c.lex.currentIndentation() - if c.blockIndentation < c.levels[^1].indentation: - endBlockNode(e) - return true - else: - c.lex.next() - return false - of StreamEnd, DocumentEnd, DirectivesEnd: - c.blockIndentation = 0 - if c.levels[^1].state != beforeDocEnd: - endBlockNode(e) - return true - else: - return false - else: - raise c.generateError("Unexpected content after node in block context (expected newline): " & $c.lex.cur) - -proc beforeFlowItem(c: Context, e: var Event): bool = - c.inlineStart = c.lex.curStartPos - case c.lex.cur - of nodePropertyKind: - c.transition(beforeFlowItemProps) - c.pushLevel(beforeNodeProperties) - of Alias: - e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos) - c.lex.next() - c.popLevel() - return true - else: - c.transition(beforeFlowItemProps) - return false - -proc beforeFlowItemProps(c: Context, e: var Event): bool = - case c.lex.cur - of nodePropertyKind: - c.pushLevel(beforeNodeProperties) - of Alias: - e = aliasEvent(c.lex.shortLexeme().Anchor, c.inlineStart, c.lex.curEndPos) - c.lex.next() - c.popLevel() - of scalarTokenKind: - e = scalarEvent(c.lex.evaluated, autoScalarTag(c.inlineProps, c.lex.cur), - toStyle(c.lex.cur), c.inlineStart, c.lex.curEndPos) - c.inlineProps = defaultProperties - c.lex.next() - c.popLevel() - of MapStart: - e = startMapEvent(csFlow, c.inlineProps, c.inlineStart, c.lex.curEndPos) - c.transition(afterFlowMapSep) - c.lex.next() - of SeqStart: - e = startSeqEvent(csFlow, c.inlineProps, c.inlineStart, c.lex.curEndPos) - c.transition(afterFlowSeqSep) - c.lex.next() - of MapEnd, SeqEnd, SeqSep, MapValueInd: - e = scalarEvent("", c.inlineProps, ssPlain, c.inlineStart, c.lex.curEndPos) - c.popLevel() - else: - raise c.generateError("Unexpected token (expected flow node): " & $c.lex.cur) - c.inlineProps = defaultProperties - return true - -proc afterFlowMapKey(c: Context, e: var Event): bool = - case c.lex.cur - of MapValueInd: - c.transition(afterFlowMapValue) - c.pushLevel(beforeFlowItem) - c.lex.next() - return false - of SeqSep, MapEnd: - e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curEndPos) - c.transition(afterFlowMapValue) - return true - else: - raise c.generateError("Unexpected token (expected ':'): " & $c.lex.cur) - -proc afterFlowMapValue(c: Context, e: var Event): bool = - case c.lex.cur - of SeqSep: - c.transition(afterFlowMapSep) - c.lex.next() - return false - of MapEnd: - e = endMapEvent(c.lex.curStartPos, c.lex.curEndPos) - c.lex.next() - c.popLevel() - return true - of Plain, SingleQuoted, DoubleQuoted, MapKeyInd, Token.Anchor, Alias, MapStart, SeqStart: - raise c.generateError("Missing ','") - else: - raise c.generateError("Unexpected token (expected ',' or '}'): " & $c.lex.cur) - -proc afterFlowSeqItem(c: Context, e: var Event): bool = - case c.lex.cur - of SeqSep: - c.transition(afterFlowSeqSep) - c.lex.next() - return false - of SeqEnd: - e = endSeqEvent(c.lex.curStartPos, c.lex.curEndPos) - c.lex.next() - c.popLevel() - return true - of Plain, SingleQuoted, DoubleQuoted, MapKeyInd, Token.Anchor, Alias, MapStart, SeqStart: - raise c.generateError("Missing ','") - else: - raise c.generateError("Unexpected token (expected ',' or ']'): " & $c.lex.cur) - -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() - c.popLevel() - return true - of SeqSep: - raise c.generateError("Missing mapping entry between commas (use '?' for an empty mapping entry)") - else: discard - c.transition(afterFlowMapKey) - c.pushLevel(beforeFlowItem) - return false - -proc afterFlowSeqSep(c: Context, e: var Event): bool = - 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: - c.transition(afterFlowSeqSepProps) - c.pushLevel(beforeNodeProperties) - return false - of Plain, SingleQuoted, DoubleQuoted, MapStart, SeqStart: - c.transition(afterFlowSeqSepProps) - return false - of MapKeyInd: - c.transition(afterFlowSeqSepProps) - e = startMapEvent(csFlow, defaultProperties, c.lex.curStartPos, c.lex.curEndPos) - c.lex.next() - c.transition(afterFlowSeqItem) - c.pushLevel(beforePairValue) - c.pushLevel(beforeFlowItem) - return true - of MapValueInd: - c.transition(afterFlowSeqItem) - e = startMapEvent(csFlow, defaultProperties, c.lex.curStartPos, c.lex.curEndPos) - c.pushLevel(atEmptyPairKey) - return true - of SeqEnd: - e = endSeqEvent(c.lex.curStartPos, c.lex.curEndPos) - c.lex.next() - c.popLevel() - return true - else: - c.transition(afterFlowSeqItem) - c.pushLevel(beforeFlowItem) - return false - -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) - c.inlineProps = defaultProperties - c.lex.next() - if c.lex.cur == Token.MapValueInd: - c.pushLevel(afterImplicitPairStart) - 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) - return true - of MapStart, SeqStart: - let - startPos = c.lex.curStartPos - indent = c.levels[^1].indentation - cacheStart = c.keyCache.len - levelDepth = c.levels.len - alreadyCaching = c.caching - c.pushLevel(beforeFlowItemProps) - c.caching = true - while c.levels.len > levelDepth: - 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: - c.pushLevel(emitCached) - 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: - c.pushLevel(emitCached) - return false - else: - c.pushLevel(beforeFlowItem) - return false - -proc atEmptyPairKey(c: Context, e: var Event): bool = - c.transition(beforePairValue) - 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: - c.transition(afterPairValue) - c.pushLevel(beforeFlowItem) - c.lex.next() - return false - else: - # pair ends here without value - e = scalarEvent("", defaultProperties, ssPlain, c.lex.curStartPos, c.lex.curEndPos) - c.popLevel() - return true - -proc afterImplicitPairStart(c: Context, e: var Event): bool = - c.lex.next() - c.transition(afterPairValue) - c.pushLevel(beforeFlowItem) - return false - -proc afterPairValue(c: Context, e: var Event): bool = - e = endMapEvent(c.lex.curStartPos, c.lex.curEndPos) - c.popLevel() - return true - -proc emitCached(c: Context, e: var Event): bool = - 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 - -proc display*(p: YamlParser, event: Event): string = - ## 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 - of yamlStartStream: result = "+STR" - of yamlEndStream: result = "-STR" - of yamlEndMap: result = "-MAP" - of yamlEndSeq: result = "-SEQ" - of yamlStartDoc: - result = "+DOC" - if event.explicitDirectivesEnd: result &= " ---" - of yamlEndDoc: - result = "-DOC" - if event.explicitDocumentEnd: result &= " ..." - of yamlStartMap: - result = "+MAP" & renderAttrs(event.mapProperties, true) - of yamlStartSeq: - result = "+SEQ" & renderAttrs(event.seqProperties, true) - of yamlScalar: - 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 &= " >" - result &= yamlTestSuiteEscape(event.scalarContent) - of yamlAlias: result = "=ALI *" & $event.aliasTarget \ No newline at end of file diff --git a/lib/yaml/yaml/presenter.nim b/lib/yaml/yaml/presenter.nim deleted file mode 100644 index dcd1e5e..0000000 --- a/lib/yaml/yaml/presenter.nim +++ /dev/null @@ -1,825 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ===================== -## Module yaml/presenter -## ===================== -## -## This is the presenter API, used for generating YAML character streams. - -import streams, deques, strutils -import data, taglib, stream, private/internal, hints, parser - -type - PresentationStyle* = enum - ## Different styles for YAML character stream output. - ## - ## - ``ypsMinimal``: Single-line flow-only output which tries to - ## use as few characters as possible. - ## - ``ypsCanonical``: Canonical YAML output. Writes all tags except - ## for the non-specific tags ``?`` and ``!``, uses flow style, quotes - ## all string scalars. - ## - ``ypsDefault``: Tries to be as human-readable as possible. Uses - ## block style by default, but tries to condense mappings and - ## sequences which only contain scalar nodes into a single line using - ## flow style. - ## - ``ypsJson``: Omits the ``%YAML`` directive and the ``---`` - ## marker. Uses flow style. Flattens anchors and aliases, omits tags. - ## Output will be parseable as JSON. ``YamlStream`` to dump may only - ## contain one document. - ## - ``ypsBlockOnly``: Formats all output in block style, does not use - ## flow style at all. - psMinimal, psCanonical, psDefault, psJson, psBlockOnly - - TagStyle* = enum - ## Whether object should be serialized with explicit tags. - ## - ## - ``tsNone``: No tags will be outputted unless necessary. - ## - ``tsRootOnly``: A tag will only be outputted for the root tag and - ## where necessary. - ## - ``tsAll``: Tags will be outputted for every object. - tsNone, tsRootOnly, tsAll - - AnchorStyle* = enum - ## How ref object should be serialized. - ## - ## - ``asNone``: No anchors will be outputted. Values present at - ## multiple places in the content that should be serialized will be - ## fully serialized at every occurence. If the content is cyclic, this - ## will lead to an endless loop! - ## - ``asTidy``: Anchors will only be generated for objects that - ## actually occur more than once in the content to be serialized. - ## This is a bit slower and needs more memory than ``asAlways``. - ## - ``asAlways``: Achors will be generated for every ref object in the - ## content to be serialized, regardless of whether the object is - ## referenced again afterwards - asNone, asTidy, asAlways - - NewLineStyle* = enum - ## What kind of newline sequence is used when presenting. - ## - ## - ``nlLF``: Use a single linefeed char as newline. - ## - ``nlCRLF``: Use a sequence of carriage return and linefeed as - ## newline. - ## - ``nlOSDefault``: Use the target operation system's default newline - ## sequence (CRLF on Windows, LF everywhere else). - nlLF, nlCRLF, nlOSDefault - - OutputYamlVersion* = enum - ## Specify which YAML version number the presenter shall emit. The - ## presenter will always emit content that is valid YAML 1.1, but by - ## default will write a directive ``%YAML 1.2``. For compatibility with - ## other YAML implementations, it is possible to change this here. - ## - ## It is also possible to specify that the presenter shall not emit any - ## YAML version. The generated content is then guaranteed to be valid - ## YAML 1.1 and 1.2 (but not 1.0 or any newer YAML version). - ov1_2, ov1_1, ovNone - - PresentationOptions* = object - ## Options for generating a YAML character stream - style*: PresentationStyle - indentationStep*: int - newlines*: NewLineStyle - outputVersion*: OutputYamlVersion - - YamlPresenterJsonError* = object of ValueError - ## Exception that may be raised by the YAML presenter when it is - ## instructed to output JSON, but is unable to do so. This may occur if: - ## - ## - The given `YamlStream <#YamlStream>`_ contains a map which has any - ## non-scalar type as key. - ## - Any float scalar bears a ``NaN`` or positive/negative infinity value - - YamlPresenterOutputError* = object of ValueError - ## Exception that may be raised by the YAML presenter. This occurs if - ## writing character data to the output stream raises any exception. - ## The error that has occurred is available from ``parent``. - - DumperState = enum - dBlockExplicitMapKey, dBlockImplicitMapKey, dBlockMapValue, - dBlockInlineMap, dBlockSequenceItem, dFlowImplicitMapKey, dFlowMapValue, - dFlowExplicitMapKey, dFlowSequenceItem, dFlowMapStart, dFlowSequenceStart - - ScalarStyle = enum - sLiteral, sFolded, sPlain, sDoubleQuoted - - Context = object - target: Stream - options: PresentationOptions - handles: seq[tuple[handle, uriPrefix: string]] - levels: seq[DumperState] - -const - defaultPresentationOptions* = - PresentationOptions(style: psDefault, indentationStep: 2, - newlines: nlOSDefault) - -proc defineOptions*(style: PresentationStyle = psDefault, - indentationStep: int = 2, - newlines: NewLineStyle = nlOSDefault, - outputVersion: OutputYamlVersion = ov1_2): - PresentationOptions {.raises: [].} = - ## Define a set of options for presentation. Convenience proc that requires - ## you to only set those values that should not equal the default. - PresentationOptions(style: style, indentationStep: indentationStep, - newlines: newlines, outputVersion: outputVersion) - -proc state(c: Context): DumperState = c.levels[^1] - -proc `state=`(c: var Context, v: DumperState) = - c.levels[^1] = v - -proc searchHandle(c: Context, tag: string): - tuple[handle: string, len: int] {.raises: [].} = - ## search in the registered tag handles for one whose prefix matches the start - ## of the given tag. If multiple registered handles match, the one with the - ## longest prefix is returned. If no registered handle matches, ("", 0) is - ## returned. - result.len = 0 - for item in c.handles: - if item.uriPrefix.len > result.len: - if tag.startsWith(item.uriPrefix): - result.len = item.uriPrefix.len - result.handle = item.handle - -proc inspect(scalar: string, indentation: int, - words, lines: var seq[tuple[start, finish: int]]): - ScalarStyle {.raises: [].} = - var - inLine = false - inWord = false - multipleSpaces = true - curWord, curLine: tuple[start, finish: int] - canUseFolded = true - canUseLiteral = true - canUsePlain = scalar.len > 0 and - scalar[0] notin {'@', '`', '|', '>', '&', '*', '!', ' ', '\t'} - for i, c in scalar: - case c - of ' ': - if inWord: - if not multipleSpaces: - curWord.finish = i - 1 - inWord = false - else: - multipleSpaces = true - inWord = true - if not inLine: - inLine = true - curLine.start = i - # space at beginning of line will preserve previous and next - # linebreak. that is currently too complex to handle. - canUseFolded = false - of '\l': - canUsePlain = false # we don't use multiline plain scalars - curWord.finish = i - 1 - if curWord.finish - curWord.start + 1 > 80 - indentation: - return if canUsePlain: sPlain else: sDoubleQuoted - words.add(curWord) - inWord = false - curWord.start = i + 1 - multipleSpaces = true - if not inLine: curLine.start = i - inLine = false - curLine.finish = i - 1 - if curLine.finish - curLine.start + 1 > 80 - indentation: - canUseLiteral = false - lines.add(curLine) - else: - if c in {'{', '}', '[', ']', ',', '#', '-', ':', '?', '%', '"', '\''} or - c.ord < 32: canUsePlain = false - if not inLine: - curLine.start = i - inLine = true - if not inWord: - if not multipleSpaces: - if curWord.finish - curWord.start + 1 > 80 - indentation: - return if canUsePlain: sPlain else: sDoubleQuoted - words.add(curWord) - curWord.start = i - inWord = true - multipleSpaces = false - if inWord: - curWord.finish = scalar.len - 1 - if curWord.finish - curWord.start + 1 > 80 - indentation: - return if canUsePlain: sPlain else: sDoubleQuoted - words.add(curWord) - if inLine: - curLine.finish = scalar.len - 1 - if curLine.finish - curLine.start + 1 > 80 - indentation: - canUseLiteral = false - lines.add(curLine) - if scalar.len <= 80 - indentation: - result = if canUsePlain: sPlain else: sDoubleQuoted - elif canUseLiteral: result = sLiteral - elif canUseFolded: result = sFolded - elif canUsePlain: result = sPlain - else: result = sDoubleQuoted - -template append(target: Stream, val: string | char) = - target.write(val) - -template append(target: ptr[string], val: string | char) = - target[].add(val) - -proc writeDoubleQuoted(c: Context, scalar: string, indentation: int, - newline: string) - {.raises: [YamlPresenterOutputError].} = - var curPos = indentation - let t = c.target - try: - t.append('"') - curPos.inc() - for c in scalar: - if curPos == 79: - t.append('\\') - t.append(newline) - t.append(repeat(' ', indentation)) - curPos = indentation - if c == ' ': - t.append('\\') - curPos.inc() - case c - of '"': - t.append("\\\"") - curPos.inc(2) - of '\l': - t.append("\\n") - curPos.inc(2) - of '\t': - t.append("\\t") - curPos.inc(2) - of '\\': - t.append("\\\\") - curPos.inc(2) - else: - if ord(c) < 32: - t.append("\\x" & toHex(ord(c), 2)) - curPos.inc(4) - else: - t.append(c) - curPos.inc() - t.append('"') - except: - var e = newException(YamlPresenterOutputError, - "Error while writing to output stream") - e.parent = getCurrentException() - raise e - -proc writeDoubleQuotedJson(c: Context, scalar: string) - {.raises: [YamlPresenterOutputError].} = - let t = c.target - try: - t.append('"') - for c in scalar: - case c - of '"': t.append("\\\"") - of '\\': t.append("\\\\") - of '\l': t.append("\\n") - of '\t': t.append("\\t") - of '\f': t.append("\\f") - of '\b': t.append("\\b") - else: - if ord(c) < 32: t.append("\\u" & toHex(ord(c), 4)) else: t.append(c) - t.append('"') - except: - var e = newException(YamlPresenterOutputError, - "Error while writing to output stream") - e.parent = getCurrentException() - raise e - -proc writeLiteral(c: Context, scalar: string, indentation, indentStep: int, - lines: seq[tuple[start, finish: int]], newline: string) - {.raises: [YamlPresenterOutputError].} = - let t = c.target - try: - t.append('|') - if scalar[^1] != '\l': t.append('-') - if scalar[0] in [' ', '\t']: t.append($indentStep) - for line in lines: - t.append(newline) - t.append(repeat(' ', indentation + indentStep)) - if line.finish >= line.start: - t.append(scalar[line.start .. line.finish]) - except: - var e = newException(YamlPresenterOutputError, - "Error while writing to output stream") - e.parent = getCurrentException() - raise e - -proc writeFolded(c: Context, scalar: string, indentation, indentStep: int, - words: seq[tuple[start, finish: int]], - newline: string) - {.raises: [YamlPresenterOutputError].} = - let t = c.target - try: - t.append(">") - if scalar[^1] != '\l': t.append('-') - if scalar[0] in [' ', '\t']: t.append($indentStep) - var curPos = 80 - for word in words: - if word.start > 0 and scalar[word.start - 1] == '\l': - t.append(newline & newline) - t.append(repeat(' ', indentation + indentStep)) - curPos = indentation + indentStep - elif curPos + (word.finish - word.start) > 80: - t.append(newline) - t.append(repeat(' ', indentation + indentStep)) - curPos = indentation + indentStep - else: - t.append(' ') - curPos.inc() - t.append(scalar[word.start .. word.finish]) - curPos += word.finish - word.start + 1 - except: - var e = newException(YamlPresenterOutputError, - "Error while writing to output stream") - e.parent = getCurrentException() - raise e - -template safeWrite(c: Context, s: string or char) = - try: c.target.append(s) - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - -proc startItem(c: var Context, indentation: int, isObject: bool, - newline: string) {.raises: [YamlPresenterOutputError].} = - let t = c.target - try: - case c.state - of dBlockMapValue: - t.append(newline) - t.append(repeat(' ', indentation)) - if isObject or c.options.style == psCanonical: - t.append("? ") - c.state = dBlockExplicitMapKey - else: c.state = dBlockImplicitMapKey - of dBlockInlineMap: c.state = dBlockImplicitMapKey - of dBlockExplicitMapKey: - t.append(newline) - t.append(repeat(' ', indentation)) - t.append(": ") - c.state = dBlockMapValue - of dBlockImplicitMapKey: - t.append(": ") - c.state = dBlockMapValue - of dFlowExplicitMapKey: - if c.options.style != psMinimal: - t.append(newline) - t.append(repeat(' ', indentation)) - t.append(": ") - c.state = dFlowMapValue - of dFlowMapValue: - if (isObject and c.options.style != psMinimal) or c.options.style in [psJson, psCanonical]: - t.append(',' & newline & repeat(' ', indentation)) - if c.options.style == psJson: c.state = dFlowImplicitMapKey - else: - t.append("? ") - c.state = dFlowExplicitMapKey - elif isObject and c.options.style == psMinimal: - t.append(", ? ") - c.state = dFlowExplicitMapKey - else: - t.append(", ") - c.state = dFlowImplicitMapKey - of dFlowMapStart: - if (isObject and c.options.style != psMinimal) or c.options.style in [psJson, psCanonical]: - t.append(newline & repeat(' ', indentation)) - if c.options.style == psJson: c.state = dFlowImplicitMapKey - else: - t.append("? ") - c.state = dFlowExplicitMapKey - else: c.state = dFlowImplicitMapKey - of dFlowImplicitMapKey: - t.append(": ") - c.state = dFlowMapValue - of dBlockSequenceItem: - t.append(newline) - t.append(repeat(' ', indentation)) - t.append("- ") - of dFlowSequenceStart: - case c.options.style - of psMinimal, psDefault: discard - of psCanonical, psJson: - t.append(newline) - t.append(repeat(' ', indentation)) - of psBlockOnly: discard # can never happen - c.state = dFlowSequenceItem - of dFlowSequenceItem: - case c.options.style - of psMinimal, psDefault: t.append(", ") - of psCanonical, psJson: - t.append(',' & newline) - t.append(repeat(' ', indentation)) - of psBlockOnly: discard # can never happen - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - -proc writeTagAndAnchor(c: Context, props: Properties) {.raises: [YamlPresenterOutputError].} = - let t = c.target - try: - if props.tag notin [yTagQuestionMark, yTagExclamationMark]: - let tagUri = $props.tag - let (handle, length) = c.searchHandle(tagUri) - if length > 0: - t.append(handle) - t.append(tagUri[length..tagUri.high]) - t.append(' ') - else: - t.append("!<") - t.append(tagUri) - t.append("> ") - if props.anchor != yAnchorNone: - t.append("&") - t.append($props.anchor) - t.append(' ') - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - -proc nextItem(c: var Deque, s: var YamlStream): - Event {.raises: [YamlStreamError].} = - if c.len > 0: - try: result = c.popFirst - except IndexDefect: internalError("Unexpected IndexError") - else: - result = s.next() - -proc doPresent(c: var Context, s: var YamlStream) = - var - indentation = 0 - cached = initDeQue[Event]() - let newline = if c.options.newlines == nlLF: "\l" - elif c.options.newlines == nlCRLF: "\c\l" else: "\n" - var firstDoc = true - while true: - let item = nextItem(cached, s) - case item.kind - of yamlStartStream: discard - of yamlEndStream: break - of yamlStartDoc: - resetHandles(c.handles) - for v in item.handles: - discard registerHandle(c.handles, v.handle, v.uriPrefix) - if not firstDoc: - if c.options.style == psJson: - raise newException(YamlPresenterJsonError, - "Cannot output more than one document in JSON style") - c.safeWrite("..." & newline) - - if c.options.style != psJson: - try: - case c.options.outputVersion - of ov1_2: c.target.append("%YAML 1.2" & newline) - of ov1_1: c.target.append("%YAML 1.1" & newLine) - of ovNone: discard - for v in c.handles: - if v.handle == "!": - if v.uriPrefix != "!": - c.target.append("%TAG ! " & v.uriPrefix & newline) - elif v.handle == "!!": - if v.uriPrefix != yamlTagRepositoryPrefix: - c.target.append("%TAG !! " & v.uriPrefix & newline) - else: - c.target.append("%TAG " & v.handle & ' ' & v.uriPrefix & newline) - c.target.append("--- ") - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - of yamlScalar: - if c.levels.len == 0: - if c.options.style != psJson: c.safeWrite(newline) - else: - c.startItem(indentation, false, newline) - if c.options.style != psJson: - c.writeTagAndAnchor(item.scalarProperties) - - if c.options.style == psJson: - let hint = guessType(item.scalarContent) - let tag = item.scalarProperties.tag - if tag in [yTagQuestionMark, yTagBoolean] and - hint in {yTypeBoolTrue, yTypeBoolFalse}: - c.safeWrite(if hint == yTypeBoolTrue: "true" else: "false") - elif tag in [yTagQuestionMark, yTagNull] and - hint == yTypeNull: - c.safeWrite("null") - elif tag in [yTagQuestionMark, yTagInteger, - yTagNimInt8, yTagNimInt16, yTagNimInt32, yTagNimInt64, - yTagNimUInt8, yTagNimUInt16, yTagNimUInt32, yTagNimUInt64] and - hint == yTypeInteger: - c.safeWrite(item.scalarContent) - elif tag 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 tag in [yTagQuestionMark, yTagFloat] and - hint == yTypeFloat: - c.safeWrite(item.scalarContent) - else: c.writeDoubleQuotedJson(item.scalarContent) - elif c.options.style == psCanonical: - c.writeDoubleQuoted(item.scalarContent, - indentation + c.options.indentationStep, newline) - else: - var words, lines = newSeq[tuple[start, finish: int]]() - case item.scalarContent.inspect( - indentation + c.options.indentationStep, words, lines) - of sLiteral: c.writeLiteral(item.scalarContent, indentation, - c.options.indentationStep, lines, newline) - of sFolded: c.writeFolded(item.scalarContent, indentation, - c.options.indentationStep, words, newline) - of sPlain: c.safeWrite(item.scalarContent) - of sDoubleQuoted: c.writeDoubleQuoted(item.scalarContent, - indentation + c.options.indentationStep, newline) - of yamlAlias: - if c.options.style == psJson: - raise newException(YamlPresenterJsonError, - "Alias not allowed in JSON output") - yAssert c.levels.len > 0 - c.startItem(indentation, false, newline) - try: - c.target.append('*') - c.target.append($item.aliasTarget) - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - of yamlStartSeq: - var nextState: DumperState - case c.options.style - of psDefault: - var length = 0 - while true: - let next = s.next() - cached.addLast(next) - case next.kind - of yamlScalar: length += 2 + next.scalarContent.len - of yamlAlias: length += 6 - of yamlEndSeq: break - else: - length = high(int) - break - nextState = if length <= 60: dFlowSequenceStart else: dBlockSequenceItem - of psJson: - if c.levels.len > 0 and c.state in [dFlowMapStart, dFlowMapValue]: - raise newException(YamlPresenterJsonError, "Cannot have sequence as map key in JSON output!") - nextState = dFlowSequenceStart - of psMinimal, psCanonical: nextState = dFlowSequenceStart - of psBlockOnly: - let next = s.peek() - if next.kind == yamlEndSeq: nextState = dFlowSequenceStart - else: nextState = dBlockSequenceItem - - if c.levels.len == 0: - case nextState - of dBlockSequenceItem: - if c.options.style != psJson: - c.writeTagAndAnchor(item.seqProperties) - of dFlowSequenceStart: - c.safeWrite(newline) - if c.options.style != psJson: - c.writeTagAndAnchor(item.seqProperties) - indentation += c.options.indentationStep - else: internalError("Invalid nextState: " & $nextState) - else: - c.startItem(indentation, true, newline) - if c.options.style != psJson: - c.writeTagAndAnchor(item.seqProperties) - indentation += c.options.indentationStep - - if nextState == dFlowSequenceStart: c.safeWrite('[') - if c.levels.len > 0 and c.options.style in [psJson, psCanonical] and - c.state in [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - indentation += c.options.indentationStep - c.levels.add(nextState) - of yamlStartMap: - var nextState: DumperState - case c.options.style - of psDefault: - type MapParseState = enum - mpInitial, mpKey, mpValue, mpNeedBlock - var mps: MapParseState = mpInitial - while mps != mpNeedBlock: - case s.peek().kind - of yamlScalar, yamlAlias: - case mps - of mpInitial: mps = mpKey - of mpKey: mps = mpValue - else: mps = mpNeedBlock - of yamlEndMap: break - else: mps = mpNeedBlock - nextState = if mps == mpNeedBlock: dBlockMapValue else: dBlockInlineMap - of psMinimal: nextState = dFlowMapStart - of psCanonical: nextState = dFlowMapStart - of psJson: - if c.levels.len > 0 and c.state in [dFlowMapStart, dFlowMapValue]: - raise newException(YamlPresenterJsonError, - "Cannot have map as map key in JSON output!") - nextState = dFlowMapStart - of psBlockOnly: - let next = s.peek() - if next.kind == yamlEndMap: nextState = dFlowMapStart - else: nextState = dBlockMapValue - if c.levels.len == 0: - case nextState - of dBlockMapValue: - if c.options.style != psJson: - c.writeTagAndAnchor(item.mapProperties) - else: - if c.options.style != psJson: - c.safeWrite(newline) - c.writeTagAndAnchor(item.mapProperties) - indentation += c.options.indentationStep - of dFlowMapStart: - c.safeWrite(newline) - if c.options.style != psJson: - c.writeTagAndAnchor(item.mapProperties) - indentation += c.options.indentationStep - of dBlockInlineMap: discard - else: internalError("Invalid nextState: " & $nextState) - else: - if nextState in [dBlockMapValue, dBlockImplicitMapKey]: - c.startItem(indentation, true, newline) - if c.options.style != psJson: - c.writeTagAndAnchor(item.mapProperties) - else: - c.startItem(indentation, true, newline) - if c.options.style != psJson: - c.writeTagAndAnchor(item.mapProperties) - indentation += c.options.indentationStep - - if nextState == dFlowMapStart: c.safeWrite('{') - if c.levels.len > 0 and c.options.style in [psJson, psCanonical] and - c.state in [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockImplicitMapKey, - dBlockSequenceItem]: - indentation += c.options.indentationStep - c.levels.add(nextState) - - of yamlEndSeq: - yAssert c.levels.len > 0 - case c.levels.pop() - of dFlowSequenceItem: - case c.options.style - of psDefault, psMinimal, psBlockOnly: c.safeWrite(']') - of psJson, psCanonical: - indentation -= c.options.indentationStep - try: - c.target.append(newline) - c.target.append(repeat(' ', indentation)) - c.target.append(']') - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - if c.levels.len == 0 or c.state notin - [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - continue - of dFlowSequenceStart: - if c.levels.len > 0 and c.options.style in [psJson, psCanonical] and - c.state in [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - indentation -= c.options.indentationStep - c.safeWrite(']') - of dBlockSequenceItem: discard - else: internalError("Invalid popped level") - indentation -= c.options.indentationStep - of yamlEndMap: - yAssert c.levels.len > 0 - let level = c.levels.pop() - case level - of dFlowMapValue: - case c.options.style - of psDefault, psMinimal, psBlockOnly: c.safeWrite('}') - of psJson, psCanonical: - indentation -= c.options.indentationStep - try: - c.target.append(newline) - c.target.append(repeat(' ', indentation)) - c.target.append('}') - except: - var e = newException(YamlPresenterOutputError, "") - e.parent = getCurrentException() - raise e - if c.levels.len == 0 or c.state notin - [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - continue - of dFlowMapStart: - if c.levels.len > 0 and c.options.style in [psJson, psCanonical] and - c.state in [dBlockExplicitMapKey, dBlockMapValue, - dBlockImplicitMapKey, dBlockSequenceItem]: - indentation -= c.options.indentationStep - c.safeWrite('}') - of dBlockMapValue, dBlockInlineMap: discard - else: internalError("Invalid level: " & $level) - indentation -= c.options.indentationStep - of yamlEndDoc: - firstDoc = false - -proc present*(s: var YamlStream, target: Stream, - options: PresentationOptions = defaultPresentationOptions) - {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, - YamlStreamError].} = - ## Convert ``s`` to a YAML character stream and write it to ``target``. - var c = Context(target: target, options: options) - doPresent(c, s) - -proc present*(s: var YamlStream, - options: PresentationOptions = defaultPresentationOptions): - string {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, - YamlStreamError].} = - ## Convert ``s`` to a YAML character stream and return it as string. - - var - ss = newStringStream() - c = Context(target: ss, options: options) - doPresent(c, s) - return ss.data - -proc doTransform(c: var Context, input: Stream, - resolveToCoreYamlTags: bool) = - var parser: YamlParser - parser.init() - var events = parser.parse(input) - try: - if c.options.style == psCanonical: - var bys: YamlStream = newBufferYamlStream() - for e in events: - if resolveToCoreYamlTags: - var event = e - case event.kind - of yamlStartStream, yamlEndStream, yamlStartDoc, yamlEndDoc, yamlEndMap, yamlAlias, yamlEndSeq: - discard - of yamlStartMap: - if event.mapProperties.tag in [yTagQuestionMark, yTagExclamationMark]: - event.mapProperties.tag = yTagMapping - of yamlStartSeq: - if event.seqProperties.tag in [yTagQuestionMark, yTagExclamationMark]: - event.seqProperties.tag = yTagSequence - of yamlScalar: - if event.scalarProperties.tag == yTagQuestionMark: - case guessType(event.scalarContent) - of yTypeInteger: event.scalarProperties.tag = yTagInteger - of yTypeFloat, yTypeFloatInf, yTypeFloatNaN: - event.scalarProperties.tag = yTagFloat - of yTypeBoolTrue, yTypeBoolFalse: event.scalarProperties.tag = yTagBoolean - of yTypeNull: event.scalarProperties.tag = yTagNull - of yTypeTimestamp: event.scalarProperties.tag = yTagTimestamp - of yTypeUnknown: event.scalarProperties.tag = yTagString - elif event.scalarProperties.tag == yTagExclamationMark: - event.scalarProperties.tag = yTagString - BufferYamlStream(bys).put(event) - else: BufferYamlStream(bys).put(e) - doPresent(c, bys) - else: - doPresent(c, events) - except YamlStreamError: - var e = getCurrentException() - while e.parent of YamlStreamError: e = e.parent - if e.parent of IOError: raise (ref IOError)(e.parent) - elif e.parent of OSError: raise (ref OSError)(e.parent) - elif e.parent of YamlParserError: raise (ref YamlParserError)(e.parent) - else: internalError("Unexpected exception: " & e.parent.repr) - -proc genInput(input: Stream): Stream = input -proc genInput(input: string): Stream = newStringStream(input) - -proc transform*(input: Stream | string, output: Stream, - options: PresentationOptions = defaultPresentationOptions, - resolveToCoreYamlTags: bool = false) - {.raises: [IOError, OSError, YamlParserError, YamlPresenterJsonError, - YamlPresenterOutputError].} = - ## Parser ``input`` as YAML character stream and then dump it to ``output`` - ## while resolving non-specific tags to the ones in the YAML core tag - ## library. If ``resolveToCoreYamlTags`` is ``true``, non-specific tags will - ## be replaced by specific tags according to the YAML core schema. - var c = Context(target: output, options: options) - doTransform(c, genInput(input), resolveToCoreYamlTags) - -proc transform*(input: Stream | string, - options: PresentationOptions = defaultPresentationOptions, - resolveToCoreYamlTags: bool = false): - string {.raises: [IOError, OSError, 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. If ``resolveToCoreYamlTags`` is - ## ``true``, non-specific tags will be replaced by specific tags according to - ## the YAML core schema. - var - ss = newStringStream() - c = Context(target: ss, options: options) - doTransform(c, genInput(input), resolveToCoreYamlTags) - return ss.data \ No newline at end of file diff --git a/lib/yaml/yaml/private/escaping.nim b/lib/yaml/yaml/private/escaping.nim deleted file mode 100644 index 7b0ae8c..0000000 --- a/lib/yaml/yaml/private/escaping.nim +++ /dev/null @@ -1,10 +0,0 @@ -proc yamlTestSuiteEscape*(s: string): string = - result = "" - for c in s: - case c - of '\l': result.add("\\n") - of '\c': result.add("\\r") - of '\\': result.add("\\\\") - of '\b': result.add("\\b") - of '\t': result.add("\\t") - else: result.add(c) \ No newline at end of file diff --git a/lib/yaml/yaml/private/internal.nim b/lib/yaml/yaml/private/internal.nim deleted file mode 100644 index 4a1e230..0000000 --- a/lib/yaml/yaml/private/internal.nim +++ /dev/null @@ -1,96 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import tables -import ../data - -template internalError*(s: string) = - # Note: to get the internal stacktrace that caused the error - # compile with the `d:debug` flag. - when not defined(release): - let ii = instantiationInfo() - echo "[NimYAML] Error in file ", ii.filename, " at line ", ii.line, ":" - echo s - when not defined(JS): - try: - var exc = getCurrentException() - while not isNil(exc): - echo "… stacktrace [", exc.name, ": ", exc.msg, "]" - echo getStackTrace(exc) - exc = exc.parent - except: discard - echo "[NimYAML] Please report this bug." - quit 1 - -template yAssert*(e: typed) = - when not defined(release): - if not e: - let ii = instantiationInfo() - echo "[NimYAML] Error in file ", ii.filename, " at line ", ii.line, ":" - echo "assertion failed!" - when not defined(JS): - echo "[NimYAML] Stacktrace:" - try: - writeStackTrace() - let exc = getCurrentException() - if not isNil(exc.parent): - echo "Internal stacktrace:" - echo getStackTrace(exc.parent) - except: discard - echo "[NimYAML] Please report this bug." - quit 1 - -proc nextAnchor*(s: var string, i: int) = - if s[i] == 'z': - s[i] = 'a' - if i == 0: - s.add('a') - else: - s[i] = 'a' - nextAnchor(s, i - 1) - else: - s[i] = char(int(s[i]) + 1) - -template resetHandles*(handles: var seq[tuple[handle, uriPrefix: string]]) {.dirty.} = - handles.setLen(0) - handles.add(("!", "!")) - handles.add(("!!", yamlTagRepositoryPrefix)) - -proc registerHandle*(handles: var seq[tuple[handle, uriPrefix: string]], handle, uriPrefix: string): bool = - for i in countup(0, len(handles)-1): - if handles[i].handle == handle: - handles[i].uriPrefix = uriPrefix - return false - handles.add((handle, uriPrefix)) - return false - -type - AnchorContext* = object - nextAnchorId: string - mapping: Table[Anchor, Anchor] - -proc initAnchorContext*(): AnchorContext = - return AnchorContext(nextAnchorId: "a", mapping: initTable[Anchor, Anchor]()) - -proc process*(context: var AnchorContext, - target: var Properties, refs: Table[pointer, tuple[a: Anchor, referenced: bool]]) = - if target.anchor == yAnchorNone: return - for key, val in refs: - if val.a == target.anchor: - if not val.referenced: - target.anchor = yAnchorNone - return - break - if context.mapping.hasKey(target.anchor): - target.anchor = context.mapping.getOrDefault(target.anchor) - else: - let old = move(target.anchor) - target.anchor = context.nextAnchorId.Anchor - nextAnchor(context.nextAnchorId, len(context.nextAnchorId)-1) - context.mapping[old] = target.anchor - -proc map*(context: AnchorContext, anchor: Anchor): Anchor = - return context.mapping.getOrDefault(anchor) \ No newline at end of file diff --git a/lib/yaml/yaml/private/lex.nim b/lib/yaml/yaml/private/lex.nim deleted file mode 100644 index 2261224..0000000 --- a/lib/yaml/yaml/private/lex.nim +++ /dev/null @@ -1,1159 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2015 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -import lexbase, streams, strutils, unicode -import ../data -when defined(yamlDebug): - import terminal - export terminal - -type - Lexer* = object - cur*: Token - curStartPos*, curEndPos*: Mark - flowDepth*: int - # recently read scalar or URI, if any - evaluated*: string - # internals - indentation: int - source: BaseLexer - tokenStart: int - state, lineStartState, jsonEnablingState: State - c: char - seenMultiline: bool - # indentation of recently started set of node properties. - # necessary for implicit keys with properties. - propertyIndentation: int - - LexerError* = object of ValueError - line*, column*: int - lineContent*: string - - # temporarily missing .raises: [LexerError] - # due to https://github.com/nim-lang/Nim/issues/13905 - State = proc(lex: var Lexer): bool {.locks: 0, gcSafe, nimcall.} - - Token* {.pure.} = enum - YamlDirective, # `%YAML` - TagDirective, # `%TAG` - UnknownDirective, # any directive but `%YAML` and `%TAG` - DirectiveParam, # parameters of %YAML and unknown directives - EmptyLine, # for line folding in multiline plain scalars - DirectivesEnd, # explicit `---` - DocumentEnd, # explicit `...` - StreamEnd, # end of input - Indentation, # beginning of non-empty line - Plain, SingleQuoted, DoubleQuoted, Literal, Folded, - SeqItemInd, # block sequence item indicator `- ` - MapKeyInd, # block mapping key indicator `? ` - MapValueInd # block mapping value indicator `: ` - MapStart, MapEnd, SeqStart, SeqEnd, SeqSep # {}[], - TagHandle, # a handle of a tag, e.g. `!!` of `!!str` - Suffix, # suffix of a tag shorthand, e.g. `str` of `!!str`. - # also used for the URI of the %TAG directive - VerbatimTag, # a verbatim tag, e.g. `!` - Anchor, # anchor property of a node, e.g. `&anchor` - Alias # alias node, e.g. `*alias` - - ChompType* = enum - ctKeep, ctClip, ctStrip - - LineStartType = enum - lsDirectivesEndMarker, lsDocumentEndMarker, lsComment, - lsNewline, lsStreamEnd, lsContent - -# consts - -const - space = {' ', '\t'} - lineEnd = {'\l', '\c', EndOfFile} - spaceOrLineEnd = {' ', '\t', '\l', '\c', EndOfFile} - commentOrLineEnd = {'\l', '\c', EndOfFile, '#'} - digits = {'0'..'9'} - flowIndicators = {'[', ']', '{', '}', ','} - uriChars = {'a' .. 'z', 'A' .. 'Z', '0' .. '9', '#', ';', '/', '?', ':', - '@', '&', '-', '=', '+', '$', '_', '.', '~', '*', '\'', '(', ')'} - tagShorthandChars = {'a' .. 'z', 'A' .. 'Z', '0' .. '9', '-'} - nodePropertyKind* = {Token.TagHandle, Token.VerbatimTag, Token.Anchor} - scalarTokenKind* = {Token.Plain, Token.SingleQuoted, Token.DoubleQuoted, - Token.Literal, Token.Folded} - - UTF8NextLine = toUTF8(0x85.Rune) - UTF8NonBreakingSpace = toUTF8(0xA0.Rune) - UTF8LineSeparator = toUTF8(0x2028.Rune) - UTF8ParagraphSeparator = toUTF8(0x2029.Rune) - - UnknownIndentation* = int.low - -proc currentIndentation*(lex: Lexer): int {.locks: 0.} = - return lex.source.getColNumber(lex.source.bufpos) - 1 - -proc recentIndentation*(lex: Lexer): int {.locks: 0.} = - return lex.indentation - -# lexer source handling - -proc advance(lex: var Lexer, step: int = 1) {.inline.} = - lex.c = lex.source.buf[lex.source.bufpos] - lex.source.bufpos.inc(step) - -template lexCR(lex: var Lexer) = - try: lex.source.bufpos = lex.source.handleCR(lex.source.bufpos - 1) - except: - var e = lex.generateError("Encountered stream error: " & - getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - lex.advance() - -template lexLF(lex: var Lexer) = - try: lex.source.bufpos = lex.source.handleLF(lex.source.bufpos - 1) - except: - var e = generateError(lex, "Encountered stream error: " & - getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - lex.advance() - -template lineNumber(lex: Lexer): Positive = - lex.source.lineNumber - -template columnNumber(lex: Lexer): Positive = - lex.source.getColNumber(lex.source.bufpos) - -template currentLine(lex: Lexer): string = - lex.source.getCurrentLine(true) - -proc isPlainSafe(lex: Lexer): bool {.inline.} = - case lex.source.buf[lex.source.bufpos] - of spaceOrLineEnd: result = false - of flowIndicators: result = lex.flowDepth == 0 - else: result = true - -# lexer states - -{.push gcSafe, locks: 0.} -# `raises` cannot be pushed. -proc outsideDoc(lex: var Lexer): bool {.raises: [].} -proc yamlVersion(lex: var Lexer): bool {.raises: LexerError.} -proc tagShorthand(lex: var Lexer): bool {.raises: LexerError.} -proc tagUri(lex: var Lexer): bool {.raises: LexerError.} -proc unknownDirParams(lex: var Lexer): bool {.raises: [].} -proc expectLineEnd(lex: var Lexer): bool {.raises: LexerError.} -proc lineStart(lex: var Lexer): bool {.raises: LexerError.} -proc flowLineStart(lex: var Lexer): bool {.raises: LexerError.} -proc flowLineIndentation(lex: var Lexer): bool {.raises: LexerError.} -proc insideLine(lex: var Lexer): bool {.raises: LexerError.} -proc indentationSettingToken(lex: var Lexer): bool {.raises: LexerError.} -proc afterToken(lex: var Lexer): bool {.raises: LexerError.} -proc beforeIndentationSettingToken(lex: var Lexer): bool {.raises: LexerError.} -proc afterJsonEnablingToken(lex: var Lexer): bool {.raises: LexerError.} -proc lineIndentation(lex: var Lexer): bool {.raises: [].} -proc lineDirEnd(lex: var Lexer): bool {.raises: [].} -proc lineDocEnd(lex: var Lexer): bool {.raises: [].} -proc atSuffix(lex: var Lexer): bool {.raises: [LexerError].} -proc streamEnd(lex: var Lexer): bool {.raises: [].} -{.pop.} - -# helpers - -template debug*(message: string) = - when defined(yamlDebug): - when nimvm: - echo "yamlDebug: ", message - else: - try: styledWriteLine(stdout, fgBlue, message) - except ValueError, IOError: discard - -proc generateError(lex: Lexer, message: string): - ref LexerError {.raises: [].} = - result = newException(LexerError, message) - result.line = lex.lineNumber() - result.column = lex.columnNumber() - result.lineContent = lex.currentLine() - -proc startToken(lex: var Lexer) {.inline.} = - lex.curStartPos = (line: lex.lineNumber(), column: lex.columnNumber()) - lex.tokenStart = lex.source.bufpos - -proc endToken(lex: var Lexer) {.inline.} = - lex.curEndPos = (line: lex.lineNumber(), column: lex.columnNumber()) - -proc readNumericSubtoken(lex: var Lexer) {.inline.} = - if lex.c notin digits: - raise lex.generateError("Illegal character in YAML version string: " & escape("" & lex.c)) - while true: - lex.advance() - if lex.c notin digits: break - -proc isDirectivesEnd(lex: var Lexer): bool = - var peek = lex.source.bufpos - if lex.source.buf[peek] == '-': - peek += 1 - if lex.source.buf[peek] == '-': - peek += 1 - if lex.source.buf[peek] in spaceOrLineEnd: - lex.source.bufpos = peek - lex.advance() - return true - return false - -proc isDocumentEnd(lex: var Lexer): bool = - var peek = lex.source.bufpos - if lex.source.buf[peek] == '.': - peek += 1 - if lex.source.buf[peek] == '.': - peek += 1 - if lex.source.buf[peek] in spaceOrLineEnd: - lex.source.bufpos = peek - lex.advance() - return true - return false - -proc readHexSequence(lex: var Lexer, len: int) = - var charPos = 0 - for i in countup(0, len-1): - lex.advance() - let digitPosition = len - i - 1 - case lex.c - of lineEnd: - raise lex.generateError("Unfinished unicode escape sequence") - of '0'..'9': - charPos = charPos or (int(lex.c) - 0x30) shl (digitPosition * 4) - of 'A' .. 'F': - charPos = charPos or (int(lex.c) - 0x37) shl (digitPosition * 4) - of 'a' .. 'f': - charPos = charPos or (int(lex.c) - 0x57) shl (digitPosition * 4) - else: - raise lex.generateError("Invalid character in hex escape sequence: " & - escape("" & lex.c)) - lex.evaluated.add(toUTF8(Rune(charPos))) - -proc readURI(lex: var Lexer) = - lex.evaluated.setLen(0) - let endWithSpace = lex.c != '<' - let restricted = lex.flowDepth > 0 - var literalStart: int - if endWithSpace: - if not restricted and lex.c in {'[', ']', ','}: - raise lex.generateError("Flow indicator cannot start tag prefix") - literalStart = lex.source.bufpos - 1 - else: - literalStart = lex.source.bufpos - lex.advance() - while true: - case lex.c - of spaceOrLineEnd: - if endWithSpace: - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - break - raise lex.generateError("Unclosed verbatim tag") - of '%': - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - lex.readHexSequence(2) - literalStart = lex.source.bufpos - of uriChars: discard - of '[', ']', ',': - if restricted: - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - break - of '!': - if restricted: - raise lex.generateError("Illegal '!' in tag suffix") - of '>': - if endWithSpace: - raise lex.generateError("Illegal character in URI: `>`") - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - lex.advance() - break - else: - raise lex.generateError("Illegal character in URI: " & escape("" & lex.c)) - lex.advance() - -proc endLine(lex: var Lexer) = - while true: - case lex.c - of '\l': - lex.lexLF() - lex.state = lex.lineStartState - break - of '\c': - lex.lexCR() - lex.state = lex.lineStartState - break - of EndOfFile: - lex.state = streamEnd - break - of '#': - while true: - lex.advance() - if lex.c in lineEnd: break - else: discard - -proc startLine(lex: var Lexer): LineStartType = - case lex.c - of '-': - return if lex.isDirectivesEnd(): lsDirectivesEndMarker - else: lsContent - of '.': - return if lex.isDocumentEnd(): lsDocumentEndMarker - else: lsContent - else: - while lex.c == ' ': lex.advance() - return case lex.c - of '#': lsComment - of '\l', '\c': lsNewline - of EndOfFile: lsStreamEnd - else: lsContent - -proc readPlainScalar(lex: var Lexer) = - lex.evaluated.setLen(0) - let afterNewlineState = if lex.flowDepth == 0: lineIndentation - else: flowLineIndentation - var lineStartPos: int - lex.seenMultiline = false - lex.startToken() - if lex.propertyIndentation != -1: - lex.indentation = lex.propertyIndentation - lex.propertyIndentation = -1 - lex.cur = Token.Plain - block multilineLoop: - while true: - lineStartPos = lex.source.bufpos - 1 - block inlineLoop: - while true: - lex.advance() - case lex.c - of space: - lex.endToken() - let spaceStart = lex.source.bufpos - 2 - block spaceLoop: - while true: - lex.advance() - case lex.c - of '\l', '\c': - lex.evaluated.add(lex.source.buf[lineStartPos..spaceStart]) - break inlineLoop - of EndOfFile: - lex.evaluated.add(lex.source.buf[lineStartPos..spaceStart]) - lex.state = streamEnd - break multilineLoop - of '#': - lex.evaluated.add(lex.source.buf[lineStartPos..spaceStart]) - lex.state = expectLineEnd - break multilineLoop - of ':': - if not lex.isPlainSafe(): - lex.evaluated.add(lex.source.buf[lineStartPos..spaceStart]) - lex.state = insideLine - break multilineLoop - break spaceLoop - of flowIndicators: - if lex.flowDepth > 0: - lex.evaluated.add(lex.source.buf[lineStartPos..spaceStart]) - lex.state = insideLine - break multilineLoop - break spaceLoop - of space: discard - else: break spaceLoop - of ':': - if not lex.isPlainSafe(): - lex.evaluated.add(lex.source.buf[lineStartPos..lex.source.bufpos - 2]) - lex.endToken() - lex.state = insideLine - break multilineLoop - of flowIndicators: - if lex.flowDepth > 0: - lex.evaluated.add(lex.source.buf[lineStartPos..lex.source.bufpos - 2]) - lex.endToken() - lex.state = insideLine - break multilineLoop - of '\l', '\c': - lex.evaluated.add(lex.source.buf[lineStartPos..lex.source.bufpos - 2]) - lex.endToken() - break inlineLoop - of EndOfFile: - lex.evaluated.add(lex.source.buf[lineStartPos..lex.source.bufpos - 2]) - if lex.currentIndentation() > 0: - lex.endToken() - lex.state = streamEnd - break multilineLoop - else: discard - lex.endLine() - var newlines = 1 - block newlineLoop: - while true: - case lex.startLine() - of lsContent: - if lex.currentIndentation() <= lex.indentation: - lex.state = afterNewlineState - break multilineLoop - if lex.c == '\t': - while lex.c in space: lex.advance() - case lex.c: - of '#': - lex.endLine() - lex.state = lineStart - break multilineLoop - of '\l', '\c': - lex.endLine() - newlines += 1 - continue - else: discard - break newlineLoop - of lsDirectivesEndMarker: - lex.state = lineDirEnd - break multilineLoop - of lsDocumentEndMarker: - lex.state = lineDocEnd - break multilineLoop - of lsStreamEnd: - break multilineLoop - of lsComment: - lex.endLine() - lex.state = lineStart - break multilineLoop - of lsNewline: lex.endLine() - newlines += 1 - while lex.c in space: lex.advance() - if (lex.c == ':' and not lex.isPlainSafe()) or - lex.c == '#' or (lex.c in flowIndicators and - lex.flowDepth > 0): - lex.state = afterNewlineState - break multilineLoop - lex.seenMultiline = true - if newlines == 1: lex.evaluated.add(' ') - else: - for i in countup(2, newlines): lex.evaluated.add('\l') - -proc streamEndAfterBlock(lex: var Lexer) = - if lex.currentIndentation() != 0: - lex.endToken() - lex.curEndPos.column -= 1 - -proc dirEndFollows(lex: Lexer): bool = - return lex.c == '-' and lex.source.buf[lex.source.bufpos] == '-' and - lex.source.buf[lex.source.bufpos+1] == '-' - -proc docEndFollows(lex: Lexer): bool = - return lex.c == '.' and lex.source.buf[lex.source.bufpos] == '.' and - lex.source.buf[lex.source.bufpos+1] == '.' - -proc readBlockScalar(lex: var Lexer) = - var - chomp = ctClip - indent = 0 - separationLines = 0 - contentStart: int - lex.startToken() - lex.cur = if lex.c == '>': Token.Folded else: Token.Literal - lex.evaluated.setLen(0) - - # header - while true: - lex.advance() - case lex.c - of '+': - if chomp != ctClip: - raise lex.generateError("Multiple chomping indicators") - chomp = ctKeep - of '-': - if chomp != ctClip: - raise lex.generateError("Multiple chomping indicators") - chomp = ctStrip - of '1' .. '9': - if indent != 0: - raise lex.generateError("Multiple indentation indicators") - indent = max(0, lex.indentation) + int(lex.c) - int('0') - of ' ': - while true: - lex.advance() - if lex.c != ' ': break - if lex.c notin commentOrLineEnd: - raise lex.generateError("Illegal character after block scalar header: " & - escape("" & lex.c)) - break - of lineEnd: break - else: - raise lex.generateError("Illegal character in block scalar header: " & - escape("" & lex.c)) - lex.endLine() - - block body: - # determining indentation and leading empty lines - var - maxLeadingSpaces = 0 - moreIndented = false - while true: - if indent == 0: - while lex.c == ' ': lex.advance() - else: - maxLeadingSpaces = lex.currentIndentation() + indent - while lex.c == ' ' and lex.currentIndentation() < maxLeadingSpaces: - lex.advance() - case lex.c - of '\l', '\c': - lex.endToken() - maxLeadingSpaces = max(maxLeadingSpaces, lex.currentIndentation()) - lex.endLine() - separationLines += 1 - of EndOfFile: - lex.state = streamEnd - lex.streamEndAfterBlock() - break body - else: - if indent == 0: - indent = lex.currentIndentation() - if indent <= lex.indentation or - (indent == 0 and (lex.dirEndFollows() or lex.docEndFollows())): - lex.state = lineIndentation - break body - elif indent < maxLeadingSpaces: - raise lex.generateError("Leading all-spaces line contains too many spaces") - elif lex.currentIndentation() < indent: break body - if lex.cur == Token.Folded and lex.c in space: - moreIndented = true - break - for i in countup(0, separationLines - 1): - lex.evaluated.add('\l') - separationLines = if moreIndented: 1 else: 0 - - block content: - while true: - contentStart = lex.source.bufpos - 1 - while lex.c notin lineEnd: lex.advance() - lex.evaluated.add(lex.source.buf[contentStart .. lex.source.bufpos - 2]) - if lex.c == EndOfFile: - lex.state = streamEnd - lex.streamEndAfterBlock() - break body - separationLines += 1 - lex.endToken() - lex.endLine() - - let oldMoreIndented = moreIndented - # empty lines and indentation of next line - moreIndented = false - while true: - while lex.c == ' ' and lex.currentIndentation() < indent: - lex.advance() - case lex.c - of '\l', '\c': - lex.endToken() - separationLines += 1 - lex.endLine() - of EndOfFile: - lex.state = streamEnd - lex.streamEndAfterBlock() - break body - else: - if lex.currentIndentation() < indent or - (indent == 0 and lex.dirEndFollows() or lex.docEndFollows()): - break content - if lex.cur == Token.Folded and lex.c in space: - moreIndented = true - if not oldMoreIndented: - separationLines += 1 - break - - # line folding - if lex.cur == Token.Literal: - for i in countup(0, separationLines - 1): - lex.evaluated.add('\l') - elif separationLines == 1: - lex.evaluated.add(' ') - else: - for i in countup(0, separationLines - 2): - lex.evaluated.add('\l') - separationLines = if moreIndented: 1 else: 0 - - let markerFollows = lex.currentIndentation() == 0 and - (lex.dirEndFollows() or lex.docEndFollows()) - if lex.currentIndentation() > lex.indentation and not markerFollows: - if lex.c == '#': - lex.state = expectLineEnd - else: - raise lex.generateError("This line #" & $lex.curStartPos.line & " at " & escape("" & lex.c) & " is less indented than necessary") - elif lex.currentIndentation() == 0: - lex.state = lineStart - else: - lex.state = lineIndentation - - lex.endToken() - - case chomp - of ctStrip: discard - of ctClip: - if len(lex.evaluated) > 0: - lex.evaluated.add('\l') - of ctKeep: - for i in countup(0, separationLines - 1): - lex.evaluated.add('\l') - -proc processQuotedWhitespace(lex: var Lexer, initial: int) = - var newlines = initial - let firstSpace = lex.source.bufpos - 1 - while true: - case lex.c - of ' ', '\t': discard - of '\l': - lex.lexLF() - break - of '\c': - lex.lexCR() - break - else: - lex.evaluated.add(lex.source.buf[firstSpace..lex.source.bufpos - 2]) - return - lex.advance() - lex.seenMultiline = true - while true: - case lex.startLine() - of lsContent, lsComment: - while lex.c in space: lex.advance() - if lex.c in {'\l', '\c'}: - lex.endLine() - else: break - of lsDirectivesEndMarker: - raise lex.generateError("Illegal `---` within quoted scalar") - of lsDocumentEndMarker: - raise lex.generateError("Illegal `...` within quoted scalar") - of lsNewline: lex.endLine() - of lsStreamEnd: - raise lex.generateError("Unclosed quoted string") - newlines += 1 - if newlines == 0: discard - elif newlines == 1: lex.evaluated.add(' ') - else: - for i in countup(2, newlines): lex.evaluated.add('\l') - -proc readSingleQuotedScalar(lex: var Lexer) = - lex.seenMultiline = false - lex.startToken() - lex.evaluated.setLen(0) - if lex.propertyIndentation != -1: - lex.indentation = lex.propertyIndentation - lex.propertyIndentation = -1 - var literalStart = lex.source.bufpos - lex.advance() - while true: - case lex.c - of EndOfFile: - raise lex.generateError("Unclosed quoted string") - of '\'': - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - lex.advance() - if lex.c == '\'': - lex.evaluated.add('\'') - literalStart = lex.source.bufpos - lex.advance() - else: break - of ' ', '\t', '\l', '\c': - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - lex.processQuotedWhitespace(1) - literalStart = lex.source.bufpos - 1 - else: - lex.advance() - lex.endToken() - lex.cur = Token.SingleQuoted - -proc readDoubleQuotedScalar(lex: var Lexer) = - lex.seenMultiline = false - lex.startToken() - lex.evaluated.setLen(0) - if lex.propertyIndentation != -1: - lex.indentation = lex.propertyIndentation - lex.propertyIndentation = -1 - var literalStart = lex.source.bufpos - lex.advance() - while true: - case lex.c - of EndOfFile: - raise lex.generateError("Unclosed quoted string") - of '\\': - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - lex.advance() - literalStart = lex.source.bufpos - case lex.c - of '0': lex.evaluated.add('\0') - of 'a': lex.evaluated.add('\a') - of 'b': lex.evaluated.add('\b') - of 't', '\t': lex.evaluated.add('\t') - of 'n': lex.evaluated.add('\l') - of 'v': lex.evaluated.add('\v') - of 'f': lex.evaluated.add('\f') - of 'r': lex.evaluated.add('\c') - of 'e': lex.evaluated.add('\e') - of ' ': lex.evaluated.add(' ') - of '"': lex.evaluated.add('"') - of '/': lex.evaluated.add('/') - of '\\':lex.evaluated.add('\\') - of 'N': lex.evaluated.add(UTF8NextLine) - of '_': lex.evaluated.add(UTF8NonBreakingSpace) - of 'L': lex.evaluated.add(UTF8LineSeparator) - of 'P': lex.evaluated.add(UTF8ParagraphSeparator) - of 'x': - lex.readHexSequence(2) - literalStart = lex.source.bufpos - of 'u': - lex.readHexSequence(4) - literalStart = lex.source.bufpos - of 'U': - lex.readHexSequence(8) - literalStart = lex.source.bufpos - of '\l', '\c': - lex.processQuotedWhitespace(0) - literalStart = lex.source.bufpos - 1 - continue - else: - raise lex.generateError("Illegal character in escape sequence: " & escape("" & lex.c)) - of '"': - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - break - of ' ', '\t', '\l', '\c': - lex.evaluated.add(lex.source.buf[literalStart..lex.source.bufpos - 2]) - lex.processQuotedWhitespace(1) - literalStart = lex.source.bufpos - 1 - continue - else: discard - lex.advance() - lex.advance() - lex.endToken() - lex.cur = Token.DoubleQuoted - -proc basicInit(lex: var Lexer) = - lex.state = outsideDoc - lex.flowDepth = 0 - lex.lineStartState = outsideDoc - lex.jsonEnablingState = afterToken - lex.propertyIndentation = -1 - lex.evaluated = "" - lex.advance() - -# interface - -proc lastScalarWasMultiline*(lex: Lexer): bool {.locks: 0.} = - result = lex.seenMultiline - -proc shortLexeme*(lex: Lexer): string {.locks: 0.} = - return lex.source.buf[lex.tokenStart..lex.source.bufpos-2] - -proc fullLexeme*(lex: Lexer): string {.locks: 0.} = - return lex.source.buf[lex.tokenStart - 1..lex.source.bufpos-2] - -proc currentLine*(lex: Lexer): string {.locks: 0.} = - return lex.source.getCurrentLine(false) - -proc next*(lex: var Lexer) = - while not lex.state(lex): discard - debug("lexer -> [" & $lex.curStartPos.line & "," & $lex.curStartPos.column & - "-" & $lex.curEndPos.line & "," & $lex.curEndPos.column & "] " & $lex.cur) - -proc init*(lex: var Lexer, source: Stream) {.raises: [IOError, OSError].} = - lex.source.open(source) - lex.basicInit() - -proc init*(lex: var Lexer, source: string) {.raises: [].} = - try: - lex.source.open(newStringStream(source)) - except: - discard # can never happen with StringStream - lex.basicInit() - -# states - -proc outsideDoc(lex: var Lexer): bool = - case lex.c - of '%': - lex.startToken() - while true: - lex.advance() - if lex.c in spaceOrLineEnd: break - lex.endToken() - let name = lex.shortLexeme() - case name - of "YAML": - lex.state = yamlVersion - lex.cur = Token.YamlDirective - of "TAG": - lex.state = tagShorthand - lex.cur = Token.TagDirective - else: - lex.state = unknownDirParams - lex.cur = Token.UnknownDirective - lex.evaluated.setLen(0) - lex.evaluated.add(name) - of '-': - lex.startToken() - if lex.isDirectivesEnd(): - lex.state = afterToken - lex.cur = Token.DirectivesEnd - else: - lex.state = indentationSettingToken - lex.cur = Token.Indentation - lex.lineStartState = lineStart - lex.indentation = -1 - lex.endToken() - of '.': - lex.startToken() - if lex.isDocumentEnd(): - lex.state = expectLineEnd - lex.cur = Token.DocumentEnd - else: - lex.state = indentationSettingToken - lex.lineStartState = lineStart - lex.indentation = -1 - lex.cur = Token.Indentation - lex.endToken() - else: - lex.startToken() - while lex.c == ' ': lex.advance() - if lex.c in commentOrLineEnd: - lex.state = expectLineEnd - return false - lex.endToken() - lex.cur = Token.Indentation - lex.indentation = -1 - lex.state = indentationSettingToken - lex.lineStartState = lineStart - return true - -proc yamlVersion(lex: var Lexer): bool = - while lex.c in space: lex.advance() - lex.startToken() - lex.readNumericSubtoken() - if lex.c != '.': - raise lex.generateError("Illegal character in YAML version string: " & escape("" & lex.c)) - lex.advance() - lex.readNumericSubtoken() - if lex.c notin spaceOrLineEnd: - raise lex.generateError("Illegal character in YAML version string: " & escape("" & lex.c)) - lex.cur = Token.DirectiveParam - lex.endToken() - lex.state = expectLineEnd - return true - -proc tagShorthand(lex: var Lexer): bool = - while lex.c in space: lex.advance() - if lex.c != '!': - raise lex.generateError("Illegal character, tag shorthand must start with '!': " & escape("" & lex.c)) - lex.startToken() - lex.advance() - - if lex.c in spaceOrLineEnd: discard - else: - while lex.c in tagShorthandChars: lex.advance() - if lex.c != '!': - if lex.c in spaceOrLineEnd: - raise lex.generateError("Tag shorthand must end with '!'.") - else: - raise lex.generateError("Illegal character in tag shorthand: " & escape("" & lex.c)) - lex.advance() - if lex.c notin spaceOrLineEnd: - raise lex.generateError("Missing space after tag shorthand") - lex.cur = Token.TagHandle - lex.endToken() - lex.state = tagUri - return true - -proc tagUri(lex: var Lexer): bool = - while lex.c in space: lex.advance() - lex.startToken() - if lex.c == '<': - raise lex.generateError("Illegal character in tag URI: " & escape("" & lex.c)) - lex.readUri() - lex.cur = Token.Suffix - lex.endToken() - lex.state = expectLineEnd - return true - -proc unknownDirParams(lex: var Lexer): bool = - while lex.c in space: lex.advance() - if lex.c in lineEnd + {'#'}: - lex.state = expectLineEnd - return false - lex.startToken() - while true: - lex.advance() - if lex.c in lineEnd + {'#'}: break - lex.cur = Token.DirectiveParam - return true - -proc expectLineEnd(lex: var Lexer): bool = - while lex.c in space: lex.advance() - if lex.c notin commentOrLineEnd: - raise lex.generateError("Unexpected character (expected line end): " & escape("" & lex.c)) - lex.endLine() - return false - -proc lineStart(lex: var Lexer): bool = - return case lex.startLine() - of lsDirectivesEndMarker: lex.lineDirEnd() - of lsDocumentEndMarker: lex.lineDocEnd() - of lsComment, lsNewline: lex.endLine(); false - of lsStreamEnd: lex.state = streamEnd; false - of lsContent: - if lex.flowDepth == 0: lex.lineIndentation() - else: lex.flowLineIndentation() - -proc flowLineStart(lex: var Lexer): bool = - var indent: int - case lex.c - of '-': - if lex.isDirectivesEnd(): - raise lex.generateError("Directives end marker before end of flow content") - indent = 0 - of '.': - if lex.isDocumentEnd(): - raise lex.generateError("Document end marker before end of flow content") - indent = 0 - else: - let lineStart = lex.source.bufpos - while lex.c == ' ': lex.advance() - indent = lex.source.bufpos - lineStart - while lex.c in space: lex.advance() - if indent <= lex.indentation: - raise lex.generateError("Too few indentation spaces (must surpass surrounding block level)") - lex.state = insideLine - return false - -proc flowLineIndentation(lex: var Lexer): bool = - if lex.currentIndentation() < lex.indentation: - raise lex.generateError("Too few indentation spaces (must surpass surrounding block level)") - lex.state = insideLine - return false - -proc checkIndicatorChar(lex: var Lexer, kind: Token) = - if lex.isPlainSafe(): - lex.readPlainScalar() - else: - lex.startToken() - lex.advance() - lex.endToken() - lex.cur = kind - lex.state = beforeIndentationSettingToken - -proc enterFlowCollection(lex: var Lexer, kind: Token) = - lex.startToken() - if lex.flowDepth == 0: - lex.jsonEnablingState = afterJsonEnablingToken - lex.lineStartState = flowLineStart - lex.propertyIndentation = -1 - lex.flowDepth += 1 - lex.state = afterToken - lex.advance() - lex.endToken() - lex.cur = kind - -proc leaveFlowCollection(lex: var Lexer, kind: Token) = - lex.startToken() - if lex.flowDepth == 0: - raise lex.generateError("No flow collection to leave!") - lex.flowDepth -= 1 - if lex.flowDepth == 0: - lex.jsonEnablingState = afterToken - lex.lineStartState = lineStart - lex.state = lex.jsonEnablingState - lex.advance() - lex.endToken() - lex.cur = kind - -proc readNamespace(lex: var Lexer) = - lex.startToken() - lex.advance() - if lex.c == '<': - lex.readURI() - lex.endToken() - lex.cur = Token.VerbatimTag - lex.state = afterToken - else: - var handleEnd = lex.tokenStart - while true: - case lex.source.buf[handleEnd] - of spaceOrLineEnd + flowIndicators: - handleEnd = lex.tokenStart - lex.source.bufpos -= 1 - break - of '!': - handleEnd += 1 - break - else: - handleEnd += 1 - while lex.source.bufpos < handleEnd: - lex.advance() - if lex.c notin tagShorthandChars + {'!'}: - raise lex.generateError("Illegal character in tag handle: " & escape("" & lex.c)) - lex.advance() - lex.endToken() - lex.cur = Token.TagHandle - lex.state = atSuffix - -proc readAnchorName(lex: var Lexer) = - lex.startToken() - while true: - lex.advance() - if lex.c in spaceOrLineEnd + flowIndicators: break - if lex.source.bufpos == lex.tokenStart + 1: - raise lex.generateError("Anchor name must not be empty") - lex.state = afterToken - -proc insideLine(lex: var Lexer): bool = - case lex.c - of ':': - lex.checkIndicatorChar(Token.MapValueInd) - if lex.cur == Token.MapValueInd and lex.propertyIndentation != -1: - lex.indentation = lex.propertyIndentation - lex.propertyIndentation = -1 - of '?': - lex.checkIndicatorChar(Token.MapKeyInd) - of '-': - lex.checkIndicatorChar(Token.SeqItemInd) - of commentOrLineEnd: - lex.endLine() - return false - of '"': - lex.readDoubleQuotedScalar() - lex.state = lex.jsonEnablingState - of '\'': - lex.readSingleQuotedScalar() - lex.state = lex.jsonEnablingState - of '>', '|': - if lex.flowDepth > 0: - lex.readPlainScalar() - else: - lex.readBlockScalar() - of '{': - lex.enterFlowCollection(Token.MapStart) - of '}': - lex.leaveFlowCollection(Token.MapEnd) - of '[': - lex.enterFlowCollection(Token.SeqStart) - of ']': - lex.leaveFlowCollection(Token.SeqEnd) - of ',': - lex.startToken() - lex.advance() - lex.endToken() - lex.cur = Token.SeqSep - lex.state = afterToken - of '!': - lex.readNamespace() - of '&': - lex.readAnchorName() - lex.endToken() - lex.cur = Token.Anchor - of '*': - lex.readAnchorName() - lex.endToken() - lex.cur = Token.Alias - of ' ', '\t': - while true: - lex.advance() - if lex.c notin space: break - return false - of '@', '`': - raise lex.generateError("Reserved character may not start any token") - else: - lex.readPlainScalar() - return true - -proc indentationSettingToken(lex: var Lexer): bool = - let cachedIntentation = lex.currentIndentation() - result = lex.insideLine() - if result and lex.flowDepth == 0: - if lex.cur in nodePropertyKind: - lex.propertyIndentation = cachedIntentation - else: - lex.indentation = cachedIntentation - -proc afterToken(lex: var Lexer): bool = - while lex.c in space: lex.advance() - if lex.c in commentOrLineEnd: - lex.endLine() - else: - lex.state = insideLine - return false - -proc beforeIndentationSettingToken(lex: var Lexer): bool = - discard lex.afterToken() - if lex.state == insideLine: - lex.state = indentationSettingToken - return false - -proc afterJsonEnablingToken(lex: var Lexer): bool = - while lex.c == ' ': lex.advance() - while true: - case lex.c - of ':': - lex.startToken() - lex.advance() - lex.endToken() - lex.cur = Token.MapValueInd - lex.state = afterToken - return true - of '#', '\l', '\c': - lex.endLine() - discard lex.flowLineStart() - of EndOfFile: - lex.state = streamEnd - return false - else: - lex.state = insideLine - return false - -proc lineIndentation(lex: var Lexer): bool = - lex.curStartPos.line = lex.source.lineNumber - lex.curStartPos.column = 1 - lex.endToken() - lex.cur = Token.Indentation - lex.state = indentationSettingToken - return true - -proc lineDirEnd(lex: var Lexer): bool = - lex.curStartPos.line = lex.source.lineNumber - lex.curStartPos.column = 1 - lex.endToken() - lex.cur = Token.DirectivesEnd - lex.state = afterToken - lex.indentation = -1 - lex.propertyIndentation = -1 - return true - -proc lineDocEnd(lex: var Lexer): bool = - lex.curStartPos.line = lex.source.lineNumber - lex.curStartPos.column = 1 - lex.endToken() - lex.cur = Token.DocumentEnd - lex.state = expectLineEnd - lex.lineStartState = outsideDoc - return true - -proc atSuffix(lex: var Lexer): bool = - lex.startToken() - lex.evaluated.setLen(0) - var curStart = lex.tokenStart - 1 - while true: - case lex.c - of uriChars: lex.advance() - of '%': - if curStart <= lex.source.bufpos - 2: - lex.evaluated.add(lex.source.buf[curStart..lex.source.bufpos - 2]) - lex.readHexSequence(2) - curStart = lex.source.bufpos - lex.advance() - else: break - if curStart <= lex.source.bufpos - 2: - lex.evaluated.add(lex.source.buf[curStart..lex.source.bufpos - 2]) - lex.endToken() - lex.cur = Token.Suffix - lex.state = afterToken - return true - -proc streamEnd(lex: var Lexer): bool = - lex.startToken() - lex.endToken() - lex.cur = Token.StreamEnd - return true \ No newline at end of file diff --git a/lib/yaml/yaml/serialization.nim b/lib/yaml/yaml/serialization.nim deleted file mode 100644 index 0a75412..0000000 --- a/lib/yaml/yaml/serialization.nim +++ /dev/null @@ -1,1440 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 - 2020 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ========================= -## Module yaml/serialization -## ========================= -## -## This is the most high-level API of NimYAML. It enables you to parse YAML -## character streams directly into native YAML types and vice versa. It builds -## on top of the low-level parser and presenter APIs. -## -## It is possible to define custom construction and serialization procs for any -## type. Please consult the serialization guide on the NimYAML website for more -## information. - -import tables, typetraits, strutils, macros, streams, times, parseutils, options -import data, parser, taglib, presenter, stream, private/internal, hints, annotations -export data, stream, macros, annotations, options - # *something* in here needs externally visible `==`(x,y: AnchorId), - # but I cannot figure out what. binding it would be the better option. - -type - SerializationContext* = ref object - ## Context information for the process of serializing YAML from Nim values. - refs*: Table[pointer, tuple[a: Anchor, referenced: bool]] - style: AnchorStyle - nextAnchorId*: string - put*: proc(e: Event) {.raises: [], closure.} - - ConstructionContext* = ref object - ## Context information for the process of constructing Nim values from YAML. - refs*: Table[Anchor, tuple[tag: Tag, p: pointer]] - - YamlConstructionError* = object of YamlLoadingError - ## Exception that may be raised when constructing data objects from a - ## `YamlStream <#YamlStream>`_. The fields ``line``, ``column`` and - ## ``lineContent`` are only available if the costructing proc also does - ## parsing, because otherwise this information is not available to the - ## costruction proc. - - YamlSerializationError* = object of ValueError - ## Exception that may be raised when serializing Nim values into YAML - ## stream events. - -# forward declares - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var T) - {.raises: [YamlConstructionError, YamlStreamError].} - ## Constructs an arbitrary Nim value from a part of a YAML stream. - ## The stream will advance until after the finishing token that was used - ## for constructing the value. The ``ConstructionContext`` is needed for - ## potential child objects which may be refs. - -proc constructChild*(s: var YamlStream, c: ConstructionContext, - result: var string) - {.raises: [YamlConstructionError, YamlStreamError].} - ## Constructs a Nim value that is a string from a part of a YAML stream. - ## This specialization takes care of possible nil strings. - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var seq[T]) - {.raises: [YamlConstructionError, YamlStreamError].} - ## Constructs a Nim value that is a string from a part of a YAML stream. - ## This specialization takes care of possible nil seqs. - -proc constructChild*[O](s: var YamlStream, c: ConstructionContext, - result: var ref O) - {.raises: [YamlConstructionError, YamlStreamError].} - ## Constructs an arbitrary Nim value from a part of a YAML stream. - ## The stream will advance until after the finishing token that was used - ## for constructing the value. The object may be constructed from an alias - ## node which will be resolved using the ``ConstructionContext``. - -proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext) - {.raises: [YamlSerializationError].} - ## Represents an arbitrary Nim reference value as YAML object. The object - ## may be represented as alias node if it is already present in the - ## ``SerializationContext``. - -proc representChild*(value: string, ts: TagStyle, c: SerializationContext) - {.inline, raises: [].} - ## Represents a Nim string. Supports nil strings. - -proc representChild*[O](value: O, ts: TagStyle, c: SerializationContext) - ## Represents an arbitrary Nim object as YAML object. - -proc newConstructionContext*(): ConstructionContext = - new(result) - result.refs = initTable[Anchor, tuple[tag: Tag, p: pointer]]() - -proc newSerializationContext*(s: AnchorStyle, - putImpl: proc(e: Event) {.raises: [], closure.}): - SerializationContext = - result = SerializationContext(style: s, nextAnchorId: "a", - put: putImpl) - result.refs = initTable[pointer, tuple[a: Anchor, referenced: bool]]() - -template presentTag*(t: typedesc, ts: TagStyle): Tag = - ## Get the Tag that represents the given type in the given style - if ts == tsNone: yTagQuestionMark else: yamlTag(t) - -proc safeTagUri(tag: Tag): string {.raises: [].} = - try: - var uri = $tag - # '!' is not allowed inside a tag handle - if uri.len > 0 and uri[0] == '!': uri = uri[1..^1] - # ',' is not allowed after a tag handle in the suffix because it's a flow - # indicator - for i in countup(0, uri.len - 1): - if uri[i] == ',': uri[i] = ';' - return uri - except KeyError: - internalError("Unexpected KeyError for Tag " & $tag) - -proc newYamlConstructionError*(s: YamlStream, mark: Mark, msg: string): ref YamlConstructionError = - result = newException(YamlConstructionError, msg) - result.mark = mark - if not s.getLastTokenContext(result.lineContent): - result.lineContent = "" - -proc constructionError(s: YamlStream, mark: Mark, msg: string): ref YamlConstructionError = - return newYamlConstructionError(s, mark, msg) - -template constructScalarItem*(s: var YamlStream, i: untyped, - t: typedesc, content: untyped) = - ## Helper template for implementing ``constructObject`` for types that - ## are constructed from a scalar. ``i`` is the identifier that holds - ## the scalar as ``Event`` in the content. Exceptions raised in - ## the content will be automatically caught and wrapped in - ## ``YamlConstructionError``, which will then be raised. - bind constructionError - let i = s.next() - if i.kind != yamlScalar: - raise constructionError(s, i.startPos, "Expected scalar") - try: content - except YamlConstructionError as e: raise e - except Exception: - var e = constructionError(s, i.startPos, - "Cannot construct to " & name(t) & ": " & item.scalarContent & - "; error: " & getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -proc yamlTag*(T: typedesc[string]): Tag {.inline, noSideEffect, raises: [].} = - yTagString - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var string) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## costructs a string from a YAML scalar - constructScalarItem(s, item, string): - result = item.scalarContent - -proc representObject*(value: string, ts: TagStyle, - c: SerializationContext, tag: Tag) {.raises: [].} = - ## represents a string as YAML scalar - c.put(scalarEvent(value, tag, yAnchorNone)) - -proc parseHex[T: int8|int16|int32|int64|uint8|uint16|uint32|uint64]( - s: YamlStream, mark: Mark, val: string): T = - result = 0 - for i in 2.. 1 and item.scalarContent[1] in {'x', 'X' }: - result = parseHex[T](s, item.startPos, item.scalarContent) - elif item.scalarContent[0] == '0' and item.scalarContent.len > 1 and item.scalarContent[1] in {'o', 'O'}: - result = parseOctal[T](s, item.startPos, item.scalarContent) - else: - let nInt = parseBiggestInt(item.scalarContent) - if nInt <= T.high: - # make sure we don't produce a range error - result = T(nInt) - else: - raise s.constructionError(item.startPos, "Cannot construct int; out of range: " & - $nInt & " for type " & T.name & " with max of: " & $T.high) - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var int) - {.raises: [YamlConstructionError, YamlStreamError], inline.} = - ## constructs an integer of architecture-defined length by loading it into - ## int32 and then converting it. - var i32Result: int32 - constructObject(s, c, i32Result) - result = int(i32Result) - -proc representObject*[T: int8|int16|int32|int64](value: T, ts: TagStyle, - c: SerializationContext, tag: Tag) {.raises: [].} = - ## represents an integer value as YAML scalar - c.put(scalarEvent($value, tag, yAnchorNone)) - -proc representObject*(value: int, tagStyle: TagStyle, - c: SerializationContext, tag: Tag) - {.raises: [YamlSerializationError], inline.}= - ## represent an integer of architecture-defined length by casting it to int32. - ## on 64-bit systems, this may cause a RangeDefect. - - # currently, sizeof(int) is at least sizeof(int32). - try: c.put(scalarEvent($int32(value), tag, yAnchorNone)) - except RangeDefect: - var e = newException(YamlSerializationError, getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -when defined(JS): - type DefiniteUIntTypes = uint8 | uint16 | uint32 -else: - type DefiniteUIntTypes = uint8 | uint16 | uint32 | uint64 - -proc constructObject*[T: DefiniteUIntTypes]( - s: var YamlStream, c: ConstructionContext, result: var T) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## construct an unsigned integer value from a YAML scalar - constructScalarItem(s, item, T): - if item.scalarContent[0] == '0' and item.scalarContent[1] in {'x', 'X'}: - result = parseHex[T](s, item.startPos, item.scalarContent) - elif item.scalarContent[0] == '0' and item.scalarContent[1] in {'o', 'O'}: - result = parseOctal[T](s, item.startPos, item.scalarContent) - else: result = T(parseBiggestUInt(item.scalarContent)) - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var uint) - {.raises: [YamlConstructionError, YamlStreamError], inline.} = - ## represent an unsigned integer of architecture-defined length by loading it - ## into uint32 and then converting it. - var u32Result: uint32 - constructObject(s, c, u32Result) - result= uint(u32Result) - -when defined(JS): - # TODO: this is a dirty hack and may lead to overflows! - proc `$`(x: uint8|uint16|uint32|uint64|uint): string = - result = $BiggestInt(x) - -proc representObject*[T: uint8|uint16|uint32|uint64](value: T, ts: TagStyle, - c: SerializationContext, tag: Tag) {.raises: [].} = - ## represents an unsigned integer value as YAML scalar - c.put(scalarEvent($value, tag, yAnchorNone)) - -proc representObject*(value: uint, ts: TagStyle, c: SerializationContext, - tag: Tag) {.raises: [YamlSerializationError], inline.} = - ## represent an unsigned integer of architecture-defined length by casting it - ## to int32. on 64-bit systems, this may cause a RangeDefect. - try: c.put(scalarEvent($uint32(value), tag, yAnchorNone)) - except RangeDefect: - var e = newException(YamlSerializationError, getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -proc constructObject*[T: float|float32|float64]( - s: var YamlStream, c: ConstructionContext, result: var T) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## construct a float value from a YAML scalar - constructScalarItem(s, item, T): - let hint = guessType(item.scalarContent) - case hint - of yTypeFloat: - discard parseBiggestFloat(item.scalarContent, result) - of yTypeInteger: - discard parseBiggestFloat(item.scalarContent, result) - of yTypeFloatInf: - if item.scalarContent[0] == '-': result = NegInf - else: result = Inf - of yTypeFloatNaN: result = NaN - else: - raise s.constructionError(item.startPos, "Cannot construct to float: " & - escape(item.scalarContent)) - -proc representObject*[T: float|float32|float64](value: T, ts: TagStyle, - c: SerializationContext, tag: Tag) {.raises: [].} = - ## represents a float value as YAML scalar - case value - of Inf: c.put(scalarEvent(".inf", tag)) - of NegInf: c.put(scalarEvent("-.inf", tag)) - of NaN: c.put(scalarEvent(".nan", tag)) - else: c.put(scalarEvent($value, tag)) - -proc yamlTag*(T: typedesc[bool]): Tag {.inline, raises: [].} = yTagBoolean - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var bool) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a bool value from a YAML scalar - constructScalarItem(s, item, bool): - case guessType(item.scalarContent) - of yTypeBoolTrue: result = true - of yTypeBoolFalse: result = false - else: - raise s.constructionError(item.startPos, "Cannot construct to bool: " & - escape(item.scalarContent)) - -proc representObject*(value: bool, ts: TagStyle, c: SerializationContext, - tag: Tag) {.raises: [].} = - ## represents a bool value as a YAML scalar - c.put(scalarEvent(if value: "true" else: "false", tag, yAnchorNone)) - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var char) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a char value from a YAML scalar - constructScalarItem(s, item, char): - if item.scalarContent.len != 1: - raise s.constructionError(item.startPos, "Cannot construct to char (length != 1): " & - escape(item.scalarContent)) - else: result = item.scalarContent[0] - -proc representObject*(value: char, ts: TagStyle, c: SerializationContext, - tag: Tag) {.raises: [].} = - ## represents a char value as YAML scalar - c.put(scalarEvent("" & value, tag, yAnchorNone)) - -proc yamlTag*(T: typedesc[Time]): Tag {.inline, raises: [].} = yTagTimestamp - -proc constructObject*(s: var YamlStream, c: ConstructionContext, - result: var Time) - {.raises: [YamlConstructionError, YamlStreamError].} = - constructScalarItem(s, item, Time): - if guessType(item.scalarContent) == yTypeTimestamp: - var - tmp = newStringOfCap(60) - pos = 8 - c: char - while pos < item.scalarContent.len(): - c = item.scalarContent[pos] - if c in {' ', '\t', 'T', 't'}: break - inc(pos) - if pos == item.scalarContent.len(): - tmp.add(item.scalarContent) - tmp.add("T00:00:00+00:00") - else: - tmp.add(item.scalarContent[0 .. pos - 1]) - if c in {' ', '\t'}: - while true: - inc(pos) - c = item.scalarContent[pos] - if c notin {' ', '\t'}: break - else: inc(pos) - tmp.add("T") - let timeStart = pos - inc(pos, 7) - var fractionStart = -1 - while pos < item.scalarContent.len(): - c = item.scalarContent[pos] - if c in {'+', '-', 'Z', ' ', '\t'}: break - elif c == '.': fractionStart = pos - inc(pos) - if fractionStart == -1: - tmp.add(item.scalarContent[timeStart .. pos - 1]) - else: - tmp.add(item.scalarContent[timeStart .. fractionStart - 1]) - if c in {'Z', ' ', '\t'}: tmp.add("+00:00") - else: - tmp.add(c) - inc(pos) - let tzStart = pos - inc(pos) - if pos < item.scalarContent.len() and item.scalarContent[pos] != ':': - inc(pos) - if pos - tzStart == 1: tmp.add('0') - tmp.add(item.scalarContent[tzStart .. pos - 1]) - if pos == item.scalarContent.len(): tmp.add(":00") - elif pos + 2 == item.scalarContent.len(): - tmp.add(":0") - tmp.add(item.scalarContent[pos + 1]) - else: - tmp.add(item.scalarContent[pos .. pos + 2]) - let info = tmp.parse("yyyy-M-d'T'H:mm:sszzz") - result = info.toTime() - else: - raise s.constructionError(item.startPos, "Not a parsable timestamp: " & - escape(item.scalarContent)) - -proc representObject*(value: Time, ts: TagStyle, c: SerializationContext, - tag: Tag) {.raises: [ValueError].} = - let tmp = value.utc() - c.put(scalarEvent(tmp.format("yyyy-MM-dd'T'HH:mm:ss'Z'"))) - -proc yamlTag*[I](T: typedesc[seq[I]]): Tag {.inline, raises: [].} = - return nimTag("system:seq(" & safeTagUri(yamlTag(I)) & ')') - -proc yamlTag*[I](T: typedesc[set[I]]): Tag {.inline, raises: [].} = - return nimTag("system:set(" & safeTagUri(yamlTag(I)) & ')') - -proc constructObject*[T](s: var YamlStream, c: ConstructionContext, - result: var seq[T]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim seq from a YAML sequence - let event = s.next() - if event.kind != yamlStartSeq: - raise s.constructionError(event.startPos, "Expected sequence start") - result = newSeq[T]() - while s.peek().kind != yamlEndSeq: - var item: T - constructChild(s, c, item) - result.add(move(item)) - discard s.next() - -proc constructObject*[T](s: var YamlStream, c: ConstructionContext, - result: var set[T]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim seq from a YAML sequence - let event = s.next() - if event.kind != yamlStartSeq: - raise s.constructionError(event.startPos, "Expected sequence start") - result = {} - while s.peek().kind != yamlEndSeq: - var item: T - constructChild(s, c, item) - result.incl(item) - discard s.next() - -proc representObject*[T](value: seq[T]|set[T], ts: TagStyle, - c: SerializationContext, tag: Tag) = - ## represents a Nim seq as YAML sequence - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startSeqEvent(tag = tag)) - for item in value: - representChild(item, childTagStyle, c) - c.put(endSeqEvent()) - -proc yamlTag*[I, V](T: typedesc[array[I, V]]): Tag {.inline, raises: [].} = - const rangeName = name(I) - return nimTag("system:array(" & rangeName[6..rangeName.high()] & ';' & - safeTagUri(yamlTag(V)) & ')') - -proc constructObject*[I, T](s: var YamlStream, c: ConstructionContext, - result: var array[I, T]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim array from a YAML sequence - var event = s.next() - if event.kind != yamlStartSeq: - raise s.constructionError(event.startPos, "Expected sequence start") - for index in low(I)..high(I): - event = s.peek() - if event.kind == yamlEndSeq: - raise s.constructionError(event.startPos, "Too few array values") - constructChild(s, c, result[index]) - event = s.next() - if event.kind != yamlEndSeq: - raise s.constructionError(event.startPos, "Too many array values") - -proc representObject*[I, T](value: array[I, T], ts: TagStyle, - c: SerializationContext, tag: Tag) = - ## represents a Nim array as YAML sequence - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startSeqEvent(tag = tag)) - for item in value: - representChild(item, childTagStyle, c) - c.put(endSeqEvent()) - -proc yamlTag*[K, V](T: typedesc[Table[K, V]]): Tag {.inline, raises: [].} = - return nimTag("tables:Table(" & safeTagUri(yamlTag(K)) & ';' & - safeTagUri(yamlTag(V)) & ")") - -proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext, - result: var Table[K, V]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim Table from a YAML mapping - let event = s.next() - if event.kind != yamlStartMap: - raise s.constructionError(event.startPos, "Expected map start, got " & $event.kind) - result = initTable[K, V]() - while s.peek.kind != yamlEndMap: - var - key: K - value: V - constructChild(s, c, key) - constructChild(s, c, value) - if result.contains(key): - raise s.constructionError(event.startPos, "Duplicate table key!") - result[key] = value - discard s.next() - -proc representObject*[K, V](value: Table[K, V], ts: TagStyle, - c: SerializationContext, tag: Tag) = - ## represents a Nim Table as YAML mapping - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startMapEvent(tag = tag)) - for key, value in value.pairs: - representChild(key, childTagStyle, c) - representChild(value, childTagStyle, c) - c.put(endMapEvent()) - -proc yamlTag*[K, V](T: typedesc[OrderedTable[K, V]]): Tag - {.inline, raises: [].} = - return nimTag("tables:OrderedTable(" & safeTagUri(yamlTag(K)) & ';' & - safeTagUri(yamlTag(V)) & ")") - -proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext, - result: var OrderedTable[K, V]) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim OrderedTable from a YAML mapping - var event = s.next() - if event.kind != yamlStartSeq: - raise s.constructionError(event.startPos, "Expected seq start, got " & $event.kind) - result = initOrderedTable[K, V]() - while s.peek.kind != yamlEndSeq: - var - key: K - value: V - event = s.next() - if event.kind != yamlStartMap: - raise s.constructionError(event.startPos, "Expected map start, got " & $event.kind) - constructChild(s, c, key) - constructChild(s, c, value) - event = s.next() - if event.kind != yamlEndMap: - raise s.constructionError(event.startPos, "Expected map end, got " & $event.kind) - if result.contains(key): - raise s.constructionError(event.startPos, "Duplicate table key!") - result[move(key)] = move(value) - discard s.next() - -proc representObject*[K, V](value: OrderedTable[K, V], ts: TagStyle, - c: SerializationContext, tag: Tag) = - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - c.put(startSeqEvent(tag = tag)) - for key, value in value.pairs: - c.put(startMapEvent()) - representChild(key, childTagStyle, c) - representChild(value, childTagStyle, c) - c.put(endMapEvent()) - c.put(endSeqEvent()) - -proc yamlTag*(T: typedesc[object|enum]): - Tag {.inline, raises: [].} = - return nimTag("custom:" & (typetraits.name(type(T)))) - -proc yamlTag*(T: typedesc[tuple]): - Tag {.inline, raises: [].} = - var - i: T - uri = nimyamlTagRepositoryPrefix & "tuple(" - first = true - for name, value in fieldPairs(i): - if first: first = false - else: uri.add(",") - uri.add(safeTagUri(yamlTag(type(value)))) - uri.add(")") - return Tag(uri) - -iterator recListItems(n: NimNode): NimNode = - if n.kind == nnkRecList: - for item in n.children: yield item - else: yield n - -proc recListLen(n: NimNode): int {.compileTime.} = - if n.kind == nnkRecList: result = n.len - else: result = 1 - -proc recListNode(n: NimNode): NimNode {.compileTime.} = - if n.kind == nnkRecList: result = n[0] - else: result = n - -proc fieldCount(t: NimNode): int {.compiletime.} = - result = 0 - let tDesc = getType(getType(t)[1]) - if tDesc.kind == nnkBracketExpr: - # tuple - result = tDesc.len - 1 - else: - # object - for child in tDesc[2].children: - inc(result) - if child.kind == nnkRecCase: - for bIndex in 1.. 0 - else: - const failOnUnknown = true - while s.peek.kind != endKind: - e = s.next() - when isVariantObject(getType(O)): - if e.kind != yamlStartMap: - raise s.constructionError(e.startPos, "Expected single-pair map, got " & $e.kind) - e = s.next() - if e.kind != yamlScalar: - raise s.constructionError(e.startPos, "Expected field name, got " & $e.kind) - let name = e.scalarContent - when result is tuple: - var i = 0 - var found = false - for fname, value in fieldPairs(result): - if fname == name: - if matched[i]: - raise s.constructionError(e.startPos, "While constructing " & - typetraits.name(O) & ": Duplicate field: " & escape(name)) - constructChild(s, c, value) - matched[i] = true - found = true - break - inc(i) - when failOnUnknown: - if not found: - raise s.constructionError(e.startPos, "While constructing " & - typetraits.name(O) & ": Unknown field: " & escape(name)) - else: - when hasIgnore(O) and failOnUnknown: - if name notin ignoredKeyList: - constructFieldValue(O, s, c, name, result, matched, failOnUnknown, e.startPos) - else: - e = s.next() - var depth = int(e.kind in {yamlStartMap, yamlStartSeq}) - while depth > 0: - case s.next().kind - of yamlStartMap, yamlStartSeq: inc(depth) - of yamlEndMap, yamlEndSeq: dec(depth) - of yamlScalar: discard - else: internalError("Unexpected event kind.") - else: - constructFieldValue(O, s, c, name, result, matched, failOnUnknown, e.startPos) - when isVariantObject(getType(O)): - e = s.next() - if e.kind != yamlEndMap: - raise s.constructionError(e.startPos, "Expected end of single-pair map, got " & - $e.kind) - discard s.next() - when result is tuple: - var i = 0 - for fname, value in fieldPairs(result): - if not matched[i]: - raise s.constructionError(startPos, "While constructing " & - typetraits.name(O) & ": Missing field: " & escape(fname)) - inc(i) - else: ensureAllFieldsPresent(s, O, result, matched, startPos) - -proc constructObject*[O: object|tuple]( - s: var YamlStream, c: ConstructionContext, result: var O) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## Overridable default implementation for custom object and tuple types - constructObjectDefault(s, c, result) - -macro genRepresentObject(t: typedesc, value, childTagStyle: typed) = - result = newStmtList() - let - tDecl = getType(t) - tDesc = getType(tDecl[1]) - isVO = isVariantObject(t) - var fieldIndex = 0'i16 - for child in tDesc[2].children: - if child.kind == nnkRecCase: - let - fieldName = $child[0] - fieldAccessor = newDotExpr(value, newIdentNode(fieldName)) - result.add(quote do: - c.put(startMapEvent()) - c.put(scalarEvent(`fieldName`, tag = if `childTagStyle` == tsNone: - yTagQuestionMark else: yTagNimField)) - representChild(`fieldAccessor`, `childTagStyle`, c) - c.put(endMapEvent()) - ) - let enumName = $getTypeInst(child[0]) - var caseStmt = newNimNode(nnkCaseStmt).add(fieldAccessor) - for bIndex in 1 .. len(child) - 1: - var curBranch: NimNode - var recListIndex = 0 - case child[bIndex].kind - of nnkOfBranch: - curBranch = newNimNode(nnkOfBranch) - while recListIndex < child[bIndex].len - 1: - expectKind(child[bIndex][recListIndex], nnkIntLit) - curBranch.add(newCall(enumName, newLit(child[bIndex][recListIndex].intVal))) - inc(recListIndex) - of nnkElse: - curBranch = newNimNode(nnkElse) - else: - internalError("Unexpected child kind: " & $child[bIndex].kind) - var curStmtList = newStmtList() - if child[bIndex][recListIndex].recListLen > 0: - for item in child[bIndex][recListIndex].recListItems(): - inc(fieldIndex) - let - name = $item - itemAccessor = newDotExpr(value, newIdentNode(name)) - curStmtList.add(quote do: - when not `itemAccessor`.hasCustomPragma(transient): - c.put(startMapEvent()) - c.put(scalarEvent(`name`, tag = if `childTagStyle` == tsNone: - yTagQuestionMark else: yTagNimField)) - representChild(`itemAccessor`, `childTagStyle`, c) - c.put(endMapEvent()) - ) - else: - curStmtList.add(newNimNode(nnkDiscardStmt).add(newEmptyNode())) - curBranch.add(curStmtList) - caseStmt.add(curBranch) - result.add(caseStmt) - else: - let - name = $child - childAccessor = newDotExpr(value, newIdentNode(name)) - result.add(quote do: - template serializeImpl = - when bool(`isVO`): c.put(startMapEvent()) - c.put(scalarEvent(`name`, if `childTagStyle` == tsNone: - yTagQuestionMark else: yTagNimField, yAnchorNone)) - representChild(`childAccessor`, `childTagStyle`, c) - when bool(`isVO`): c.put(endMapEvent()) - when not `childAccessor`.hasCustomPragma(transient): - when hasSparse(`t`) and `child` is Option: - if `childAccessor`.isSome: serializeImpl() - else: - serializeImpl() - ) - inc(fieldIndex) - -proc representObject*[O: object](value: O, ts: TagStyle, - c: SerializationContext, tag: Tag) = - ## represents a Nim object or tuple as YAML mapping - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - when isVariantObject(getType(O)): c.put(startSeqEvent(tag = tag)) - else: c.put(startMapEvent(tag = tag)) - genRepresentObject(O, value, childTagStyle) - when isVariantObject(getType(O)): c.put(endSeqEvent()) - else: c.put(endMapEvent()) - -proc representObject*[O: tuple](value: O, ts: TagStyle, - c: SerializationContext, tag: Tag) = - let childTagStyle = if ts == tsRootOnly: tsNone else: ts - var fieldIndex = 0'i16 - c.put(startMapEvent(tag = tag)) - for name, fvalue in fieldPairs(value): - c.put(scalarEvent(name, tag = if childTagStyle == tsNone: - yTagQuestionMark else: yTagNimField)) - representChild(fvalue, childTagStyle, c) - inc(fieldIndex) - c.put(endMapEvent()) - -proc constructObject*[O: enum](s: var YamlStream, c: ConstructionContext, - result: var O) - {.raises: [YamlConstructionError, YamlStreamError].} = - ## constructs a Nim enum from a YAML scalar - let e = s.next() - if e.kind != yamlScalar: - raise s.constructionError(e.startPos, "Expected scalar, got " & $e.kind) - try: result = parseEnum[O](e.scalarContent) - except ValueError: - var ex = s.constructionError(e.startPos, "Cannot parse '" & - escape(e.scalarContent) & "' as " & type(O).name) - ex.parent = getCurrentException() - raise ex - -proc representObject*[O: enum](value: O, ts: TagStyle, - c: SerializationContext, tag: Tag) {.raises: [].} = - ## represents a Nim enum as YAML scalar - c.put(scalarEvent($value, tag, yAnchorNone)) - -proc yamlTag*[O](T: typedesc[ref O]): Tag {.inline, raises: [].} = yamlTag(O) - -macro constructImplicitVariantObject(s, m, c, r, possibleTags: untyped, - t: typedesc) = - let tDesc = getType(getType(t)[1]) - yAssert tDesc.kind == nnkObjectTy - let recCase = tDesc[2][0] - yAssert recCase.kind == nnkRecCase - result = newNimNode(nnkIfStmt) - for i in 1 .. recCase.len - 1: - yAssert recCase[i].kind == nnkOfBranch - var branch = newNimNode(nnkElifBranch) - var branchContent = newStmtList(newAssignment(r, - newNimNode(nnkObjConstr).add( - newCall("type", r), - newColonExpr(newIdentNode($recCase[0]), recCase[i][0]) - ))) - case recCase[i][1].recListLen - of 0: - branch.add(infix(newIdentNode("yTagNull"), "in", possibleTags)) - branchContent.add(newNimNode(nnkDiscardStmt).add(newCall("next", s))) - of 1: - let field = newDotExpr(r, newIdentNode($recCase[i][1].recListNode)) - branch.add(infix( - newCall("yamlTag", newCall("type", field)), "in", possibleTags)) - branchContent.add(newCall("constructChild", s, c, field)) - else: - block: - internalError("Too many children: " & $recCase[i][1].recListlen) - branch.add(branchContent) - result.add(branch) - let raiseStmt = newNimNode(nnkRaiseStmt).add( - newCall(bindSym("constructionError"), s, m, - infix(newStrLitNode("This value type does not map to any field in " & - getTypeImpl(t)[1].repr & ": "), "&", - newCall("$", newNimNode(nnkBracketExpr).add(possibleTags, newIntLitNode(0))) - ) - )) - result.add(newNimNode(nnkElse).add(newNimNode(nnkTryStmt).add( - newStmtList(raiseStmt), newNimNode(nnkExceptBranch).add( - newIdentNode("KeyError"), - newNimNode(nnkDiscardStmt).add(newEmptyNode()) - )))) - -proc isImplicitVariantObject(t: typedesc): bool {.compileTime.} = - when compiles(t.hasCustomPragma(implicit)): - return t.hasCustomPragma(implicit) - else: - return false - -proc canBeImplicit(t: typedesc): bool {.compileTime.} = - let tDesc = getType(t) - if tDesc.kind != nnkObjectTy: return false - if tDesc[2].len != 1: return false - if tDesc[2][0].kind != nnkRecCase: return false - var foundEmptyBranch = false - for i in 1.. tDesc[2][0].len - 1: - case tDesc[2][0][i][1].recListlen # branch contents - of 0: - if foundEmptyBranch: return false - else: foundEmptyBranch = true - of 1: discard - else: return false - return true - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var T) = - let item = s.peek() - when isImplicitVariantObject(T): - when not canBeImplicit(T): - {. fatal: "This type cannot be marked as implicit" .} - var possibleTags = newSeq[Tag]() - case item.kind - of yamlScalar: - case item.scalarProperties.tag - of yTagQuestionMark: - case guessType(item.scalarContent) - of yTypeInteger: - possibleTags.add([yamlTag(int), yamlTag(int8), yamlTag(int16), - yamlTag(int32), yamlTag(int64)]) - if item.scalarContent[0] != '-': - possibleTags.add([yamlTag(uint), yamlTag(uint8), yamlTag(uint16), - yamlTag(uint32), yamlTag(uint64)]) - of yTypeFloat, yTypeFloatInf, yTypeFloatNaN: - possibleTags.add([yamlTag(float), yamlTag(float32), - yamlTag(float64)]) - of yTypeBoolTrue, yTypeBoolFalse: - possibleTags.add(yamlTag(bool)) - of yTypeNull: - raise s.constructionError(item.startPos, "not implemented!") - of yTypeUnknown: - possibleTags.add(yamlTag(string)) - of yTypeTimestamp: - possibleTags.add(yamlTag(Time)) - of yTagExclamationMark: - possibleTags.add(yamlTag(string)) - else: - possibleTags.add(item.scalarProperties.tag) - of yamlStartMap: - if item.mapProperties.tag in [yTagQuestionMark, yTagExclamationMark]: - raise s.constructionError(item.startPos, - "Complex value of implicit variant object type must have a tag.") - possibleTags.add(item.mapProperties.tag) - of yamlStartSeq: - if item.seqProperties.tag in [yTagQuestionMark, yTagExclamationMark]: - raise s.constructionError(item.startPos, - "Complex value of implicit variant object type must have a tag.") - possibleTags.add(item.seqProperties.tag) - else: internalError("Unexpected item kind: " & $item.kind) - constructImplicitVariantObject(s, item.startPos, c, result, possibleTags, T) - else: - case item.kind - of yamlScalar: - if item.scalarProperties.tag notin [yTagQuestionMark, yTagExclamationMark, - yamlTag(T)]: - raise s.constructionError(item.startPos, "Wrong tag for " & typetraits.name(T)) - elif item.scalarProperties.anchor != yAnchorNone: - raise s.constructionError(item.startPos, "Anchor on non-ref type") - of yamlStartMap: - if item.mapProperties.tag notin [yTagQuestionMark, yamlTag(T)]: - raise s.constructionError(item.startPos, "Wrong tag for " & typetraits.name(T)) - elif item.mapProperties.anchor != yAnchorNone: - raise s.constructionError(item.startPos, "Anchor on non-ref type") - of yamlStartSeq: - if item.seqProperties.tag notin [yTagQuestionMark, yamlTag(T)]: - raise s.constructionError(item.startPos, "Wrong tag for " & typetraits.name(T)) - elif item.seqProperties.anchor != yAnchorNone: - raise s.constructionError(item.startPos, "Anchor on non-ref type") - else: internalError("Unexpected item kind: " & $item.kind) - constructObject(s, c, result) - -proc constructChild*(s: var YamlStream, c: ConstructionContext, - result: var string) = - let item = s.peek() - if item.kind == yamlScalar: - if item.scalarProperties.tag notin - [yTagQuestionMark, yTagExclamationMark, yamlTag(string)]: - raise s.constructionError(item.startPos, "Wrong tag for string") - elif item.scalarProperties.anchor != yAnchorNone: - raise s.constructionError(item.startPos, "Anchor on non-ref type") - constructObject(s, c, result) - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var seq[T]) = - let item = s.peek() - if item.kind == yamlStartSeq: - if item.seqProperties.tag notin [yTagQuestionMark, yamlTag(seq[T])]: - raise s.constructionError(item.startPos, "Wrong tag for " & typetraits.name(seq[T])) - elif item.seqProperties.anchor != yAnchorNone: - raise s.constructionError(item.startPos, "Anchor on non-ref type") - constructObject(s, c, result) - -proc constructChild*[T](s: var YamlStream, c: ConstructionContext, - result: var Option[T]) = - ## constructs an optional value. A value with a !!null tag will be loaded - ## an empty value. - let event = s.peek() - if event.kind == yamlScalar and event.scalarProperties.tag == yTagNull: - result = none(T) - discard s.next() - else: - var inner: T - constructChild(s, c, inner) - result = some(inner) - -when defined(JS): - # in JS, Time is a ref type. Therefore, we need this specialization so that - # it is not handled by the general ref-type handler. - proc constructChild*(s: var YamlStream, c: ConstructionContext, - result: var Time) = - let e = s.peek() - if e.kind == yamlScalar: - if e.scalarProperties.tag notin [yTagQuestionMark, yTagTimestamp]: - raise s.constructionError(e.startPos, "Wrong tag for Time") - elif guessType(e.scalarContent) != yTypeTimestamp: - raise s.constructionError(e.startPos, "Invalid timestamp") - elif e.scalarProperties.anchor != yAnchorNone: - raise s.constructionError(e.startPos, "Anchor on non-ref type") - constructObject(s, c, result) - else: - raise s.constructionError(e.startPos, "Unexpected structure, expected timestamp") - -proc constructChild*[O](s: var YamlStream, c: ConstructionContext, - result: var ref O) = - var e = s.peek() - if e.kind == yamlScalar: - let props = e.scalarProperties - if props.tag == yTagNull or (props.tag == yTagQuestionMark and - guessType(e.scalarContent) == yTypeNull): - result = nil - discard s.next() - return - elif e.kind == yamlAlias: - let val = c.refs.getOrDefault(e.aliasTarget) - if val.tag != yamlTag(O): - raise constructionError(s, e.startPos, - "alias node refers to object of incompatible type") - result = cast[ref O](val.p) - discard s.next() - return - new(result) - template removeAnchor(anchor: var Anchor) {.dirty.} = - if anchor != yAnchorNone: - yAssert(not c.refs.hasKey(anchor)) - c.refs[anchor] = (yamlTag(O), cast[pointer](result)) - anchor = yAnchorNone - - case e.kind - of yamlScalar: removeAnchor(e.scalarProperties.anchor) - of yamlStartMap: removeAnchor(e.mapProperties.anchor) - of yamlStartSeq: removeAnchor(e.seqProperties.anchor) - else: internalError("Unexpected event kind: " & $e.kind) - s.peek = e - try: constructChild(s, c, result[]) - except YamlConstructionError as e: - raise e - except YamlStreamError as e: - raise e - except Exception: - var e = newException(YamlStreamError, getCurrentExceptionMsg()) - e.parent = getCurrentException() - raise e - -proc representChild*(value: string, ts: TagStyle, c: SerializationContext) = - let tag = presentTag(string, ts) - representObject(value, ts, c, - if tag == yTagQuestionMark and guessType(value) != yTypeUnknown: - yTagExclamationMark - else: - tag) - -proc representChild*[T](value: seq[T], ts: TagStyle, c: SerializationContext) = - representObject(value, ts, c, presentTag(seq[T], ts)) - -proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext) = - if isNil(value): c.put(scalarEvent("~", yTagNull)) - elif c.style == asNone: representChild(value[], ts, c) - else: - var val: tuple[a: Anchor, referenced: bool] - let p = cast[pointer](value) - if c.refs.hasKey(p): - val = c.refs.getOrDefault(p) - yAssert(val.a != yAnchorNone) - if not val.referenced: - c.refs[p] = (val.a, true) - c.put(aliasEvent(val.a)) - return - if c.style != asNone: - val = (c.nextAnchorId.Anchor, false) - c.refs[p] = val - nextAnchor(c.nextAnchorId, len(c.nextAnchorId) - 1) - let - childTagStyle = if ts == tsAll: tsAll else: tsRootOnly - origPut = c.put - c.put = proc(e: Event) = - var ex = e - case ex.kind - of yamlStartMap: - ex.mapProperties.anchor = val.a - if ts == tsNone: ex.mapProperties.tag = yTagQuestionMark - of yamlStartSeq: - ex.seqProperties.anchor = val.a - if ts == tsNone: ex.seqProperties.tag = yTagQuestionMark - of yamlScalar: - ex.scalarProperties.anchor = val.a - if ts == tsNone and guessType(ex.scalarContent) != yTypeNull: - ex.scalarProperties.tag = yTagQuestionMark - else: discard - c.put = origPut - c.put(ex) - representChild(value[], childTagStyle, c) - -proc representChild*[T](value: Option[T], ts: TagStyle, - c: SerializationContext) = - ## represents an optional value. If the value is missing, a !!null scalar - ## will be produced. - if value.isSome: - representChild(value.get(), ts, c) - else: - c.put(scalarEvent("~", yTagNull)) - -proc representChild*[O](value: O, ts: TagStyle, - c: SerializationContext) = - when isImplicitVariantObject(O): - # todo: this would probably be nicer if constructed with a macro - var count = 0 - for name, field in fieldPairs(value): - if count > 0: - representChild(field, if ts == tsAll: tsAll else: tsRootOnly, c) - inc(count) - if count == 1: c.put(scalarEvent("~", yTagNull)) - else: - representObject(value, ts, c, - if ts == tsNone: yTagQuestionMark else: yamlTag(O)) - -proc construct*[T](s: var YamlStream, target: var T) - {.raises: [YamlStreamError, YamlConstructionError].} = - ## Constructs a Nim value from a YAML stream. - var context = newConstructionContext() - try: - var e = s.next() - yAssert(e.kind == yamlStartDoc) - - constructChild(s, context, target) - e = s.next() - yAssert(e.kind == yamlEndDoc) - except YamlConstructionError: - raise (ref YamlConstructionError)(getCurrentException()) - except YamlStreamError: - raise (ref YamlStreamError)(getCurrentException()) - except Exception: - # may occur while calling s() - var ex = newException(YamlStreamError, "") - ex.parent = getCurrentException() - raise ex - -proc load*[K](input: Stream | string, target: var K) - {.raises: [YamlConstructionError, IOError, OSError, YamlParserError].} = - ## Loads a Nim value from a YAML character stream. - try: - var - parser = initYamlParser() - events = parser.parse(input) - e = events.next() - yAssert(e.kind == yamlStartStream) - construct(events, target) - e = events.next() - if e.kind != yamlEndStream: - var ex = (ref YamlConstructionError)( - mark: e.startPos, msg: "stream contains multiple documents") - discard events.getLastTokenContext(ex.lineContent) - raise ex - except YamlStreamError: - let e = (ref YamlStreamError)(getCurrentException()) - if e.parent of IOError: raise (ref IOError)(e.parent) - if e.parent of OSError: raise (ref OSError)(e.parent) - elif e.parent of YamlParserError: raise (ref YamlParserError)(e.parent) - else: internalError("Unexpected exception: " & $e.parent.name) - -proc loadAs*[K](input: string): K {.raises: - [YamlConstructionError, IOError, OSError, YamlParserError].} = - ## Loads the given YAML input to a value of the type K and returns it - load(input, result) - -proc loadMultiDoc*[K](input: Stream | string, target: var seq[K]) = - var - parser = initYamlParser() - events = parser.parse(input) - e = events.next() - yAssert(e.kind == yamlStartStream) - try: - while events.peek().kind == yamlStartDoc: - var item: K - construct(events, item) - target.add(item) - e = events.next() - yAssert(e.kind == yamlEndStream) - except YamlConstructionError: - var e = (ref YamlConstructionError)(getCurrentException()) - discard events.getLastTokenContext(e.lineContent) - raise e - except YamlStreamError: - let e = (ref YamlStreamError)(getCurrentException()) - if e.parent of IOError: raise (ref IOError)(e.parent) - elif e.parent of OSError: raise (ref OSError)(e.parent) - elif e.parent of YamlParserError: raise (ref YamlParserError)(e.parent) - else: internalError("Unexpected exception: " & $e.parent.name) - -proc represent*[T](value: T, ts: TagStyle = tsRootOnly, - a: AnchorStyle = asTidy, - handles: seq[tuple[handle, uriPrefix: string]] = - @[("!n!", nimyamlTagRepositoryPrefix)]): YamlStream = - ## Represents a Nim value as ``YamlStream`` - var - bys = newBufferYamlStream() - context = newSerializationContext(a, proc(e: Event) = bys.put(e)) - bys.put(startStreamEvent()) - bys.put(startDocEvent(handles = handles)) - representChild(value, ts, context) - bys.put(endDocEvent()) - bys.put(endStreamEvent()) - if a == asTidy: - var ctx = initAnchorContext() - for item in bys.mitems(): - case item.kind - of yamlStartMap: ctx.process(item.mapProperties, context.refs) - of yamlStartSeq: ctx.process(item.seqProperties, context.refs) - of yamlScalar: ctx.process(item.scalarProperties, context.refs) - of yamlAlias: item.aliasTarget = ctx.map(item.aliasTarget) - else: discard - result = bys - -proc dump*[K](value: K, target: Stream, tagStyle: TagStyle = tsRootOnly, - anchorStyle: AnchorStyle = asTidy, - options: PresentationOptions = defaultPresentationOptions, - handles: seq[tuple[handle, uriPrefix: string]] = - @[("!n!", nimyamlTagRepositoryPrefix)]) - {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, - YamlSerializationError].} = - ## Dump a Nim value as YAML character stream. - ## To prevent %TAG directives in the output, give ``handles = @[]``. - var events = represent(value, - if options.style == psCanonical: tsAll else: tagStyle, - if options.style == psJson: asNone else: anchorStyle, handles) - try: present(events, target, options) - except YamlStreamError: - internalError("Unexpected exception: " & $getCurrentException().name) - -proc dump*[K](value: K, tagStyle: TagStyle = tsRootOnly, - anchorStyle: AnchorStyle = asTidy, - options: PresentationOptions = defaultPresentationOptions, - handles: seq[tuple[handle, uriPrefix: string]] = - @[("!n!", nimyamlTagRepositoryPrefix)]): - string {.raises: [YamlPresenterJsonError, YamlPresenterOutputError, - YamlSerializationError].} = - ## Dump a Nim value as YAML into a string. - ## To prevent %TAG directives in the output, give ``handles = @[]``. - var events = represent(value, - if options.style == psCanonical: tsAll else: tagStyle, - if options.style == psJson: asNone else: anchorStyle, handles) - try: result = present(events, options) - except YamlStreamError: - internalError("Unexpected exception: " & $getCurrentException().name) diff --git a/lib/yaml/yaml/stream.nim b/lib/yaml/yaml/stream.nim deleted file mode 100644 index 73da22a..0000000 --- a/lib/yaml/yaml/stream.nim +++ /dev/null @@ -1,142 +0,0 @@ - # NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================== -## Module yaml/stream -## ================== -## -## The stream API provides the basic data structure on which all low-level APIs -## operate. It is not named ``streams`` to not confuse it with the modle in the -## stdlib with that name. - -import data - -when defined(nimNoNil): - {.experimental: "notnil".} - -type - 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 - ## ``yamlStartSeq`` is terminated by a ``yamlEndSeq`` and every - ## ``yamlStartDoc`` is terminated by a ``yamlEndDoc``. Moreover, every - ## emitted mapping has an even number of children. - ## - ## The creator of a ``YamlStream`` is responsible for it being - ## well-formed. A user of the stream may assume that it is well-formed - ## 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. - nextImpl*: proc(s: YamlStream, e: var Event): bool {.gcSafe.} - lastTokenContextImpl*: - proc(s: YamlStream, lineContent: var string): bool {.raises: [].} - peeked: bool - cached: Event - - YamlStreamError* = object of ValueError - ## Exception that may be raised by a ``YamlStream`` when the underlying - ## backend raises an exception. The error that has occurred is - ## available from ``parent``. - -proc noLastContext(s: YamlStream, lineContent: var string): bool {.raises: [].} = - result = false - -proc basicInit*(s: YamlStream, lastTokenContextImpl: - proc(s: YamlStream, lineContent: var string): bool - {.raises: [].} = noLastContext) {.raises: [].} = - ## initialize basic values of the YamlStream. Call this in your constructor - ## if you subclass YamlStream. - s.peeked = false - s.lastTokenContextImpl = lastTokenContextImpl - -when not defined(JS): - type IteratorYamlStream = ref object of YamlStream - backend: iterator(): Event {.gcSafe.} - - proc initYamlStream*(backend: iterator(): Event {.gcSafe.}): YamlStream - {.raises: [].} = - ## Creates a new ``YamlStream`` that uses the given iterator as backend. - result = new(IteratorYamlStream) - result.basicInit() - IteratorYamlStream(result).backend = backend - result.nextImpl = proc(s: YamlStream, e: var Event): bool {.gcSafe.} = - e = IteratorYamlStream(s).backend() - result = true - -type - BufferYamlStream* = ref object of YamlStream - pos: int - buf: seq[Event] - -proc newBufferYamlStream*(): BufferYamlStream not nil = - result = cast[BufferYamlStream not nil](new(BufferYamlStream)) - result.basicInit() - result.buf = @[] - result.pos = 0 - result.nextImpl = proc(s: YamlStream, e: var Event): bool = - let bys = BufferYamlStream(s) - e = bys.buf[bys.pos] - inc(bys.pos) - result = true - -proc put*(bys: BufferYamlStream, e: Event) {.raises: [].} = - bys.buf.add(e) - -proc next*(s: YamlStream): Event {.raises: [YamlStreamError], gcSafe.} = - ## 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. - if s.peeked: - s.peeked = false - return move(s.cached) - else: - try: - while true: - if s.nextImpl(s, result): break - except YamlStreamError: - raise (ref YamlStreamError)(getCurrentException()) - except Exception: - let cur = getCurrentException() - var e = newException(YamlStreamError, cur.msg) - e.parent = cur - raise e - -proc peek*(s: YamlStream): Event {.raises: [YamlStreamError].} = - ## Get the next item of the stream without advancing the stream. - ## Requires ``finished(s) == true``. Handles exceptions of the backend like - ## ``next()``. - if not s.peeked: - s.cached = s.next() - s.peeked = true - shallowCopy(result, s.cached) - -proc `peek=`*(s: YamlStream, value: Event) {.raises: [].} = - ## Set the next item of the stream. Will replace a previously peeked item, - ## if one exists. - s.cached = value - s.peeked = true - -proc getLastTokenContext*(s: YamlStream, lineContent: var string): bool = - ## ``true`` if source context information is available about the last returned - ## token. If ``true``, line, column and lineContent are set to position and - ## line content where the last token has been read from. - result = s.lastTokenContextImpl(s, lineContent) - -iterator items*(s: YamlStream): Event - {.raises: [YamlStreamError].} = - ## Iterate over all items of the stream. You may not use ``peek()`` on the - ## stream while iterating. - while true: - let e = s.next() - var last = e.kind == yamlEndStream - yield e - if last: break - -iterator mitems*(bys: BufferYamlStream): var Event {.raises: [].} = - ## Iterate over all items of the stream. You may not use ``peek()`` on the - ## stream while iterating. - for e in bys.buf.mitems(): yield e diff --git a/lib/yaml/yaml/taglib.nim b/lib/yaml/yaml/taglib.nim deleted file mode 100644 index 3d49162..0000000 --- a/lib/yaml/yaml/taglib.nim +++ /dev/null @@ -1,83 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================== -## Module yaml/taglib -## ================== -## -## The taglib API enables you to define custom tags for the types you are -## using with the serialization API. - -import macros -import data - -template n(suffix: string): Tag = Tag(nimyamlTagRepositoryPrefix & suffix) - -var - registeredUris {.compileTime.} = newSeq[string]() ## \ - ## Since Table doesn't really work at compile time, we also store - ## registered URIs here to be able to generate a static compiler error - ## when the user tries to register an URI more than once. - -template setTag*(t: typedesc, tag: Tag) = - ## Associate the given uri with a certain type. This uri is used as YAML tag - ## when loading and dumping values of this type. - when $tag in registeredUris: - {. fatal: "[NimYAML] URI \"" & uri & "\" registered twice!" .} - const tconst {.genSym.} = tag - static: - registeredUris.add($tag) - proc yamlTag*(T: typedesc[t]): Tag {.inline, raises: [].} = tconst - ## autogenerated - -template setTag*(t: typedesc, tag: Tag, idName: untyped) = - ## Like `setTagUri <#setTagUri.t,typedesc,string>`_, but lets - ## you choose a symbol for the `TagId <#TagId>`_ of the uri. This is only - ## necessary if you want to implement serialization / construction yourself. - when $tag in registeredUris: - {. fatal: "[NimYAML] URI \"" & uri & "\" registered twice!" .} - const idName* = tag - static: - registeredUris.add($tag) - proc yamlTag*(T: typedesc[t]): Tag {.inline, raises: [].} = idName - ## autogenerated - -template setTagUri*(t: typedesc; uri: string) {.deprecated: "use setTag".} = - setTag(t, Tag(uri)) -template setTagUri*(t: typedesc; uri: string; idName: untyped) - {.deprecated: "use setTag".} = setTag(t, Tag(uri), idName) - -static: - # standard YAML tags used by serialization - registeredUris.add($yTagExclamationMark) - registeredUris.add($yTagQuestionMark) - registeredUris.add($yTagString) - registeredUris.add($yTagNull) - registeredUris.add($yTagBoolean) - registeredUris.add($yTagFloat) - registeredUris.add($yTagTimestamp) - registeredUris.add($yTagValue) - registeredUris.add($yTagBinary) - # special tags used by serialization - registeredUris.add($yTagNimField) - -# tags for Nim's standard types -setTag(char, n"system:char", yTagNimChar) -setTag(int8, n"system:int8", yTagNimInt8) -setTag(int16, n"system:int16", yTagNimInt16) -setTag(int32, n"system:int32", yTagNimInt32) -setTag(int64, n"system:int64", yTagNimInt64) -setTag(uint8, n"system:uint8", yTagNimUInt8) -setTag(uint16, n"system:uint16", yTagNimUInt16) -setTag(uint32, n"system:uint32", yTagNimUInt32) -setTag(uint64, n"system:uint64", yTagNimUInt64) -setTag(float32, n"system:float32", yTagNimFloat32) -setTag(float64, n"system:float64", yTagNimFloat64) - -proc nimTag*(suffix: string): Tag = - ## prepends NimYAML's tag repository prefix to the given suffix. For example, - ## ``nimTag("system:char")`` yields ``"tag:nimyaml.org,2016:system:char"``. - Tag(nimyamlTagRepositoryPrefix & suffix) diff --git a/lib/yaml/yaml/tojson.nim b/lib/yaml/yaml/tojson.nim deleted file mode 100644 index 83caec1..0000000 --- a/lib/yaml/yaml/tojson.nim +++ /dev/null @@ -1,213 +0,0 @@ -# NimYAML - YAML implementation in Nim -# (c) Copyright 2016 Felix Krause -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. - -## ================== -## Module yaml/tojson -## ================== -## -## The tojson API enables you to parser a YAML character stream into the JSON -## structures provided by Nim's stdlib. - -import json, streams, strutils, tables -import data, hints, serialization, stream, private/internal, parser - -# represents a single YAML level. The `node` with name `key`. -# `expKey` is used to indicate that an empty node shall be filled -type Level = tuple[node: JsonNode, key: string, expKey: bool] - -proc initLevel(node: JsonNode): Level {.raises: [].} = - (node: node, key: "", expKey: true) - -proc jsonFromScalar(content: string, tag: Tag): JsonNode - {.raises: [YamlConstructionError].}= - new(result) - var mappedType: TypeHint - - case tag - of yTagQuestionMark: mappedType = guessType(content) - of yTagExclamationMark, yTagString: mappedType = yTypeUnknown - of yTagBoolean: - case guessType(content) - of yTypeBoolTrue: mappedType = yTypeBoolTrue - of yTypeBoolFalse: mappedType = yTypeBoolFalse - else: - raise newException(YamlConstructionError, - "Invalid boolean value: " & content) - of yTagInteger: mappedType = yTypeInteger - of yTagNull: mappedType = yTypeNull - of yTagFloat: - case guessType(content) - of yTypeFloat: mappedType = yTypeFloat - of yTypeFloatInf: mappedType = yTypeFloatInf - of yTypeFloatNaN: mappedType = yTypeFloatNaN - else: - raise newException(YamlConstructionError, - "Invalid float value: " & content) - else: mappedType = yTypeUnknown - - try: - case mappedType - of yTypeInteger: - result = JsonNode(kind: JInt, num: parseBiggestInt(content)) - of yTypeFloat: - result = JsonNode(kind: JFloat, fnum: parseFloat(content)) - of yTypeFloatInf: - result = JsonNode(kind: JFloat, fnum: if content[0] == '-': NegInf else: Inf) - of yTypeFloatNaN: - result = JsonNode(kind: JFloat, fnum: NaN) - of yTypeBoolTrue: - result = JsonNode(kind: JBool, bval: true) - of yTypeBoolFalse: - result = JsonNode(kind: JBool, bval: false) - of yTypeNull: - result = JsonNode(kind: JNull) - else: - result = JsonNode(kind: JString) - shallowCopy(result.str, content) - except ValueError: - var e = newException(YamlConstructionError, "Cannot parse numeric value") - e.parent = getCurrentException() - raise e - -proc constructJson*(s: var YamlStream): seq[JsonNode] - {.raises: [YamlConstructionError, YamlStreamError].} = - ## Construct an in-memory JSON tree from a YAML event stream. The stream may - ## not contain any tags apart from those in ``coreTagLibrary``. Anchors and - ## aliases will be resolved. Maps in the input must not contain - ## non-scalars as keys. Each element of the result represents one document - ## in the YAML stream. - ## - ## **Warning:** The special float values ``[+-]Inf`` and ``NaN`` will be - ## parsed into Nim's JSON structure without error. However, they cannot be - ## rendered to a JSON character stream, because these values are not part - ## of the JSON specification. Nim's JSON implementation currently does not - ## check for these values and will output invalid JSON when rendering one - ## of these values into a JSON character stream. - newSeq(result, 0) - - var - levels = newSeq[Level]() - anchors = initTable[Anchor, JsonNode]() - for event in s: - case event.kind - of yamlStartStream, yamlEndStream: discard - of yamlStartDoc: - # we don't need to do anything here; root node will be created - # by first scalar, sequence or map event - discard - of yamlEndDoc: - # we can savely assume that levels has e length of exactly 1. - result.add(levels.pop().node) - of yamlStartSeq: - levels.add(initLevel(newJArray())) - if event.seqProperties.anchor != yAnchorNone: - anchors[event.seqProperties.anchor] = levels[levels.high].node - of yamlStartMap: - levels.add(initLevel(newJObject())) - if event.mapProperties.anchor != yAnchorNone: - anchors[event.mapProperties.anchor] = levels[levels.high].node - of yamlScalar: - if levels.len == 0: - # parser ensures that next event will be yamlEndDocument - levels.add((node: jsonFromScalar(event.scalarContent, - event.scalarProperties.tag), - key: "", - expKey: true)) - continue - - case levels[levels.high].node.kind - of JArray: - let jsonScalar = jsonFromScalar(event.scalarContent, - event.scalarProperties.tag) - levels[levels.high].node.elems.add(jsonScalar) - if event.scalarProperties.anchor != yAnchorNone: - anchors[event.scalarProperties.anchor] = jsonScalar - of JObject: - if levels[levels.high].expKey: - levels[levels.high].expKey = false - # JSON only allows strings as keys - levels[levels.high].key = event.scalarContent - if event.scalarProperties.anchor != yAnchorNone: - raise newException(YamlConstructionError, - "scalar keys may not have anchors in JSON") - else: - let jsonScalar = jsonFromScalar(event.scalarContent, - event.scalarProperties.tag) - levels[levels.high].node[levels[levels.high].key] = jsonScalar - levels[levels.high].expKey = true - if event.scalarProperties.anchor != yAnchorNone: - anchors[event.scalarProperties.anchor] = jsonScalar - else: - internalError("Unexpected node kind: " & $levels[levels.high].node.kind) - of yamlEndSeq, yamlEndMap: - if levels.len > 1: - let level = levels.pop() - case levels[levels.high].node.kind - of JArray: levels[levels.high].node.elems.add(level.node) - of JObject: - if levels[levels.high].expKey: - raise newException(YamlConstructionError, - "non-scalar as key not allowed in JSON") - else: - levels[levels.high].node[levels[levels.high].key] = level.node - levels[levels.high].expKey = true - else: - internalError("Unexpected node kind: " & - $levels[levels.high].node.kind) - else: discard # wait for yamlEndDocument - of yamlAlias: - # we can savely assume that the alias exists in anchors - # (else the parser would have already thrown an exception) - case levels[levels.high].node.kind - of JArray: - levels[levels.high].node.elems.add( - anchors.getOrDefault(event.aliasTarget)) - of JObject: - if levels[levels.high].expKey: - raise newException(YamlConstructionError, - "cannot use alias node as key in JSON") - else: - levels[levels.high].node.fields[ - levels[levels.high].key] = anchors.getOrDefault(event.aliasTarget) - levels[levels.high].expKey = true - else: - internalError("Unexpected node kind: " & $levels[levels.high].node.kind) - -when not defined(JS): - proc loadToJson*(s: Stream): seq[JsonNode] - {.raises: [YamlParserError, YamlConstructionError, IOError, OSError].} = - ## Uses `YamlParser <#YamlParser>`_ and - ## `constructJson <#constructJson>`_ to construct an in-memory JSON tree - ## from a YAML character stream. - var parser: YamlParser - parser.init() - var events = parser.parse(s) - try: - return constructJson(events) - except YamlStreamError: - let e = getCurrentException() - if e.parent of IOError: - raise (ref IOError)(e.parent) - elif e.parent of OSError: - raise (ref OSError)(e.parent) - elif e.parent of YamlParserError: - raise (ref YamlParserError)(e.parent) - else: internalError("Unexpected exception: " & e.parent.repr) - -proc loadToJson*(str: string): seq[JsonNode] - {.raises: [YamlParserError, YamlConstructionError].} = - ## Uses `YamlParser <#YamlParser>`_ and - ## `constructJson <#constructJson>`_ to construct an in-memory JSON tree - ## from a YAML character stream. - var parser: YamlParser - parser.init() - var events = parser.parse(str) - try: return constructJson(events) - except YamlStreamError: - let e = getCurrentException() - if e.parent of YamlParserError: - raise (ref YamlParserError)(e.parent) - else: internalError("Unexpected exception: " & e.parent.repr) diff --git a/nim.cfg b/nim.cfg index 675c574..cddb52b 100644 --- a/nim.cfg +++ b/nim.cfg @@ -1,6 +1,4 @@ -path = "$projectPath/lib/yaml/" ---path:"./lib/yaml/" --opt:speed -d:release -d:useLibzipSrc ---gc:refc +--gc:orc # ORC is default in Nim 2.0, required for NimYAML 2.x DOM API diff --git a/qax.nimble b/qax.nimble index 063507d..78283fe 100644 --- a/qax.nimble +++ b/qax.nimble @@ -1,11 +1,11 @@ # Package -version = "0.9.8" +version = "1.0.0" author = "Andrea Telatin" description = "Qiime Artifact eXtractor" license = "Apache" # Dependencies -requires "nim >= 1.2", "docopt", "terminaltables", "zip", "uuids" +requires "nim >= 2.0.0", "docopt", "terminaltables", "zip", "uuids", "yaml >= 2.0.0" srcDir = "src" diff --git a/src/make.nim b/src/make.nim index d9832ca..a7ce16d 100644 --- a/src/make.nim +++ b/src/make.nim @@ -99,7 +99,7 @@ format: {artifactAttributes.format}""" & "\n" & artifactAttributes.append createDir(tempUUID) else: try: - removeDir(tempUUID): + removeDir(tempUUID) except Exception as e: stderr.writeLine(fmt"Unable to remove temporary directory {tempUUID}: {e.msg}") return false diff --git a/src/provenance.nim b/src/provenance.nim index 55a547f..871aace 100644 --- a/src/provenance.nim +++ b/src/provenance.nim @@ -46,8 +46,9 @@ proc getChildType(inputFile, childId, parentId, parentType: string): string = try: let child = readFileFromZip(inputFile, metadataPath) - let meta = loadDom(child) - return meta.root["format"].content + var meta: YamlNode + load(child, meta) + return meta["format"].content except Exception as e: stderr.writeLine("Warning: unable to find metadata for: ", childId) return "" @@ -99,19 +100,20 @@ Options: # Parse child metadata / action let childYaml = joinPath(art.uuid, joinPath("provenance", joinPath(joinPath("action", "action.yaml")))) let child = readFileFromZip($args[""], childYaml) - let childMeta = loadDom(child) + var childMeta: YamlNode + load(child, childMeta) var inputSeq = newSeq[string]() - echo childMeta.root["action"]["plugin"].content - - + echo childMeta["action"]["plugin"].content + + try: - let inputs = childMeta.root["action"]["inputs"] + let inputs = childMeta["action"]["inputs"] for node in inputs.items: for i in node.pairs: inputSeq.add(i.value.content) dotEdges &= makeEdge(art.uuid, i.value.content, "?") - let parents = childMeta.root["action"]["parameters"] + let parents = childMeta["action"]["parameters"] for node in parents.items: for i in node.pairs: if i.key.content == "input": @@ -122,11 +124,11 @@ Options: quit(1) try: - actionType[art.uuid] = childMeta.root["action"]["output-name"].content + actionType[art.uuid] = childMeta["action"]["output-name"].content except: actionType[art.uuid] = "" - Family.add((uuid: art.uuid, rank: "child", actionName: "", timestamp: parseStamp(childMeta.root["execution"]["runtime"]["start"].content), inputs: inputSeq)) + Family.add((uuid: art.uuid, rank: "child", actionName: "", timestamp: parseStamp(childMeta["execution"]["runtime"]["start"].content), inputs: inputSeq)) # Parse actions for all parents for parent in art.parents: @@ -137,16 +139,17 @@ Options: let proveYaml = joinPath(art.uuid, joinPath("provenance/artifacts", joinPath(parent, joinPath("action", "action.yaml")))) let yaml = readFileFromZip($args[""], proveYaml) - let metaYaml = loadDOM(yaml) - + var metaYaml: YamlNode + load(yaml, metaYaml) + try: - pluginActionName = metaYaml.root["action"]["plugin"].content + pluginActionName = metaYaml["action"]["plugin"].content except Exception as e: rank = "top" inputSeq.add("") try: - let inputs = metaYaml.root["action"]["inputs"] + let inputs = metaYaml["action"]["inputs"] for node in inputs.items: for i in node.pairs: dotNodes &= makeEdge(parent, i.value.content, i.key.content) @@ -155,7 +158,7 @@ Options: except Exception as e: rank = "top" - Family.add((uuid: parent, rank: rank, actionName: pluginActionName, timestamp: parseStamp(metaYaml.root["execution"]["runtime"]["start"].content), inputs: inputSeq)) + Family.add((uuid: parent, rank: rank, actionName: pluginActionName, timestamp: parseStamp(metaYaml["execution"]["runtime"]["start"].content), inputs: inputSeq)) Family = Family.sortedByIt(it.timestamp) diff --git a/src/qax_utils.nim b/src/qax_utils.nim index 0e5fa0c..6f2fc57 100644 --- a/src/qax_utils.nim +++ b/src/qax_utils.nim @@ -184,20 +184,23 @@ proc readArtifact*(path: string): QiimeArtifact = versionLines = version.split("\n") versionLines.delete(0) #Remove first line QIIME2 - let - metaYaml = loadDOM(metadata) - versionYaml = loadDOM(versionLines.join("\n")) + var + metaYaml: YamlNode + versionYaml: YamlNode + + load(metadata, metaYaml) + load(versionLines.join("\n"), versionYaml) try: - result.version = versionYaml.root["framework"].content - result.archive = versionYaml.root["archive"].content + result.version = versionYaml["framework"].content + result.archive = versionYaml["archive"].content except Exception as e: stderr.writeLine("Unable to parse Artifact version: ", e.msg) try: - result.artifacttype = metaYaml.root["type"].content + result.artifacttype = metaYaml["type"].content result.format = if result.artifacttype == "Visualization" : "HTML" - else: metaYaml.root["format"].content + else: metaYaml["format"].content except Exception as e: stderr.writeLine("Unable to parse Artifact metadata.yaml: ", e.msg)