2016-02-27 12:09:50 +00:00
|
|
|
# NimYAML - YAML implementation in Nim
|
|
|
|
# (c) Copyright 2015 Felix Krause
|
|
|
|
#
|
|
|
|
# See the file "copying.txt", included in this
|
|
|
|
# distribution, for details about the copyright.
|
|
|
|
|
2016-01-28 20:59:26 +00:00
|
|
|
proc initRefNodeData(p: pointer): RefNodeData =
|
|
|
|
result.p = p
|
|
|
|
result.count = 1
|
|
|
|
result.anchor = yAnchorNone
|
|
|
|
|
2016-01-28 21:29:26 +00:00
|
|
|
proc newConstructionContext(): ConstructionContext =
|
|
|
|
new(result)
|
|
|
|
result.refs = initTable[AnchorId, pointer]()
|
|
|
|
|
2016-01-28 20:59:26 +00:00
|
|
|
proc newSerializationContext(s: AnchorStyle): SerializationContext =
|
|
|
|
new(result)
|
2016-02-22 20:56:30 +00:00
|
|
|
result.refs = initTable[pointer, AnchorId]()
|
2016-01-28 20:59:26 +00:00
|
|
|
result.style = s
|
2016-02-22 20:56:30 +00:00
|
|
|
result.nextAnchorId = 0.AnchorId
|
2016-01-05 15:54:14 +00:00
|
|
|
|
2016-02-16 18:24:55 +00:00
|
|
|
template presentTag*(t: typedesc, ts: TagStyle): TagId =
|
2016-02-26 20:13:40 +00:00
|
|
|
## Get the TagId that represents the given type in the given style
|
|
|
|
if ts == tsNone: yTagQuestionMark else: yamlTag(t)
|
2016-01-04 20:46:33 +00:00
|
|
|
|
2016-02-26 20:13:40 +00:00
|
|
|
proc lazyLoadTag(uri: string): TagId {.inline, raises: [].} =
|
2016-03-17 18:30:40 +00:00
|
|
|
try: result = serializationTagLibrary.tags[uri]
|
|
|
|
except KeyError: result = serializationTagLibrary.registerUri(uri)
|
2016-01-04 20:46:33 +00:00
|
|
|
|
2016-02-26 20:13:40 +00:00
|
|
|
proc safeTagUri(id: TagId): string {.raises: [].} =
|
2016-01-24 19:38:30 +00:00
|
|
|
try:
|
|
|
|
let uri = serializationTagLibrary.uri(id)
|
|
|
|
if uri.len > 0 and uri[0] == '!':
|
|
|
|
return uri[1..uri.len - 1]
|
2016-02-16 18:24:55 +00:00
|
|
|
else: return uri
|
2016-01-24 19:38:30 +00:00
|
|
|
except KeyError:
|
|
|
|
# cannot happen (theoretically, you known)
|
|
|
|
assert(false)
|
2016-01-05 15:54:14 +00:00
|
|
|
|
2016-02-26 20:13:40 +00:00
|
|
|
template constructScalarItem*(s: var YamlStream, i: expr,
|
|
|
|
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.
|
|
|
|
let i = s.next()
|
|
|
|
if i.kind != yamlScalar:
|
2016-01-24 19:38:30 +00:00
|
|
|
raise newException(YamlConstructionError, "Expected scalar")
|
2016-02-16 18:24:55 +00:00
|
|
|
try: content
|
|
|
|
except YamlConstructionError: raise
|
2016-01-24 19:38:30 +00:00
|
|
|
except Exception:
|
|
|
|
var e = newException(YamlConstructionError,
|
2016-02-26 20:13:40 +00:00
|
|
|
"Cannot construct to " & name(t) & ": " & item.scalarContent)
|
2016-01-24 19:38:30 +00:00
|
|
|
e.parent = getCurrentException()
|
|
|
|
raise e
|
|
|
|
|
2016-02-15 18:46:21 +00:00
|
|
|
proc yamlTag*(T: typedesc[string]): TagId {.inline, noSideEffect, raises: [].} =
|
|
|
|
yTagString
|
2016-01-24 19:38:30 +00:00
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
|
|
|
result: var string)
|
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## costructs a string from a YAML scalar
|
|
|
|
constructScalarItem(s, item, string):
|
2016-01-24 19:38:30 +00:00
|
|
|
result = item.scalarContent
|
2015-12-29 14:09:37 +00:00
|
|
|
|
2016-03-25 20:27:41 +00:00
|
|
|
proc representObject*(value: string, ts: TagStyle,
|
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents a string as YAML scalar
|
2015-12-29 15:10:47 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-03-25 20:27:41 +00:00
|
|
|
yield scalarEvent(value, tag, yAnchorNone)
|
2016-01-04 20:46:33 +00:00
|
|
|
|
2016-01-28 21:29:26 +00:00
|
|
|
proc constructObject*[T: int8|int16|int32|int64](
|
2016-02-12 18:53:25 +00:00
|
|
|
s: var YamlStream, c: ConstructionContext, result: var T)
|
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## constructs an integer value from a YAML scalar
|
|
|
|
constructScalarItem(s, item, T):
|
2016-01-26 19:00:28 +00:00
|
|
|
result = T(parseBiggestInt(item.scalarContent))
|
2015-12-29 14:09:37 +00:00
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
template constructObject*(s: var YamlStream, c: ConstructionContext,
|
2016-01-28 21:29:26 +00:00
|
|
|
result: var int) =
|
2016-02-26 20:13:40 +00:00
|
|
|
## calling this will raise a compiler error because ``int`` is not supported
|
2016-01-26 19:00:28 +00:00
|
|
|
{.fatal: "The length of `int` is platform dependent. Use int[8|16|32|64].".}
|
|
|
|
discard
|
2016-01-04 20:46:33 +00:00
|
|
|
|
2016-03-25 20:27:41 +00:00
|
|
|
proc representObject*[T: int8|int16|int32|int64](value: T, ts: TagStyle,
|
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents an integer value as YAML scalar
|
2016-01-26 19:00:28 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-03-25 20:27:41 +00:00
|
|
|
yield scalarEvent($value, tag, yAnchorNone)
|
2016-01-26 19:00:28 +00:00
|
|
|
|
2016-02-02 17:19:40 +00:00
|
|
|
template representObject*(value: int, tagStyle: TagStyle,
|
2016-03-25 20:27:41 +00:00
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream =
|
2016-02-26 20:13:40 +00:00
|
|
|
## calling this will raise a compiler error because ``int`` is not supported
|
2016-01-26 19:00:28 +00:00
|
|
|
{.fatal: "The length of `int` is platform dependent. Use int[8|16|32|64].".}
|
|
|
|
discard
|
|
|
|
|
|
|
|
{.push overflowChecks: on.}
|
|
|
|
proc parseBiggestUInt(s: string): uint64 =
|
|
|
|
result = 0
|
|
|
|
for c in s:
|
2016-03-17 18:30:40 +00:00
|
|
|
if c in {'0'..'9'}: result *= 10.uint64 + (uint64(c) - uint64('0'))
|
|
|
|
elif c == '_': discard
|
|
|
|
else: raise newException(ValueError, "Invalid char in uint: " & c)
|
2016-01-26 19:00:28 +00:00
|
|
|
{.pop.}
|
|
|
|
|
2016-01-28 21:29:26 +00:00
|
|
|
proc constructObject*[T: uint8|uint16|uint32|uint64](
|
2016-02-12 18:53:25 +00:00
|
|
|
s: var YamlStream, c: ConstructionContext, result: var T)
|
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## construct an unsigned integer value from a YAML scalar
|
|
|
|
constructScalarItem(s, item, T):
|
2016-01-26 19:00:28 +00:00
|
|
|
result = T(parseBiggestUInt(item.scalarContent))
|
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
template constructObject*(s: var YamlStream, c: ConstructionContext,
|
2016-01-28 21:29:26 +00:00
|
|
|
result: var uint) =
|
2016-02-26 20:13:40 +00:00
|
|
|
## calling this will raise a compiler error because ``uint`` is not
|
|
|
|
## supported
|
2016-01-26 19:00:28 +00:00
|
|
|
{.fatal:
|
|
|
|
"The length of `uint` is platform dependent. Use uint[8|16|32|64].".}
|
|
|
|
discard
|
2016-01-24 19:38:30 +00:00
|
|
|
|
2016-03-25 20:27:41 +00:00
|
|
|
proc representObject*[T: uint8|uint16|uint32|uint64](value: T, ts: TagStyle,
|
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents an unsigned integer value as YAML scalar
|
2015-12-29 15:10:47 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-03-25 20:27:41 +00:00
|
|
|
yield scalarEvent($value, tag, yAnchorNone)
|
2016-01-04 20:46:33 +00:00
|
|
|
|
2016-03-25 20:27:41 +00:00
|
|
|
template representObject*(value: uint, ts: TagStyle, c: SerializationContext,
|
|
|
|
tag: TagId): RawYamlStream =
|
2016-02-26 20:13:40 +00:00
|
|
|
## calling this will raise a compiler error because ``uint`` is not
|
|
|
|
## supported
|
2016-01-26 19:00:28 +00:00
|
|
|
{.fatal:
|
|
|
|
"The length of `uint` is platform dependent. Use uint[8|16|32|64].".}
|
|
|
|
discard
|
2015-12-29 15:10:47 +00:00
|
|
|
|
2016-01-28 21:29:26 +00:00
|
|
|
proc constructObject*[T: float32|float64](
|
2016-02-12 18:53:25 +00:00
|
|
|
s: var YamlStream, c: ConstructionContext, result: var T)
|
2016-02-26 20:13:40 +00:00
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
|
|
|
## construct a float value from a YAML scalar
|
|
|
|
constructScalarItem(s, item, T):
|
2016-01-24 19:38:30 +00:00
|
|
|
let hint = guessType(item.scalarContent)
|
|
|
|
case hint
|
2016-03-17 18:30:40 +00:00
|
|
|
of yTypeFloat: result = T(parseBiggestFloat(item.scalarContent))
|
2016-01-24 19:38:30 +00:00
|
|
|
of yTypeFloatInf:
|
2016-03-17 18:30:40 +00:00
|
|
|
if item.scalarContent[0] == '-': result = NegInf
|
|
|
|
else: result = Inf
|
|
|
|
of yTypeFloatNaN: result = NaN
|
2015-12-29 14:09:37 +00:00
|
|
|
else:
|
2016-01-24 19:38:30 +00:00
|
|
|
raise newException(YamlConstructionError,
|
|
|
|
"Cannot construct to float: " & item.scalarContent)
|
2015-12-29 14:09:37 +00:00
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
template constructObject*(s: var YamlStream, c: ConstructionContext,
|
2016-01-28 21:29:26 +00:00
|
|
|
result: var float) =
|
2016-02-26 20:13:40 +00:00
|
|
|
## calling this will raise a compiler error because ``float`` is not
|
|
|
|
## supported
|
2016-01-26 19:00:28 +00:00
|
|
|
{.fatal: "The length of `float` is platform dependent. Use float[32|64].".}
|
|
|
|
|
2016-02-02 17:19:40 +00:00
|
|
|
proc representObject*[T: float32|float64](value: T, ts: TagStyle,
|
2016-03-25 20:27:41 +00:00
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents a float value as YAML scalar
|
2015-12-29 15:10:47 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-03-17 18:30:40 +00:00
|
|
|
var asString: string
|
2016-01-05 18:06:55 +00:00
|
|
|
case value
|
2016-02-16 18:24:55 +00:00
|
|
|
of Inf: asString = ".inf"
|
|
|
|
of NegInf: asString = "-.inf"
|
|
|
|
of NaN: asString = ".nan"
|
|
|
|
else: asString = $value
|
2016-03-25 20:27:41 +00:00
|
|
|
yield scalarEvent(asString, tag, yAnchorNone)
|
2016-01-26 19:00:28 +00:00
|
|
|
|
2016-02-02 17:19:40 +00:00
|
|
|
template representObject*(value: float, tagStyle: TagStyle,
|
2016-03-25 20:27:41 +00:00
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream =
|
2016-02-26 20:13:40 +00:00
|
|
|
## calling this will result in a compiler error because ``float`` is not
|
|
|
|
## supported
|
2016-01-26 19:00:28 +00:00
|
|
|
{.fatal: "The length of `float` is platform dependent. Use float[32|64].".}
|
2015-12-29 15:10:47 +00:00
|
|
|
|
2016-01-24 19:38:30 +00:00
|
|
|
proc yamlTag*(T: typedesc[bool]): TagId {.inline, raises: [].} = yTagBoolean
|
2016-01-04 20:46:33 +00:00
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
|
|
|
result: var bool)
|
2016-02-26 20:13:40 +00:00
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
|
|
|
## constructs a bool value from a YAML scalar
|
|
|
|
constructScalarItem(s, item, bool):
|
2016-01-24 19:38:30 +00:00
|
|
|
case guessType(item.scalarContent)
|
2016-03-17 18:30:40 +00:00
|
|
|
of yTypeBoolTrue: result = true
|
|
|
|
of yTypeBoolFalse: result = false
|
2016-01-05 15:54:14 +00:00
|
|
|
else:
|
2016-01-24 19:38:30 +00:00
|
|
|
raise newException(YamlConstructionError,
|
|
|
|
"Cannot construct to bool: " & item.scalarContent)
|
2016-01-05 15:54:14 +00:00
|
|
|
|
2016-03-25 20:27:41 +00:00
|
|
|
proc representObject*(value: bool, ts: TagStyle, c: SerializationContext,
|
|
|
|
tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents a bool value as a YAML scalar
|
2015-12-29 15:10:47 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-03-25 20:27:41 +00:00
|
|
|
yield scalarEvent(if value: "y" else: "n", tag, yAnchorNone)
|
2016-01-04 20:46:33 +00:00
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
|
|
|
result: var char)
|
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## constructs a char value from a YAML scalar
|
|
|
|
constructScalarItem(s, item, char):
|
2016-01-26 19:00:28 +00:00
|
|
|
if item.scalarContent.len != 1:
|
|
|
|
raise newException(YamlConstructionError,
|
|
|
|
"Cannot construct to char (length != 1): " &
|
|
|
|
item.scalarContent)
|
|
|
|
else:
|
|
|
|
result = item.scalarContent[0]
|
|
|
|
|
2016-03-25 20:27:41 +00:00
|
|
|
proc representObject*(value: char, ts: TagStyle, c: SerializationContext,
|
|
|
|
tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents a char value as YAML scalar
|
2016-01-26 19:00:28 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-03-25 20:27:41 +00:00
|
|
|
yield scalarEvent("" & value, tag, yAnchorNone)
|
2016-01-26 19:00:28 +00:00
|
|
|
|
2016-01-24 19:38:30 +00:00
|
|
|
proc yamlTag*[I](T: typedesc[seq[I]]): TagId {.inline, raises: [].} =
|
2016-02-01 18:48:42 +00:00
|
|
|
let uri = "!nim:system:seq(" & safeTagUri(yamlTag(I)) & ")"
|
2016-01-04 20:46:33 +00:00
|
|
|
result = lazyLoadTag(uri)
|
2015-12-29 15:10:47 +00:00
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
proc constructObject*[T](s: var YamlStream, c: ConstructionContext,
|
2016-01-28 21:29:26 +00:00
|
|
|
result: var seq[T])
|
2016-02-12 18:53:25 +00:00
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## constructs a Nim seq from a YAML sequence
|
2016-02-12 18:53:25 +00:00
|
|
|
let event = s.next()
|
2016-03-14 17:10:34 +00:00
|
|
|
if event.kind != yamlStartSeq:
|
2016-01-24 19:38:30 +00:00
|
|
|
raise newException(YamlConstructionError, "Expected sequence start")
|
2015-12-29 14:09:37 +00:00
|
|
|
result = newSeq[T]()
|
2016-03-14 17:10:34 +00:00
|
|
|
while s.peek().kind != yamlEndSeq:
|
2016-02-12 18:53:25 +00:00
|
|
|
var item: T
|
2016-02-16 18:24:55 +00:00
|
|
|
constructChild(s, c, item)
|
2015-12-29 14:09:37 +00:00
|
|
|
result.add(item)
|
2016-02-12 18:53:25 +00:00
|
|
|
discard s.next()
|
2015-12-29 14:09:37 +00:00
|
|
|
|
2016-02-02 17:19:40 +00:00
|
|
|
proc representObject*[T](value: seq[T], ts: TagStyle,
|
2016-03-25 20:27:41 +00:00
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents a Nim seq as YAML sequence
|
2015-12-29 15:10:47 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-01-26 19:51:21 +00:00
|
|
|
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
|
2016-03-14 17:10:34 +00:00
|
|
|
yield YamlStreamEvent(kind: yamlStartSeq,
|
2016-03-25 20:27:41 +00:00
|
|
|
seqTag: tag,
|
2015-12-29 15:10:47 +00:00
|
|
|
seqAnchor: yAnchorNone)
|
|
|
|
for item in value:
|
2016-03-25 20:27:41 +00:00
|
|
|
var events = representChild(item, childTagStyle, c)
|
2016-02-12 18:53:25 +00:00
|
|
|
while true:
|
|
|
|
let event = events()
|
|
|
|
if finished(events): break
|
2015-12-29 15:10:47 +00:00
|
|
|
yield event
|
2016-03-14 17:10:34 +00:00
|
|
|
yield YamlStreamEvent(kind: yamlEndSeq)
|
2015-12-29 15:10:47 +00:00
|
|
|
|
2016-01-24 19:38:30 +00:00
|
|
|
proc yamlTag*[K, V](T: typedesc[Table[K, V]]): TagId {.inline, raises: [].} =
|
|
|
|
try:
|
2016-02-19 17:25:01 +00:00
|
|
|
let uri = "!nim:tables:Table(" & safeTagUri(yamlTag(K)) & "," &
|
|
|
|
safeTagUri(yamlTag(V)) & ")"
|
2016-01-24 19:38:30 +00:00
|
|
|
result = lazyLoadTag(uri)
|
|
|
|
except KeyError:
|
|
|
|
# cannot happen (theoretically, you known)
|
|
|
|
assert(false)
|
2016-01-04 20:46:33 +00:00
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext,
|
2016-01-28 21:29:26 +00:00
|
|
|
result: var Table[K, V])
|
2016-02-12 18:53:25 +00:00
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## constructs a Nim Table from a YAML mapping
|
2016-02-12 18:53:25 +00:00
|
|
|
let event = s.next()
|
2016-02-01 18:48:42 +00:00
|
|
|
if event.kind != yamlStartMap:
|
|
|
|
raise newException(YamlConstructionError, "Expected map start, got " &
|
|
|
|
$event.kind)
|
2015-12-29 14:09:37 +00:00
|
|
|
result = initTable[K, V]()
|
2016-02-12 18:53:25 +00:00
|
|
|
while s.peek.kind != yamlEndMap:
|
2015-12-29 14:09:37 +00:00
|
|
|
var
|
|
|
|
key: K
|
|
|
|
value: V
|
2016-02-16 18:24:55 +00:00
|
|
|
constructChild(s, c, key)
|
|
|
|
constructChild(s, c, value)
|
2015-12-29 14:09:37 +00:00
|
|
|
result[key] = value
|
2016-02-12 18:53:25 +00:00
|
|
|
discard s.next()
|
2015-12-29 15:10:47 +00:00
|
|
|
|
2016-02-02 17:19:40 +00:00
|
|
|
proc representObject*[K, V](value: Table[K, V], ts: TagStyle,
|
2016-03-25 20:27:41 +00:00
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream {.raises:[].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents a Nim Table as YAML mapping
|
2015-12-29 15:10:47 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-01-26 19:51:21 +00:00
|
|
|
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
|
2016-01-04 21:18:55 +00:00
|
|
|
yield YamlStreamEvent(kind: yamlStartMap,
|
2016-03-25 20:27:41 +00:00
|
|
|
mapTag: tag,
|
2015-12-29 15:10:47 +00:00
|
|
|
mapAnchor: yAnchorNone)
|
|
|
|
for key, value in value.pairs:
|
2016-03-25 20:27:41 +00:00
|
|
|
var events = representChild(key, childTagStyle, c)
|
2016-02-12 18:53:25 +00:00
|
|
|
while true:
|
|
|
|
let event = events()
|
|
|
|
if finished(events): break
|
2015-12-29 15:10:47 +00:00
|
|
|
yield event
|
2016-03-25 20:27:41 +00:00
|
|
|
events = representChild(value, childTagStyle, c)
|
2016-02-12 18:53:25 +00:00
|
|
|
while true:
|
|
|
|
let event = events()
|
|
|
|
if finished(events): break
|
2015-12-29 15:10:47 +00:00
|
|
|
yield event
|
2015-12-29 17:22:55 +00:00
|
|
|
yield YamlStreamEvent(kind: yamlEndMap)
|
|
|
|
|
2016-02-01 19:16:35 +00:00
|
|
|
template yamlTag*(T: typedesc[object|enum]): expr =
|
2016-02-01 18:48:42 +00:00
|
|
|
var uri = when compiles(yamlTagId(T)): yamlTagId(T) else:
|
2016-02-12 18:53:25 +00:00
|
|
|
"!nim:custom:" & (typetraits.name(type(T)))
|
2016-03-17 18:30:40 +00:00
|
|
|
try: serializationTagLibrary.tags[uri]
|
|
|
|
except KeyError: serializationTagLibrary.registerUri(uri)
|
2016-02-01 18:48:42 +00:00
|
|
|
|
|
|
|
template yamlTag*(T: typedesc[tuple]): expr =
|
|
|
|
var
|
|
|
|
i: T
|
|
|
|
uri = "!nim: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)
|
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
proc constructObject*[O: object|tuple](s: var YamlStream,
|
|
|
|
c: ConstructionContext,
|
|
|
|
result: var O)
|
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## constructs a Nim object or tuple from a YAML mapping
|
2016-02-12 18:53:25 +00:00
|
|
|
let e = s.next()
|
2016-02-01 18:48:42 +00:00
|
|
|
if e.kind != yamlStartMap:
|
|
|
|
raise newException(YamlConstructionError, "Expected map start, got " &
|
|
|
|
$e.kind)
|
2016-02-12 18:53:25 +00:00
|
|
|
while s.peek.kind != yamlEndMap:
|
|
|
|
let e = s.next()
|
2016-02-01 18:48:42 +00:00
|
|
|
if e.kind != yamlScalar:
|
2016-02-12 18:53:25 +00:00
|
|
|
raise newException(YamlConstructionError,
|
|
|
|
"Expected field name, got " & $e.kind)
|
2016-02-01 18:48:42 +00:00
|
|
|
let name = e.scalarContent
|
|
|
|
for fname, value in fieldPairs(result):
|
|
|
|
if fname == name:
|
2016-02-16 18:24:55 +00:00
|
|
|
constructChild(s, c, value)
|
2016-02-01 18:48:42 +00:00
|
|
|
break
|
2016-02-12 18:53:25 +00:00
|
|
|
discard s.next()
|
2016-02-01 18:48:42 +00:00
|
|
|
|
2016-02-02 17:19:40 +00:00
|
|
|
proc representObject*[O: object|tuple](value: O, ts: TagStyle,
|
2016-03-25 20:27:41 +00:00
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents a Nim object or tuple as YAML mapping
|
2016-02-01 18:48:42 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
|
|
|
let childTagStyle = if ts == tsRootOnly: tsNone else: ts
|
2016-03-25 20:27:41 +00:00
|
|
|
yield startMapEvent(tag, yAnchorNone)
|
2016-02-01 18:48:42 +00:00
|
|
|
for name, value in fieldPairs(value):
|
2016-03-25 20:38:28 +00:00
|
|
|
yield scalarEvent(name,
|
|
|
|
if childTagStyle == tsNone: yTagQuestionMark else:
|
|
|
|
yTagNimField, yAnchorNone)
|
2016-03-25 20:27:41 +00:00
|
|
|
var events = representChild(value, childTagStyle, c)
|
2016-02-12 18:53:25 +00:00
|
|
|
while true:
|
|
|
|
let event = events()
|
|
|
|
if finished(events): break
|
2016-02-01 18:48:42 +00:00
|
|
|
yield event
|
|
|
|
yield endMapEvent()
|
|
|
|
|
2016-02-12 18:53:25 +00:00
|
|
|
proc constructObject*[O: enum](s: var YamlStream, c: ConstructionContext,
|
2016-02-01 19:16:35 +00:00
|
|
|
result: var O)
|
2016-02-12 18:53:25 +00:00
|
|
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## constructs a Nim enum from a YAML scalar
|
2016-02-12 18:53:25 +00:00
|
|
|
let e = s.next()
|
2016-02-01 19:16:35 +00:00
|
|
|
if e.kind != yamlScalar:
|
|
|
|
raise newException(YamlConstructionError, "Expected scalar, got " &
|
|
|
|
$e.kind)
|
|
|
|
try: result = parseEnum[O](e.scalarContent)
|
|
|
|
except ValueError:
|
|
|
|
var ex = newException(YamlConstructionError, "Cannot parse '" &
|
|
|
|
e.scalarContent & "' as " & type(O).name)
|
|
|
|
ex.parent = getCurrentException()
|
|
|
|
raise ex
|
|
|
|
|
2016-02-02 17:19:40 +00:00
|
|
|
proc representObject*[O: enum](value: O, ts: TagStyle,
|
2016-03-25 20:27:41 +00:00
|
|
|
c: SerializationContext, tag: TagId): RawYamlStream {.raises: [].} =
|
2016-02-26 20:13:40 +00:00
|
|
|
## represents a Nim enum as YAML scalar
|
2016-02-01 19:16:35 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-03-25 20:27:41 +00:00
|
|
|
yield scalarEvent($value, tag, yAnchorNone)
|
2016-02-01 19:16:35 +00:00
|
|
|
|
2016-01-28 20:59:26 +00:00
|
|
|
proc yamlTag*[O](T: typedesc[ref O]): TagId {.inline, raises: [].} = yamlTag(O)
|
|
|
|
|
2016-02-16 18:24:55 +00:00
|
|
|
proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
|
|
|
result: var T) =
|
|
|
|
let item = s.peek()
|
|
|
|
case item.kind
|
|
|
|
of yamlScalar:
|
|
|
|
if item.scalarTag notin [yTagQuestionMark, yTagExclamationMark,
|
|
|
|
yamlTag(T)]:
|
|
|
|
raise newException(YamlConstructionError, "Wrong tag for " &
|
|
|
|
typetraits.name(T))
|
|
|
|
elif item.scalarAnchor != yAnchorNone:
|
|
|
|
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
|
|
|
of yamlStartMap:
|
|
|
|
if item.mapTag notin [yTagQuestionMark, yamlTag(T)]:
|
|
|
|
raise newException(YamlConstructionError, "Wrong tag for " &
|
|
|
|
typetraits.name(T))
|
|
|
|
elif item.mapAnchor != yAnchorNone:
|
|
|
|
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
2016-03-14 17:10:34 +00:00
|
|
|
of yamlStartSeq:
|
2016-02-16 18:24:55 +00:00
|
|
|
if item.seqTag notin [yTagQuestionMark, yamlTag(T)]:
|
|
|
|
raise newException(YamlConstructionError, "Wrong tag for " &
|
|
|
|
typetraits.name(T))
|
|
|
|
elif item.seqAnchor != yAnchorNone:
|
|
|
|
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
|
|
|
else: assert false
|
|
|
|
constructObject(s, c, result)
|
|
|
|
|
|
|
|
proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
|
2016-02-12 18:53:25 +00:00
|
|
|
result: var ref O) =
|
|
|
|
var e = s.peek()
|
2016-01-28 20:59:26 +00:00
|
|
|
if e.kind == yamlScalar:
|
|
|
|
if e.scalarTag == yTagNull or (
|
2016-02-16 18:24:55 +00:00
|
|
|
e.scalarTag == yTagQuestionMark and
|
2016-01-28 20:59:26 +00:00
|
|
|
guessType(e.scalarContent) == yTypeNull):
|
|
|
|
result = nil
|
2016-02-12 18:53:25 +00:00
|
|
|
discard s.next()
|
2016-01-28 20:59:26 +00:00
|
|
|
return
|
2016-01-28 21:29:26 +00:00
|
|
|
elif e.kind == yamlAlias:
|
|
|
|
try:
|
|
|
|
result = cast[ref O](c.refs[e.aliasTarget])
|
2016-02-12 18:53:25 +00:00
|
|
|
discard s.next()
|
2016-01-28 21:29:26 +00:00
|
|
|
return
|
2016-03-17 18:30:40 +00:00
|
|
|
except KeyError: assert(false)
|
2016-01-28 20:59:26 +00:00
|
|
|
new(result)
|
2016-02-12 18:53:25 +00:00
|
|
|
template removeAnchor(anchor: var AnchorId) {.dirty.} =
|
|
|
|
if anchor != yAnchorNone:
|
|
|
|
assert(not c.refs.hasKey(anchor))
|
|
|
|
c.refs[anchor] = cast[pointer](result)
|
|
|
|
anchor = yAnchorNone
|
|
|
|
|
2016-01-28 21:29:26 +00:00
|
|
|
case e.kind
|
2016-02-12 18:53:25 +00:00
|
|
|
of yamlScalar: removeAnchor(e.scalarAnchor)
|
|
|
|
of yamlStartMap: removeAnchor(e.mapAnchor)
|
2016-03-14 17:10:34 +00:00
|
|
|
of yamlStartSeq: removeAnchor(e.seqAnchor)
|
2016-01-28 21:29:26 +00:00
|
|
|
else: assert(false)
|
2016-02-12 18:53:25 +00:00
|
|
|
s.peek = e
|
2016-03-17 18:30:40 +00:00
|
|
|
try: constructChild(s, c, result[])
|
|
|
|
except YamlConstructionError, YamlStreamError, AssertionError: raise
|
2016-01-28 20:59:26 +00:00
|
|
|
except Exception:
|
2016-02-12 18:53:25 +00:00
|
|
|
var e = newException(YamlStreamError,
|
2016-01-28 20:59:26 +00:00
|
|
|
getCurrentExceptionMsg())
|
|
|
|
e.parent = getCurrentException()
|
|
|
|
raise e
|
|
|
|
|
2016-03-25 20:27:41 +00:00
|
|
|
proc representChild*[O](value: O, ts: TagStyle, c: SerializationContext):
|
|
|
|
RawYamlStream =
|
|
|
|
result = representObject(value, ts, c, presentTag(O, ts))
|
|
|
|
|
|
|
|
proc representChild*[O](value: ref O, ts: TagStyle, c: SerializationContext):
|
2016-02-26 20:13:40 +00:00
|
|
|
RawYamlStream =
|
2016-01-28 20:59:26 +00:00
|
|
|
if value == nil:
|
2016-02-12 18:53:25 +00:00
|
|
|
result = iterator(): YamlStreamEvent =
|
|
|
|
yield scalarEvent("~", yTagNull)
|
2016-01-28 20:59:26 +00:00
|
|
|
elif c.style == asNone:
|
2016-03-25 20:27:41 +00:00
|
|
|
result = representChild(value[], ts, c)
|
2016-01-28 20:59:26 +00:00
|
|
|
else:
|
2016-02-22 20:56:30 +00:00
|
|
|
let p = cast[pointer](value)
|
|
|
|
if c.refs.hasKey(p):
|
|
|
|
try:
|
|
|
|
if c.refs[p] == yAnchorNone:
|
|
|
|
c.refs[p] = c.nextAnchorId
|
|
|
|
c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1)
|
|
|
|
except KeyError: assert false, "Can never happen"
|
|
|
|
result = iterator(): YamlStreamEvent {.raises: [].} =
|
|
|
|
var event: YamlStreamEvent
|
|
|
|
try: event = aliasEvent(c.refs[p])
|
|
|
|
except KeyError: assert false, "Can never happen"
|
2016-02-12 18:53:25 +00:00
|
|
|
yield event
|
2016-02-22 20:56:30 +00:00
|
|
|
return
|
|
|
|
try:
|
|
|
|
if c.style == asAlways:
|
|
|
|
c.refs[p] = c.nextAnchorId
|
|
|
|
c.nextAnchorId = AnchorId(int(c.nextAnchorId) + 1)
|
|
|
|
else: c.refs[p] = yAnchorNone
|
|
|
|
let
|
|
|
|
a = if c.style == asAlways: c.refs[p] else: cast[AnchorId](p)
|
|
|
|
childTagStyle = if ts == tsAll: tsAll else: tsRootOnly
|
|
|
|
result = iterator(): YamlStreamEvent =
|
2016-03-25 20:27:41 +00:00
|
|
|
var child = representChild(value[], childTagStyle, c)
|
2016-02-22 20:56:30 +00:00
|
|
|
var first = child()
|
|
|
|
assert(not finished(child))
|
|
|
|
case first.kind
|
|
|
|
of yamlStartMap:
|
|
|
|
first.mapAnchor = a
|
|
|
|
if ts == tsNone: first.mapTag = yTagQuestionMark
|
2016-03-14 17:10:34 +00:00
|
|
|
of yamlStartSeq:
|
2016-02-22 20:56:30 +00:00
|
|
|
first.seqAnchor = a
|
|
|
|
if ts == tsNone: first.seqTag = yTagQuestionMark
|
|
|
|
of yamlScalar:
|
|
|
|
first.scalarAnchor = a
|
|
|
|
if ts == tsNone and guessType(first.scalarContent) != yTypeNull:
|
|
|
|
first.scalarTag = yTagQuestionMark
|
|
|
|
else: discard
|
|
|
|
yield first
|
|
|
|
while true:
|
|
|
|
let event = child()
|
|
|
|
if finished(child): break
|
|
|
|
yield event
|
|
|
|
except KeyError: assert false, "Can never happen"
|
2016-01-28 20:59:26 +00:00
|
|
|
|
2016-02-26 20:13:40 +00:00
|
|
|
proc construct*[T](s: var YamlStream, target: var T) =
|
2016-02-12 18:53:25 +00:00
|
|
|
var
|
|
|
|
context = newConstructionContext()
|
2016-01-26 19:51:21 +00:00
|
|
|
try:
|
2016-02-12 18:53:25 +00:00
|
|
|
var e = s.next()
|
2016-03-14 17:10:34 +00:00
|
|
|
assert(e.kind == yamlStartDoc)
|
2016-01-28 21:29:26 +00:00
|
|
|
|
2016-02-16 18:24:55 +00:00
|
|
|
constructChild(s, context, target)
|
2016-02-12 18:53:25 +00:00
|
|
|
e = s.next()
|
2016-03-14 17:10:34 +00:00
|
|
|
assert(e.kind == yamlEndDoc)
|
2016-02-19 17:25:01 +00:00
|
|
|
except YamlConstructionError:
|
|
|
|
raise (ref YamlConstructionError)(getCurrentException())
|
|
|
|
except YamlStreamError:
|
|
|
|
raise (ref YamlStreamError)(getCurrentException())
|
|
|
|
except AssertionError:
|
|
|
|
raise (ref AssertionError)(getCurrentException())
|
2016-01-26 19:51:21 +00:00
|
|
|
except Exception:
|
|
|
|
# may occur while calling s()
|
2016-02-12 18:53:25 +00:00
|
|
|
var ex = newException(YamlStreamError, "")
|
2016-01-26 19:51:21 +00:00
|
|
|
ex.parent = getCurrentException()
|
|
|
|
raise ex
|
|
|
|
|
2016-02-26 20:13:40 +00:00
|
|
|
proc load*[K](input: Stream, target: var K) =
|
2016-01-26 19:51:21 +00:00
|
|
|
var
|
|
|
|
parser = newYamlParser(serializationTagLibrary)
|
|
|
|
events = parser.parse(input)
|
2016-01-24 19:53:51 +00:00
|
|
|
try:
|
|
|
|
construct(events, target)
|
2016-02-16 18:24:55 +00:00
|
|
|
except YamlConstructionError:
|
|
|
|
var e = (ref YamlConstructionError)(getCurrentException())
|
|
|
|
e.line = parser.getLineNumber()
|
|
|
|
e.column = parser.getColNumber()
|
|
|
|
e.lineContent = parser.getLineContent()
|
|
|
|
raise e
|
2016-02-12 18:53:25 +00:00
|
|
|
except YamlStreamError:
|
|
|
|
let e = (ref YamlStreamError)(getCurrentException())
|
2016-01-24 20:38:29 +00:00
|
|
|
if e.parent of IOError:
|
2016-01-26 19:51:21 +00:00
|
|
|
raise (ref IOError)(e.parent)
|
2016-01-24 20:38:29 +00:00
|
|
|
elif e.parent of YamlParserError:
|
2016-01-26 19:51:21 +00:00
|
|
|
raise (ref YamlParserError)(e.parent)
|
2016-03-17 18:30:40 +00:00
|
|
|
else: assert(false)
|
2015-12-29 17:22:55 +00:00
|
|
|
|
2016-02-22 20:56:30 +00:00
|
|
|
proc setAnchor(a: var AnchorId, q: var Table[pointer, AnchorId])
|
2016-01-28 20:59:26 +00:00
|
|
|
{.inline.} =
|
|
|
|
if a != yAnchorNone:
|
2016-02-22 20:56:30 +00:00
|
|
|
try:a = q[cast[pointer](a)]
|
|
|
|
except KeyError: assert false, "Can never happen"
|
2016-02-12 18:53:25 +00:00
|
|
|
|
2016-02-02 17:19:40 +00:00
|
|
|
proc represent*[T](value: T, ts: TagStyle = tsRootOnly,
|
2016-02-26 20:13:40 +00:00
|
|
|
a: AnchorStyle = asTidy): YamlStream =
|
2016-01-28 20:59:26 +00:00
|
|
|
var
|
|
|
|
context = newSerializationContext(a)
|
2016-02-12 18:53:25 +00:00
|
|
|
objStream = iterator(): YamlStreamEvent =
|
2016-03-14 17:10:34 +00:00
|
|
|
yield YamlStreamEvent(kind: yamlStartDoc)
|
2016-03-25 20:27:41 +00:00
|
|
|
var events = representChild(value, ts, context)
|
2016-02-12 18:53:25 +00:00
|
|
|
while true:
|
|
|
|
let e = events()
|
|
|
|
if finished(events): break
|
|
|
|
yield e
|
2016-03-14 17:10:34 +00:00
|
|
|
yield YamlStreamEvent(kind: yamlEndDoc)
|
2016-01-28 20:59:26 +00:00
|
|
|
if a == asTidy:
|
|
|
|
var objQueue = newSeq[YamlStreamEvent]()
|
|
|
|
try:
|
2016-03-17 18:30:40 +00:00
|
|
|
for event in objStream(): objQueue.add(event)
|
2016-01-28 20:59:26 +00:00
|
|
|
except Exception:
|
|
|
|
assert(false)
|
2016-02-12 18:53:25 +00:00
|
|
|
var backend = iterator(): YamlStreamEvent =
|
2016-01-28 20:59:26 +00:00
|
|
|
for i in countup(0, objQueue.len - 1):
|
|
|
|
var event = objQueue[i]
|
|
|
|
case event.kind
|
|
|
|
of yamlStartMap:
|
2016-02-22 20:56:30 +00:00
|
|
|
event.mapAnchor.setAnchor(context.refs)
|
2016-03-14 17:10:34 +00:00
|
|
|
of yamlStartSeq:
|
2016-02-22 20:56:30 +00:00
|
|
|
event.seqAnchor.setAnchor(context.refs)
|
2016-01-28 20:59:26 +00:00
|
|
|
of yamlScalar:
|
2016-02-22 20:56:30 +00:00
|
|
|
event.scalarAnchor.setAnchor(context.refs)
|
|
|
|
else: discard
|
2016-01-28 20:59:26 +00:00
|
|
|
yield event
|
2016-02-12 18:53:25 +00:00
|
|
|
result = initYamlStream(backend)
|
2016-03-17 18:30:40 +00:00
|
|
|
else: result = initYamlStream(objStream)
|
2016-01-28 20:59:26 +00:00
|
|
|
|
2016-02-26 20:55:59 +00:00
|
|
|
proc dump*[K](value: K, target: Stream, tagStyle: TagStyle = tsRootOnly,
|
|
|
|
anchorStyle: AnchorStyle = asTidy,
|
|
|
|
options: PresentationOptions = defaultPresentationOptions) =
|
|
|
|
var events = represent(value,
|
|
|
|
if options.style == psCanonical: tsAll else: tagStyle,
|
|
|
|
if options.style == psJson: asNone else: anchorStyle)
|
2016-03-17 18:30:40 +00:00
|
|
|
try: present(events, target, serializationTagLibrary, options)
|
2016-02-12 18:53:25 +00:00
|
|
|
except YamlStreamError:
|
2016-01-24 19:38:30 +00:00
|
|
|
# serializing object does not raise any errors, so we can ignore this
|
2016-02-19 17:25:01 +00:00
|
|
|
assert false, "Can never happen"
|