mirror of https://github.com/status-im/NimYAML.git
Added setTagUriForType. Used it. Improved docs.
This commit is contained in:
parent
8d472d3278
commit
02e505959a
209
README.md
209
README.md
|
@ -1,213 +1,11 @@
|
|||
# NimYAML - YAML implementation for Nim
|
||||
|
||||
NimYAML is a YAML implementation in Nim. It aims to implement the complete
|
||||
YAML 1.2 specification and has a streaming interface that makes it possible to
|
||||
parse YAML input sequentially, without loading all data into memory at once. It
|
||||
is able to automatically serialize Nim object to YAML and deserialize them
|
||||
again.
|
||||
|
||||
**Attention**: NimYAML is work in progress. There is no release yet, and some
|
||||
features are highly experimental.
|
||||
|
||||
## Quickstart
|
||||
|
||||
### Using the sequential parser
|
||||
|
||||
```Nimrod
|
||||
import yaml
|
||||
|
||||
let input = """
|
||||
an integer: 42
|
||||
a boolean: yes
|
||||
a list:
|
||||
- 3.14159
|
||||
- !!str 23
|
||||
- null
|
||||
"""
|
||||
|
||||
var
|
||||
parser = newYamlParser(initCoreTagLibrary())
|
||||
events = parser.parse(newStringStream(input))
|
||||
|
||||
for event in events():
|
||||
echo $event
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
yamlStartDocument()
|
||||
yamlStartMap(tag=?)
|
||||
yamlScalar(tag=?, typeHint=yTypeUnknown, content="an integer")
|
||||
yamlScalar(tag=?, typeHint=yTypeInteger, content="42")
|
||||
yamlScalar(tag=?, typeHint=yTypeUnknown, content="a boolean")
|
||||
yamlScalar(tag=?, typeHint=yTypeBoolTrue, content="yes")
|
||||
yamlScalar(tag=?, typeHint=yTypeUnknown, content="a list")
|
||||
yamlStartSequence(tag=?)
|
||||
yamlScalar(tag=?, typeHint=yTypeFloat, content="3.14159")
|
||||
yamlScalar(tag=!!str, typeHint=yTypeInteger, content="23")
|
||||
yamlScalar(tag=?, typeHint=yTypeNull, content="null")
|
||||
yamlEndSequence()
|
||||
yamlEndMap()
|
||||
yamlEndDocument()
|
||||
```
|
||||
|
||||
### Dumping YAML
|
||||
|
||||
```Nimrod
|
||||
import yaml, streams
|
||||
|
||||
proc example(): YamlStream =
|
||||
result = iterator(): YamlStreamEvent =
|
||||
yield startDocEvent()
|
||||
yield startMapEvent()
|
||||
yield scalarEvent("an integer")
|
||||
yield scalarEvent("42", tag = yTagInteger)
|
||||
yield scalarEvent("a list")
|
||||
yield startSeqEvent(tag = yTagSequence)
|
||||
yield scalarEvent("item", tag = yTagString)
|
||||
yield scalarEvent("no", tag = yTagBoolean)
|
||||
yield scalarEvent("")
|
||||
yield endSeqEvent()
|
||||
yield scalarEvent("a float")
|
||||
yield scalarEvent("3.14159", tag = yTagFloat)
|
||||
yield endMapEvent()
|
||||
yield endDocEvent()
|
||||
|
||||
present(example(), newFileStream(stdout), initCoreTagLibrary(), psBlockOnly)
|
||||
echo "\n\n"
|
||||
present(example(), newFileStream(stdout), initCoreTagLibrary(), psCanonical)
|
||||
echo "\n\n"
|
||||
present(example(), newFileStream(stdout), initCoreTagLibrary(), psJson)
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
%YAML 1.2
|
||||
---
|
||||
an integer: !!int 42
|
||||
a list: !!seq
|
||||
- !!str item
|
||||
- !!bool no
|
||||
- ""
|
||||
a float: !!float 3.14159
|
||||
|
||||
|
||||
%YAML 1.2
|
||||
---
|
||||
{
|
||||
? "an integer"
|
||||
: !!int "42",
|
||||
? "a list"
|
||||
: !!seq [
|
||||
!!str "item",
|
||||
!!bool "no",
|
||||
""
|
||||
],
|
||||
? "a float"
|
||||
: !!float "3.14159"
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
"an integer": 42,
|
||||
"a list": [
|
||||
"item",
|
||||
false,
|
||||
""
|
||||
],
|
||||
"a float": 3.14159
|
||||
}
|
||||
```
|
||||
|
||||
### Using Nim Type Serialization
|
||||
|
||||
**Attention**: This feature is highly experimental!
|
||||
|
||||
```Nimrod
|
||||
import yaml.serialization
|
||||
import tables
|
||||
|
||||
serializable:
|
||||
type
|
||||
Person = object
|
||||
firstname, surname: string
|
||||
age: int32
|
||||
additionalAttributes: Table[string, string]
|
||||
|
||||
# loading
|
||||
|
||||
let input = """
|
||||
-
|
||||
firstname: Peter
|
||||
surname: Pan
|
||||
age: 12
|
||||
additionalAttributes:
|
||||
canFly: yes
|
||||
location: Neverland
|
||||
-
|
||||
firstname: Karl
|
||||
surname: Koch
|
||||
age: 23
|
||||
additionalAttributes:
|
||||
location: Celle
|
||||
occupation: Hacker
|
||||
"""
|
||||
|
||||
var persons: seq[Person]
|
||||
load(newStringStream(input), persons)
|
||||
assert persons[0].surname == "Pan"
|
||||
assert persons[1].additionalAttributes["location"] == "Celle"
|
||||
|
||||
# dumping
|
||||
|
||||
dump(persons, newFileStream(stdout), psCanonical)
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
%YAML 1.2
|
||||
--- !nim:seq(nim:Person)
|
||||
[
|
||||
!nim:Person {
|
||||
? !!str "firstname"
|
||||
: !!str "Peter",
|
||||
? !!str "surname"
|
||||
: !!str "Pan",
|
||||
? !!str "age"
|
||||
: !nim:int "12",
|
||||
? !!str "additionalAttributes"
|
||||
: !nim:Table(tag:yaml.org,2002:str,tag:yaml.org,2002:str) {
|
||||
? !!str "canFly"
|
||||
: !!str "yes",
|
||||
? !!str "location"
|
||||
: !!str "Neverland"
|
||||
}
|
||||
},
|
||||
!nim:Person {
|
||||
? !!str "firstname"
|
||||
: !!str "Karl",
|
||||
? !!str "surname"
|
||||
: !!str "Koch",
|
||||
? !!str "age"
|
||||
: !nim:int "23",
|
||||
? !!str "additionalAttributes"
|
||||
: !nim:Table(tag:yaml.org,2002:str,tag:yaml.org,2002:str) {
|
||||
? !!str "occupation"
|
||||
: !!str "Hacker",
|
||||
? !!str "location"
|
||||
: !!str "Celle"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
NimYAML is currently being developed. There is no release yet. See
|
||||
[the documentation](http://flyx.github.io/NimYAML/) for an overview of already
|
||||
available features.
|
||||
|
||||
## TODO list
|
||||
|
||||
* Documentation:
|
||||
- Document yaml.serialization
|
||||
* Misc:
|
||||
- Add type hints for more scalar types
|
||||
* Serialization:
|
||||
|
@ -216,7 +14,6 @@ Output:
|
|||
- Support variant objects
|
||||
- Support transient fields (i.e. fields that will not be (de-)serialized on
|
||||
objects and tuples)
|
||||
- Make it possible for user to define a tag URI for custom types
|
||||
- Use `concept` type class `Serializable` or something
|
||||
- Check for and avoid name clashes when generating local tags for custom
|
||||
object types.
|
||||
|
|
|
@ -22,6 +22,7 @@ task documentation, "Generate documentation":
|
|||
exec "mkdir -p docout"
|
||||
exec r"nim doc2 -o:docout/yaml.html --docSeeSrcUrl:https://github.com/flyx/NimYAML/blob/`git log -n 1 --format=%H` yaml"
|
||||
exec r"nim rst2html -o:docout/index.html doc/index.txt"
|
||||
exec r"nim rst2html -o:docout/api.html doc/api.txt"
|
||||
exec "cp doc/docutils.css doc/style.css doc/testing.html doc/processing.svg docout"
|
||||
setCommand "nop"
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
===
|
||||
API
|
||||
===
|
||||
|
||||
Overview
|
||||
========
|
||||
|
||||
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 <yaml.html#YamlStream>`_. This is basically an iterator over
|
||||
`YamlStreamEvent <yaml.html#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 <yaml.html#load,Stream,K>`_. This is the easiest and recommended
|
||||
way to load YAML data. The following paragraphs will explain the steps involved.
|
||||
|
||||
For parsing, a `YamlParser <yaml.html#YamlParser>`_ object is needed. This
|
||||
object stores some state while parsing that may be useful for error reporting to
|
||||
the user. The
|
||||
`parse <yaml.html#present,YamlStream,Stream,TagLibrary,PresentationStyle,int>`_
|
||||
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 <yaml.html#dump,K,Stream,PresentationStyle,TagStyle,AnchorStyle,int>`_,
|
||||
which serializes a native Nim variable to a character stream. Like ``load``, you
|
||||
can use the steps involved separately.
|
||||
|
||||
You transform a variable into a ``YamlStream`` with
|
||||
`represent <yaml.html#represent,T,TagStyle,AnchorStyle>`_. 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 <yaml.html#present,YamlStream,Stream,TagLibrary,PresentationStyle,int>`_.
|
||||
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.
|
|
@ -70,78 +70,3 @@ NimYAML's features.
|
|||
of other: echo "child: ", child.name
|
||||
echo "------------------------"
|
||||
dump(persons, newFileStream(stdout))
|
||||
|
||||
API Overview
|
||||
============
|
||||
|
||||
NimYAML advocates parsing YAML input into native Nim types. Basic 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 <yaml.html#YamlStream>`_. This is basically an iterator over
|
||||
`YamlStreamEvent <yaml.html#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
|
||||
------------
|
||||
|
||||
For parsing, a `YamlParser <yaml.html#YamlParser>`_ object is needed. This
|
||||
object stores some state while parsing that may be useful for error reporting to
|
||||
the user. The
|
||||
`parse <yaml.html#present,YamlStream,Stream,TagLibrary,PresentationStyle,int>`_
|
||||
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.
|
||||
|
||||
If you want to load YAML character data directly into a native Nim variable, you
|
||||
can use `load <yaml.html#load,Stream,K>`_.
|
||||
|
||||
Dumping YAML
|
||||
------------
|
||||
|
||||
Dumping YAML is straightforward: You transform a variable into a ``YamlStream``
|
||||
with `represent <yaml.html#represent,T,TagStyle,AnchorStyle>`_ and then write
|
||||
that to a stream using
|
||||
`present <yaml.html#present,YamlStream,Stream,TagLibrary,PresentationStyle,int>`_.
|
||||
If you want to execute both steps at once, you can use
|
||||
`dump <yaml.html#dump,K,Stream,PresentationStyle,TagStyle,AnchorStyle,int>`_.
|
||||
|
||||
The ``present`` step allows you to specify how you want the output YAML
|
||||
character stream to be formatted. Amongst other options, it is possible to
|
||||
output pure JSON, but only if the stream does not contain any constructs that
|
||||
cannot be presented in JSON.
|
|
@ -96,9 +96,7 @@
|
|||
<g id="atomics" text-anchor="middle" transform="translate(0 90)">
|
||||
<g id="represent" transform="translate(65 10)">
|
||||
<use xlink:href="#atomic-right-long"/>
|
||||
<a xlink:href="yaml.html#represent,T,TagStyle,AnchorStyle" target="_top">
|
||||
<text x="80" y="25" font-style="italic">represent</text>
|
||||
</a>
|
||||
<text x="80" y="25" font-style="italic">represent</text>
|
||||
</g>
|
||||
|
||||
<g id="serialize" transform="translate(235 10)">
|
||||
|
@ -115,9 +113,7 @@
|
|||
|
||||
<g id="construct" transform="translate(65 120)">
|
||||
<use xlink:href="#atomic-left-long"/>
|
||||
<a xlink:href="yaml.html#construct,YamlStream,T" target="_top">
|
||||
<text x="80" y="35" font-style="italic">construct</text>
|
||||
</a>
|
||||
<text x="80" y="35" font-style="italic">construct</text>
|
||||
</g>
|
||||
|
||||
<g id="compose" transform="translate(235 120)">
|
||||
|
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.1 KiB |
|
@ -23,17 +23,6 @@ proc initSerializationTagLibrary(): TagLibrary {.raises: [].} =
|
|||
result.tags["tag:yaml.org,2002:timestamp"] = yTagTimestamp
|
||||
result.tags["tag:yaml.org,2002:value"] = yTagValue
|
||||
result.tags["tag:yaml.org,2002:binary"] = yTagBinary
|
||||
result.tags["!nim:system:int8"] = yTagNimInt8
|
||||
result.tags["!nim:system:int16"] = yTagNimInt16
|
||||
result.tags["!nim:system:int32"] = yTagNimInt32
|
||||
result.tags["!nim:system:int64"] = yTagNimInt64
|
||||
result.tags["!nim:system:uint8"] = yTagNimUInt8
|
||||
result.tags["!nim:system:uint16"] = yTagNimUInt16
|
||||
result.tags["!nim:system:uint32"] = yTagNimUInt32
|
||||
result.tags["!nim:system:uint64"] = yTagNimUInt64
|
||||
result.tags["!nim:system:float32"] = yTagNimFloat32
|
||||
result.tags["!nim:system:float64"] = yTagNimFloat64
|
||||
result.tags["!nim:system:char"] = yTagNimChar
|
||||
|
||||
var
|
||||
serializationTagLibrary* = initSerializationTagLibrary() ## \
|
||||
|
@ -44,7 +33,6 @@ var
|
|||
## Should not be modified manually. Will be extended by
|
||||
## `serializable <#serializable,stmt,stmt>`_.
|
||||
|
||||
|
||||
static:
|
||||
iterator objectFields(n: NimNode): tuple[name: NimNode, t: NimNode]
|
||||
{.raises: [].} =
|
||||
|
@ -59,6 +47,31 @@ static:
|
|||
template presentTag(t: typedesc, ts: TagStyle): TagId =
|
||||
if ts == tsNone: yTagQuestionMark else: yamlTag(t)
|
||||
|
||||
template setTagUriForType*(t: typedesc, uri: string): stmt =
|
||||
## Associate the given uri with a certain type. This uri is used as YAML tag
|
||||
## when loading and dumping values of this type.
|
||||
let id {.gensym.} = serializationTagLibrary.registerUri(uri)
|
||||
proc yamlTag*(T: typedesc[t]): TagId {.inline, raises: [].} = id
|
||||
|
||||
template setTagUriForType*(t: typedesc, uri: string, idName: expr): stmt =
|
||||
## Like `setTagUriForType <#setTagUriForType,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.
|
||||
let idName* = serializationTagLibrary.registerUri(uri)
|
||||
proc yamlTag*(T: typedesc[t]): TagId {.inline, raises: [].} = idName
|
||||
|
||||
setTagUriForType(char, "!nim:system:char", yTagNimChar)
|
||||
setTagUriForType(int8, "!nim:system:int8", yTagNimInt8)
|
||||
setTagUriForType(int16, "!nim:system:int16", yTagNimInt16)
|
||||
setTagUriForType(int32, "!nim:system:int32", yTagNimInt32)
|
||||
setTagUriForType(int64, "!nim:system:int64", yTagNimInt64)
|
||||
setTagUriForType(uint8, "!nim:system:uint8", yTagNimUInt8)
|
||||
setTagUriForType(uint16, "!nim:system:uint16", yTagNimUInt16)
|
||||
setTagUriForType(uint32, "!nim:system:uint32", yTagNimUInt32)
|
||||
setTagUriForType(uint64, "!nim:system:uint64", yTagNimUInt64)
|
||||
setTagUriForType(float32, "!nim:system:float32", yTagNimFloat32)
|
||||
setTagUriForType(float64, "!nim:system:float64", yTagNimFloat64)
|
||||
|
||||
proc lazyLoadTag*(uri: string): TagId {.inline, raises: [].} =
|
||||
## Internal function. Do not call explicitly.
|
||||
try:
|
||||
|
@ -275,7 +288,8 @@ template constructScalarItem(bs: var YamlStream, item: YamlStreamEvent,
|
|||
e.parent = getCurrentException()
|
||||
raise e
|
||||
|
||||
proc yamlTag*(T: typedesc[string]): TagId {.inline, raises: [].} = yTagString
|
||||
proc yamlTag*(T: typedesc[string]): TagId {.inline, noSideEffect, raises: [].} =
|
||||
yTagString
|
||||
|
||||
proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
||||
result: var string)
|
||||
|
@ -289,11 +303,6 @@ proc representObject*(value: string, ts: TagStyle = tsNone,
|
|||
result = iterator(): YamlStreamEvent =
|
||||
yield scalarEvent(value, presentTag(string, ts), yAnchorNone)
|
||||
|
||||
proc yamlTag*(T: typedesc[int8]): TagId {.inline, raises: [].} = yTagNimInt8
|
||||
proc yamlTag*(T: typedesc[int16]): TagId {.inline, raises: [].} = yTagNimInt16
|
||||
proc yamlTag*(T: typedesc[int32]): TagId {.inline, raises: [].} = yTagNimInt32
|
||||
proc yamlTag*(T: typedesc[int64]): TagId {.inline, raises: [].} = yTagNimInt64
|
||||
|
||||
proc constructObject*[T: int8|int16|int32|int64](
|
||||
s: var YamlStream, c: ConstructionContext, result: var T)
|
||||
{.raises: [YamlConstructionError, YamlStreamError].} =
|
||||
|
@ -317,11 +326,6 @@ template representObject*(value: int, tagStyle: TagStyle,
|
|||
{.fatal: "The length of `int` is platform dependent. Use int[8|16|32|64].".}
|
||||
discard
|
||||
|
||||
proc yamlTag*(T: typedesc[uint8]): TagId {.inline, raises: [].} = yTagNimUInt8
|
||||
proc yamlTag*(T: typedesc[uint16]): TagId {.inline, raises: [].} = yTagNimUInt16
|
||||
proc yamlTag*(T: typedesc[uint32]): TagId {.inline, raises: [].} = yTagNimUInt32
|
||||
proc yamlTag*(T: typedesc[uint64]): TagId {.inline, raises: [].} = yTagNimUInt64
|
||||
|
||||
{.push overflowChecks: on.}
|
||||
proc parseBiggestUInt(s: string): uint64 =
|
||||
result = 0
|
||||
|
@ -359,11 +363,6 @@ template representObject*(value: uint, ts: TagStyle, c: SerializationContext):
|
|||
"The length of `uint` is platform dependent. Use uint[8|16|32|64].".}
|
||||
discard
|
||||
|
||||
proc yamlTag*(T: typedesc[float32]): TagId {.inline, raises: [].} =
|
||||
yTagNimFloat32
|
||||
proc yamlTag*(T: typedesc[float64]): TagId {.inline, raises: [].} =
|
||||
yTagNimFloat64
|
||||
|
||||
proc constructObject*[T: float32|float64](
|
||||
s: var YamlStream, c: ConstructionContext, result: var T)
|
||||
{.raises: [YamlConstructionError, YamlStreamError].} =
|
||||
|
@ -431,8 +430,6 @@ proc representObject*(value: bool, ts: TagStyle,
|
|||
yield scalarEvent(if value: "y" else: "n", presentTag(bool, ts),
|
||||
yAnchorNone)
|
||||
|
||||
proc yamlTag*(T: typedesc[char]): TagId {.inline, raises: [].} = yTagNimChar
|
||||
|
||||
proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
||||
result: var char)
|
||||
{.raises: [YamlConstructionError, YamlStreamError].} =
|
||||
|
@ -617,6 +614,11 @@ proc constructObject*[O: enum](s: var YamlStream, c: ConstructionContext,
|
|||
if e.kind != yamlScalar:
|
||||
raise newException(YamlConstructionError, "Expected scalar, got " &
|
||||
$e.kind)
|
||||
if e.scalarAnchor != yAnchorNone:
|
||||
raise newException(YamlConstructionError, "Anchor on a non-ref type")
|
||||
if e.scalarTag notin [yTagQuestionMark, yamlTag(O)]:
|
||||
raise newException(YamlConstructionError,
|
||||
"Wrong tag for " & type(O).name)
|
||||
try: result = parseEnum[O](e.scalarContent)
|
||||
except ValueError:
|
||||
var ex = newException(YamlConstructionError, "Cannot parse '" &
|
||||
|
|
|
@ -11,13 +11,17 @@ type
|
|||
tlGreen, tlYellow, tlRed
|
||||
|
||||
Person = object
|
||||
firstname, surname: string
|
||||
firstnamechar: char
|
||||
surname: string
|
||||
age: int32
|
||||
|
||||
Node = object
|
||||
value: string
|
||||
next: ref Node
|
||||
|
||||
setTagUriForType(TrafficLight, "!tl")
|
||||
setTagUriForType(Node, "!example.net:Node")
|
||||
|
||||
template assertStringEqual(expected, actual: string) =
|
||||
for i in countup(0, min(expected.len, actual.len)):
|
||||
if expected[i] != actual[i]:
|
||||
|
@ -93,7 +97,7 @@ suite "Serialization":
|
|||
output.data
|
||||
|
||||
test "Serialization: Load Enum":
|
||||
let input = newStringStream("- tlRed\n- tlGreen\n- tlYellow")
|
||||
let input = newStringStream("!nim:system:seq(tl)\n- !tl tlRed\n- tlGreen\n- tlYellow")
|
||||
var
|
||||
result: seq[TrafficLight]
|
||||
parser = newYamlParser(tagLib)
|
||||
|
@ -130,22 +134,22 @@ suite "Serialization":
|
|||
output.data
|
||||
|
||||
test "Serialization: Load custom object":
|
||||
let input = newStringStream("firstname: Peter\nsurname: Pan\nage: 12")
|
||||
let input = newStringStream("firstnamechar: P\nsurname: Pan\nage: 12")
|
||||
var
|
||||
result: Person
|
||||
parser = newYamlParser(tagLib)
|
||||
events = parser.parse(input)
|
||||
construct(events, result)
|
||||
assert result.firstname == "Peter"
|
||||
assert result.firstnamechar == 'P'
|
||||
assert result.surname == "Pan"
|
||||
assert result.age == 12
|
||||
|
||||
test "Serialization: Represent custom object":
|
||||
let input = Person(firstname: "Peter", surname: "Pan", age: 12)
|
||||
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
||||
var output = newStringStream()
|
||||
dump(input, output, psBlockOnly, tsNone)
|
||||
assertStringEqual(
|
||||
"%YAML 1.2\n--- \nfirstname: Peter\nsurname: Pan\nage: 12",
|
||||
"%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12",
|
||||
output.data)
|
||||
|
||||
test "Serialization: Load sequence with explicit tags":
|
||||
|
@ -169,22 +173,22 @@ suite "Serialization":
|
|||
|
||||
test "Serialization: Load custom object with explicit root tag":
|
||||
let input = newStringStream(
|
||||
"--- !nim:custom:Person\nfirstname: Peter\nsurname: Pan\nage: 12")
|
||||
"--- !nim:custom:Person\nfirstnamechar: P\nsurname: Pan\nage: 12")
|
||||
var
|
||||
result: Person
|
||||
parser = newYamlParser(tagLib)
|
||||
events = parser.parse(input)
|
||||
construct(events, result)
|
||||
assert result.firstname == "Peter"
|
||||
assert result.firstnamechar == 'P'
|
||||
assert result.surname == "Pan"
|
||||
assert result.age == 12
|
||||
|
||||
test "Serialization: Represent custom object with explicit root tag":
|
||||
let input = Person(firstname: "Peter", surname: "Pan", age: 12)
|
||||
let input = Person(firstnamechar: 'P', surname: "Pan", age: 12)
|
||||
var output = newStringStream()
|
||||
dump(input, output, psBlockOnly, tsRootOnly)
|
||||
assertStringEqual("%YAML 1.2\n" &
|
||||
"--- !nim:custom:Person \nfirstname: Peter\nsurname: Pan\nage: 12",
|
||||
"--- !nim:custom:Person \nfirstnamechar: P\nsurname: Pan\nage: 12",
|
||||
output.data)
|
||||
|
||||
test "Serialization: Represent cyclic data structure":
|
||||
|
@ -198,7 +202,7 @@ suite "Serialization":
|
|||
var output = newStringStream()
|
||||
dump(a, output, psBlockOnly, tsRootOnly)
|
||||
assertStringEqual """%YAML 1.2
|
||||
--- !nim:custom:Node &a
|
||||
--- !example.net:Node &a
|
||||
value: a
|
||||
next:
|
||||
value: b
|
||||
|
@ -208,7 +212,7 @@ next:
|
|||
|
||||
test "Serialization: Load cyclic data structure":
|
||||
let input = newStringStream("""%YAML 1.2
|
||||
--- !nim:system:seq(nim:custom:Node)
|
||||
--- !nim:system:seq(example.net:Node)
|
||||
- &a
|
||||
value: a
|
||||
next: &b
|
||||
|
|
14
yaml.nim
14
yaml.nim
|
@ -126,7 +126,7 @@ type
|
|||
##
|
||||
## When `YamlParser <#YamlParser>`_ encounters tags not existing in the
|
||||
## tag library, it will use
|
||||
## `registerTagUri <#registerTagUri,TagLibrary,string>`_ to add
|
||||
## `registerUri <#registerUri,TagLibrary,string>`_ to add
|
||||
## the tag to the library.
|
||||
##
|
||||
## You can base your tag library on common tag libraries by initializing
|
||||
|
@ -343,18 +343,6 @@ const
|
|||
|
||||
yamlTagRepositoryPrefix* = "tag:yaml.org,2002:"
|
||||
|
||||
yTagNimInt8* = 100.TagId ## tag for Nim's ``int8``
|
||||
yTagNimInt16* = 101.TagId ## tag for Nim's ``int16``
|
||||
yTagNimInt32* = 102.TagId ## tag for Nim's ``int32``
|
||||
yTagNimInt64* = 103.TagId ## tag for Nim's ``int64``
|
||||
yTagNimUInt8* = 104.TagId ## tag for Nim's ``uint8``
|
||||
yTagNimUInt16* = 105.TagId ## tag for Nim's ``uint16``
|
||||
yTagNimUInt32* = 106.TagId ## tag for Nim's ``uint32``
|
||||
yTagNimUInt64* = 107.TagId ## tag for Nim's ``uint64``
|
||||
yTagNimFloat32* = 108.TagId ## tag for Nim's ``float32``
|
||||
yTagNimFloat64* = 109.TagId ## tag for Nim's ``float64``
|
||||
yTagNimChar* = 110.TagId ## tag for Nim's ``char``
|
||||
|
||||
# interface
|
||||
|
||||
proc `==`*(left: YamlStreamEvent, right: YamlStreamEvent): bool {.raises: [].}
|
||||
|
|
Loading…
Reference in New Issue