mirror of https://github.com/status-im/NimYAML.git
Implemented construction of ref objects.
This commit is contained in:
parent
96f01385ef
commit
f74a5da999
|
@ -1,5 +1,5 @@
|
||||||
import "../yaml"
|
import "../yaml"
|
||||||
import macros, strutils, streams, tables, json, hashes, typetraits, queues
|
import macros, strutils, streams, tables, json, hashes, typetraits
|
||||||
export yaml, streams, tables, json
|
export yaml, streams, tables, json
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -14,6 +14,9 @@ type
|
||||||
count: int
|
count: int
|
||||||
anchor: AnchorId
|
anchor: AnchorId
|
||||||
|
|
||||||
|
ConstructionContext* = ref object
|
||||||
|
refs: Table[AnchorId, pointer]
|
||||||
|
|
||||||
SerializationContext* = ref object
|
SerializationContext* = ref object
|
||||||
refsList: seq[RefNodeData]
|
refsList: seq[RefNodeData]
|
||||||
style: AnchorStyle
|
style: AnchorStyle
|
||||||
|
@ -36,6 +39,10 @@ proc initRefNodeData(p: pointer): RefNodeData =
|
||||||
result.count = 1
|
result.count = 1
|
||||||
result.anchor = yAnchorNone
|
result.anchor = yAnchorNone
|
||||||
|
|
||||||
|
proc newConstructionContext(): ConstructionContext =
|
||||||
|
new(result)
|
||||||
|
result.refs = initTable[AnchorId, pointer]()
|
||||||
|
|
||||||
proc newSerializationContext(s: AnchorStyle): SerializationContext =
|
proc newSerializationContext(s: AnchorStyle): SerializationContext =
|
||||||
new(result)
|
new(result)
|
||||||
result.refsList = newSeq[RefNodeData]()
|
result.refsList = newSeq[RefNodeData]()
|
||||||
|
@ -160,6 +167,8 @@ macro serializable*(types: stmt): stmt =
|
||||||
var constructProc = newProc(newIdentNode("constructObject"), [
|
var constructProc = newProc(newIdentNode("constructObject"), [
|
||||||
newEmptyNode(),
|
newEmptyNode(),
|
||||||
newIdentDefs(newIdentNode("s"), newIdentNode("YamlStream")),
|
newIdentDefs(newIdentNode("s"), newIdentNode("YamlStream")),
|
||||||
|
newIdentDefs(newIdentNode("c"),
|
||||||
|
newIdentNode("ConstructionContext")),
|
||||||
newIdentDefs(newIdentNode("result"),
|
newIdentDefs(newIdentNode("result"),
|
||||||
newNimNode(nnkVarTy).add(tIdent))])
|
newNimNode(nnkVarTy).add(tIdent))])
|
||||||
constructProc[4] = newNimNode(nnkPragma).add(
|
constructProc[4] = newNimNode(nnkPragma).add(
|
||||||
|
@ -193,6 +202,7 @@ macro serializable*(types: stmt): stmt =
|
||||||
keyCase.insert(1, newNimNode(nnkOfBranch).add(
|
keyCase.insert(1, newNimNode(nnkOfBranch).add(
|
||||||
newStrLitNode($field.name.ident)).add(newStmtList(
|
newStrLitNode($field.name.ident)).add(newStmtList(
|
||||||
newCall("constructObject", [newIdentNode("s"),
|
newCall("constructObject", [newIdentNode("s"),
|
||||||
|
newIdentNode("c"),
|
||||||
newDotExpr(newIdentNode("result"), field.name)])
|
newDotExpr(newIdentNode("result"), field.name)])
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
@ -289,6 +299,8 @@ template constructScalarItem(item: YamlStreamEvent, name: string, t: TagId,
|
||||||
content: stmt) =
|
content: stmt) =
|
||||||
try:
|
try:
|
||||||
item = s()
|
item = s()
|
||||||
|
except YamlConstructionStreamError, AssertionError:
|
||||||
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
var e = newException(YamlConstructionStreamError, "")
|
var e = newException(YamlConstructionStreamError, "")
|
||||||
e.parent = getCurrentException()
|
e.parent = getCurrentException()
|
||||||
|
@ -310,6 +322,8 @@ template constructScalarItem(item: YamlStreamEvent, name: string, t: TagId,
|
||||||
template safeNextEvent(e: YamlStreamEvent, s: YamlStream) =
|
template safeNextEvent(e: YamlStreamEvent, s: YamlStream) =
|
||||||
try:
|
try:
|
||||||
e = s()
|
e = s()
|
||||||
|
except YamlConstructionStreamError, AssertionError:
|
||||||
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
var ex = newException(YamlConstructionStreamError, "")
|
var ex = newException(YamlConstructionStreamError, "")
|
||||||
ex.parent = getCurrentException()
|
ex.parent = getCurrentException()
|
||||||
|
@ -317,7 +331,7 @@ template safeNextEvent(e: YamlStreamEvent, s: YamlStream) =
|
||||||
|
|
||||||
proc yamlTag*(T: typedesc[string]): TagId {.inline, raises: [].} = yTagString
|
proc yamlTag*(T: typedesc[string]): TagId {.inline, raises: [].} = yTagString
|
||||||
|
|
||||||
proc constructObject*(s: YamlStream, result: var string)
|
proc constructObject*(s: YamlStream, c: ConstructionContext, result: var string)
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var item: YamlStreamEvent
|
var item: YamlStreamEvent
|
||||||
constructScalarItem(item, "string", yTagString):
|
constructScalarItem(item, "string", yTagString):
|
||||||
|
@ -333,13 +347,15 @@ proc yamlTag*(T: typedesc[int16]): TagId {.inline, raises: [].} = yTagNimInt16
|
||||||
proc yamlTag*(T: typedesc[int32]): TagId {.inline, raises: [].} = yTagNimInt32
|
proc yamlTag*(T: typedesc[int32]): TagId {.inline, raises: [].} = yTagNimInt32
|
||||||
proc yamlTag*(T: typedesc[int64]): TagId {.inline, raises: [].} = yTagNimInt64
|
proc yamlTag*(T: typedesc[int64]): TagId {.inline, raises: [].} = yTagNimInt64
|
||||||
|
|
||||||
proc constructObject*[T: int8|int16|int32|int64](s: YamlStream, result: var T)
|
proc constructObject*[T: int8|int16|int32|int64](
|
||||||
|
s: YamlStream, c: ConstructionContext, result: var T)
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var item: YamlStreamEvent
|
var item: YamlStreamEvent
|
||||||
constructScalarItem(item, name(T), yamlTag(T)):
|
constructScalarItem(item, name(T), yamlTag(T)):
|
||||||
result = T(parseBiggestInt(item.scalarContent))
|
result = T(parseBiggestInt(item.scalarContent))
|
||||||
|
|
||||||
template constructObject*(s: YamlStream, result: var int) =
|
template constructObject*(s: YamlStream, c: ConstructionContext,
|
||||||
|
result: var int) =
|
||||||
{.fatal: "The length of `int` is platform dependent. Use int[8|16|32|64].".}
|
{.fatal: "The length of `int` is platform dependent. Use int[8|16|32|64].".}
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
@ -371,14 +387,15 @@ proc parseBiggestUInt(s: string): uint64 =
|
||||||
raise newException(ValueError, "Invalid char in uint: " & c)
|
raise newException(ValueError, "Invalid char in uint: " & c)
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc constructObject*[T: uint8|uint16|uint32|uint64](s: YamlStream,
|
proc constructObject*[T: uint8|uint16|uint32|uint64](
|
||||||
result: var T)
|
s: YamlStream, c: ConstructionContext, result: var T)
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var item: YamlStreamEvent
|
var item: YamlStreamEvent
|
||||||
constructScalarItem(item, name[T], yamlTag(T)):
|
constructScalarItem(item, name[T], yamlTag(T)):
|
||||||
result = T(parseBiggestUInt(item.scalarContent))
|
result = T(parseBiggestUInt(item.scalarContent))
|
||||||
|
|
||||||
template constructObject*(s: YamlStream, result: var uint) =
|
template constructObject*(s: YamlStream, c: ConstructionContext,
|
||||||
|
result: var uint) =
|
||||||
{.fatal:
|
{.fatal:
|
||||||
"The length of `uint` is platform dependent. Use uint[8|16|32|64].".}
|
"The length of `uint` is platform dependent. Use uint[8|16|32|64].".}
|
||||||
discard
|
discard
|
||||||
|
@ -399,7 +416,8 @@ proc yamlTag*(T: typedesc[float32]): TagId {.inline, raises: [].} =
|
||||||
proc yamlTag*(T: typedesc[float64]): TagId {.inline, raises: [].} =
|
proc yamlTag*(T: typedesc[float64]): TagId {.inline, raises: [].} =
|
||||||
yTagNimFloat64
|
yTagNimFloat64
|
||||||
|
|
||||||
proc constructObject*[T: float32|float64](s: YamlStream, result: var T)
|
proc constructObject*[T: float32|float64](
|
||||||
|
s: YamlStream, c: ConstructionContext, result: var T)
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var item: YamlStreamEvent
|
var item: YamlStreamEvent
|
||||||
constructScalarItem(item, name(T), yamlTag(T)):
|
constructScalarItem(item, name(T), yamlTag(T)):
|
||||||
|
@ -418,7 +436,8 @@ proc constructObject*[T: float32|float64](s: YamlStream, result: var T)
|
||||||
raise newException(YamlConstructionError,
|
raise newException(YamlConstructionError,
|
||||||
"Cannot construct to float: " & item.scalarContent)
|
"Cannot construct to float: " & item.scalarContent)
|
||||||
|
|
||||||
template constructObject*(s: YamlStream, result: var float) =
|
template constructObject*(s: YamlStream, c: ConstructionContext,
|
||||||
|
result: var float) =
|
||||||
{.fatal: "The length of `float` is platform dependent. Use float[32|64].".}
|
{.fatal: "The length of `float` is platform dependent. Use float[32|64].".}
|
||||||
|
|
||||||
proc serializeObject*[T: float32|float64](value: T, ts: TagStyle,
|
proc serializeObject*[T: float32|float64](value: T, ts: TagStyle,
|
||||||
|
@ -444,7 +463,7 @@ template serializeObject*(value: float, tagStyle: TagStyle,
|
||||||
|
|
||||||
proc yamlTag*(T: typedesc[bool]): TagId {.inline, raises: [].} = yTagBoolean
|
proc yamlTag*(T: typedesc[bool]): TagId {.inline, raises: [].} = yTagBoolean
|
||||||
|
|
||||||
proc constructObject*(s: YamlStream, result: var bool)
|
proc constructObject*(s: YamlStream, c: ConstructionContext, result: var bool)
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var item: YamlStreamEvent
|
var item: YamlStreamEvent
|
||||||
constructScalarItem(item, "bool", yTagBoolean):
|
constructScalarItem(item, "bool", yTagBoolean):
|
||||||
|
@ -465,7 +484,7 @@ proc serializeObject*(value: bool, ts: TagStyle,
|
||||||
|
|
||||||
proc yamlTag*(T: typedesc[char]): TagId {.inline, raises: [].} = yTagNimChar
|
proc yamlTag*(T: typedesc[char]): TagId {.inline, raises: [].} = yTagNimChar
|
||||||
|
|
||||||
proc constructObject*(s: YamlStream, result: var char)
|
proc constructObject*(s: YamlStream, c: ConstructionContext, result: var char)
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var item: YamlStreamEvent
|
var item: YamlStreamEvent
|
||||||
constructScalarItem(item, "char", yTagNimChar):
|
constructScalarItem(item, "char", yTagNimChar):
|
||||||
|
@ -485,7 +504,8 @@ proc yamlTag*[I](T: typedesc[seq[I]]): TagId {.inline, raises: [].} =
|
||||||
let uri = "!nim:seq(" & safeTagUri(yamlTag(I)) & ")"
|
let uri = "!nim:seq(" & safeTagUri(yamlTag(I)) & ")"
|
||||||
result = lazyLoadTag(uri)
|
result = lazyLoadTag(uri)
|
||||||
|
|
||||||
proc constructObject*[T](s: YamlStream, result: var seq[T])
|
proc constructObject*[T](s: YamlStream, c: ConstructionContext,
|
||||||
|
result: var seq[T])
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var event: YamlStreamEvent
|
var event: YamlStreamEvent
|
||||||
safeNextEvent(event, s)
|
safeNextEvent(event, s)
|
||||||
|
@ -501,7 +521,7 @@ proc constructObject*[T](s: YamlStream, result: var seq[T])
|
||||||
item: T
|
item: T
|
||||||
events = prepend(event, s)
|
events = prepend(event, s)
|
||||||
try:
|
try:
|
||||||
constructObject(events, item)
|
constructObject(events, c, item)
|
||||||
except AssertionError: raise
|
except AssertionError: raise
|
||||||
except:
|
except:
|
||||||
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
|
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
|
||||||
|
@ -538,7 +558,8 @@ proc yamlTag*[K, V](T: typedesc[Table[K, V]]): TagId {.inline, raises: [].} =
|
||||||
# cannot happen (theoretically, you known)
|
# cannot happen (theoretically, you known)
|
||||||
assert(false)
|
assert(false)
|
||||||
|
|
||||||
proc constructObject*[K, V](s: YamlStream, result: var Table[K, V])
|
proc constructObject*[K, V](s: YamlStream, c: ConstructionContext,
|
||||||
|
result: var Table[K, V])
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var event: YamlStreamEvent
|
var event: YamlStreamEvent
|
||||||
safeNextEvent(event, s)
|
safeNextEvent(event, s)
|
||||||
|
@ -555,8 +576,8 @@ proc constructObject*[K, V](s: YamlStream, result: var Table[K, V])
|
||||||
value: V
|
value: V
|
||||||
events = prepend(event, s)
|
events = prepend(event, s)
|
||||||
try:
|
try:
|
||||||
constructObject(events, key)
|
constructObject(events, c, key)
|
||||||
constructObject(s, value)
|
constructObject(s, c, value)
|
||||||
except AssertionError: raise
|
except AssertionError: raise
|
||||||
except Exception:
|
except Exception:
|
||||||
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
|
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
|
||||||
|
@ -583,7 +604,8 @@ proc serializeObject*[K, V](value: Table[K, V], ts: TagStyle,
|
||||||
|
|
||||||
proc yamlTag*[O](T: typedesc[ref O]): TagId {.inline, raises: [].} = yamlTag(O)
|
proc yamlTag*[O](T: typedesc[ref O]): TagId {.inline, raises: [].} = yamlTag(O)
|
||||||
|
|
||||||
proc constructObject*[O](s: YamlStream, result: var ref O)
|
proc constructObject*[O](s: YamlStream, c: ConstructionContext,
|
||||||
|
result: var ref O)
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
var e = s()
|
var e = s()
|
||||||
assert(not finished(s))
|
assert(not finished(s))
|
||||||
|
@ -593,10 +615,25 @@ proc constructObject*[O](s: YamlStream, result: var ref O)
|
||||||
guessType(e.scalarContent) == yTypeNull):
|
guessType(e.scalarContent) == yTypeNull):
|
||||||
result = nil
|
result = nil
|
||||||
return
|
return
|
||||||
|
elif e.kind == yamlAlias:
|
||||||
|
try:
|
||||||
|
result = cast[ref O](c.refs[e.aliasTarget])
|
||||||
|
return
|
||||||
|
except KeyError:
|
||||||
|
assert(false)
|
||||||
new(result)
|
new(result)
|
||||||
|
var a: AnchorId
|
||||||
|
case e.kind
|
||||||
|
of yamlScalar: a = e.scalarAnchor
|
||||||
|
of yamlStartMap: a = e.mapAnchor
|
||||||
|
of yamlStartSequence: a = e.seqAnchor
|
||||||
|
else: assert(false)
|
||||||
|
if a != yAnchorNone:
|
||||||
|
assert(not c.refs.hasKey(a))
|
||||||
|
c.refs[a] = cast[pointer](result)
|
||||||
try:
|
try:
|
||||||
constructObject(prepend(e, s), result[])
|
constructObject(prepend(e, s), c, result[])
|
||||||
except YamlConstructionError, YamlConstructionStreamError:
|
except YamlConstructionError, YamlConstructionStreamError, AssertionError:
|
||||||
raise
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
var e = newException(YamlConstructionStreamError,
|
var e = newException(YamlConstructionStreamError,
|
||||||
|
@ -643,10 +680,12 @@ proc serializeObject*[O](value: ref O, ts: TagStyle, c: SerializationContext):
|
||||||
|
|
||||||
proc construct*[T](s: YamlStream, target: var T)
|
proc construct*[T](s: YamlStream, target: var T)
|
||||||
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
|
||||||
|
var context = newConstructionContext()
|
||||||
try:
|
try:
|
||||||
var e = s()
|
var e = s()
|
||||||
assert((not finished(s)) and e.kind == yamlStartDocument)
|
assert((not finished(s)) and e.kind == yamlStartDocument)
|
||||||
constructObject(s, target)
|
|
||||||
|
constructObject(s, context, target)
|
||||||
e = s()
|
e = s()
|
||||||
assert((not finished(s)) and e.kind == yamlEndDocument)
|
assert((not finished(s)) and e.kind == yamlEndDocument)
|
||||||
except YamlConstructionError, YamlConstructionStreamError, AssertionError:
|
except YamlConstructionError, YamlConstructionStreamError, AssertionError:
|
||||||
|
|
Loading…
Reference in New Issue