Added constructChild for better serialization.

- Handle tag and anchor checks and ref types in constructChild
 - Added tests for using custom representObject and constructObject
   procs
 - Code cleanup
This commit is contained in:
Felix Krause 2016-02-16 19:24:55 +01:00
parent 0a7f87a539
commit 9be97ff386
2 changed files with 140 additions and 306 deletions

View File

@ -44,7 +44,7 @@ static:
var existingTuples = newSeq[NimNode]()
template presentTag(t: typedesc, ts: TagStyle): TagId =
template presentTag*(t: typedesc, ts: TagStyle): TagId =
if ts == tsNone: yTagQuestionMark else: yamlTag(t)
template setTagUriForType*(t: typedesc, uri: string): stmt =
@ -52,13 +52,15 @@ template setTagUriForType*(t: typedesc, uri: string): stmt =
## when loading and dumping values of this type.
let id {.gensym.} = serializationTagLibrary.registerUri(uri)
proc yamlTag*(T: typedesc[t]): TagId {.inline, raises: [].} = id
## autogenerated
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
proc yamlTag*(T: typedesc[t]): TagId {.inline, raises: [].} =
## autogenerated
setTagUriForType(char, "!nim:system:char", yTagNimChar)
setTagUriForType(int8, "!nim:system:int8", yTagNimInt8)
@ -79,215 +81,46 @@ proc lazyLoadTag*(uri: string): TagId {.inline, raises: [].} =
except KeyError:
result = serializationTagLibrary.registerUri(uri)
macro serializable*(types: stmt): stmt =
## Macro for customizing serialization of user-defined types.
## Currently does not provide more features than just using the standard
## serialization procs. This will change in the future.
assert types.kind == nnkTypeSection
result = newStmtList(types)
for typedef in types.children:
assert typedef.kind == nnkTypeDef
let
tName = $typedef[0].symbol
tIdent = newIdentNode(tName)
var
tUri: NimNode
recList: NimNode
assert typedef[1].kind == nnkEmpty
let objectTy = typedef[2]
case objectTy.kind
of nnkObjectTy:
assert objectTy[0].kind == nnkEmpty
assert objectTy[1].kind == nnkEmpty
tUri = newStrLitNode("!nim:custom:" & tName)
recList = objectTy[2]
of nnkTupleTy:
if objectTy in existingTuples:
continue
existingTuples.add(objectTy)
recList = objectTy
tUri = newStmtList()
var
first = true
curStrLit = "!nim:tuple("
curInfix = tUri
for field in objectFields(recList):
if first:
first = false
else:
curStrLit &= ","
curStrLit &= $field.name & "="
var tmp = newNimNode(nnkInfix).add(newIdentNode("&"),
newStrLitNode(curStrLit))
curInfix.add(tmp)
curInfix = tmp
tmp = newNimNode(nnkInfix).add(newIdentNode("&"),
newCall("safeTagUri", newCall("yamlTag",
newCall("type", field.t))))
curInfix.add(tmp)
curInfix = tmp
curStrLit = ""
curInfix.add(newStrLitNode(curStrLit & ")"))
tUri = tUri[0]
else:
assert false
# yamlTag()
var yamlTagProc = newProc(newIdentNode("yamlTag"), [
newIdentNode("TagId"),
newIdentDefs(newIdentNode("T"), newNimNode(nnkBracketExpr).add(
newIdentNode("typedesc"), tIdent))])
var impl = newStmtList(newCall("lazyLoadTag", tUri))
yamlTagProc[6] = impl
result.add(yamlTagProc)
# constructObject()
var constructProc = newProc(newIdentNode("constructObject"), [
newEmptyNode(),
newIdentDefs(newIdentNode("s"), newIdentNode("YamlStream")),
newIdentDefs(newIdentNode("c"),
newIdentNode("ConstructionContext")),
newIdentDefs(newIdentNode("result"),
newNimNode(nnkVarTy).add(tIdent))])
constructProc[4] = newNimNode(nnkPragma).add(
newNimNode(nnkExprColonExpr).add(newIdentNode("raises"),
newNimNode(nnkBracket).add(
newIdentNode("YamlConstructionError"),
newIdentNode("YamlStreamError"))))
impl = quote do:
var event = s()
if finished(s) or event.kind != yamlStartMap:
raise newException(YamlConstructionError, "Expected map start")
if event.mapTag != yTagQuestionMark and
event.mapTag != yamlTag(type(`tIdent`)):
raise newException(YamlConstructionError,
"Wrong tag for " & `tName`)
event = s()
assert(not finished(s))
while event.kind != yamlEndMap:
assert event.kind == yamlScalar
assert event.scalarTag in [yTagQuestionMark, yTagString]
case event.scalarContent
else:
raise newException(YamlConstructionError,
"Unknown key for " & `tName` & ": " &
event.scalarContent)
event = s()
assert(not finished(s))
var keyCase = impl[5][1][2]
assert keyCase.kind == nnkCaseStmt
for field in objectFields(recList):
keyCase.insert(1, newNimNode(nnkOfBranch).add(
newStrLitNode($field.name.ident)).add(newStmtList(
newCall("constructObject", [newIdentNode("s"),
newIdentNode("c"),
newDotExpr(newIdentNode("result"), field.name)])
))
)
constructProc[6] = impl
result.add(constructProc)
# representObject()
var representProc = newProc(newIdentNode("representObject"), [
newIdentNode("RawYamlStream"),
newIdentDefs(newIdentNode("value"), tIdent),
newIdentDefs(newIdentNode("ts"),
newIdentNode("TagStyle")),
newIdentDefs(newIdentNode("c"),
newIdentNode("SerializationContext"))])
representProc[4] = newNimNode(nnkPragma).add(
newNimNode(nnkExprColonExpr).add(newIdentNode("raises"),
newNimNode(nnkBracket)))
var iterBody = newStmtList(
newLetStmt(newIdentNode("childTagStyle"), newNimNode(nnkIfExpr).add(
newNimNode(nnkElifExpr).add(
newNimNode(nnkInfix).add(newIdentNode("=="),
newIdentNode("ts"), newIdentNode("tsRootOnly")),
newIdentNode("tsNone")
), newNimNode(nnkElseExpr).add(newIdentNode("ts")))),
newNimNode(nnkYieldStmt).add(
newNimNode(nnkObjConstr).add(newIdentNode("YamlStreamEvent"),
newNimNode(nnkExprColonExpr).add(newIdentNode("kind"),
newIdentNode("yamlStartMap")),
newNimNode(nnkExprColonExpr).add(newIdentNode("mapTag"),
newNimNode(nnkIfExpr).add(newNimNode(nnkElifExpr).add(
newNimNode(nnkInfix).add(newIdentNode("=="),
newIdentNode("ts"),
newIdentNode("tsNone")),
newIdentNode("yTagQuestionMark")
), newNimNode(nnkElseExpr).add(
newCall("yamlTag", newCall("type", tIdent))
))),
newNimNode(nnkExprColonExpr).add(newIdentNode("mapAnchor"),
newIdentNode("yAnchorNone"))
)
), newNimNode(nnkYieldStmt).add(newNimNode(nnkObjConstr).add(
newIdentNode("YamlStreamEvent"), newNimNode(nnkExprColonExpr).add(
newIdentNode("kind"), newIdentNode("yamlEndMap")
)
)))
var i = 2
for field in objectFields(recList):
let
fieldIterIdent = newIdentNode($field.name & "Events")
fieldNameString = newStrLitNode($field.name)
iterbody.insert(i, quote do:
yield YamlStreamEvent(kind: yamlScalar,
scalarTag: presentTag(string,
childTagStyle),
scalarAnchor: yAnchorNone,
scalarContent: `fieldNameString`)
)
iterbody.insert(i + 1, newVarStmt(fieldIterIdent,
newCall("representObject", newDotExpr(newIdentNode("value"),
field.name), newIdentNode("childTagStyle"),
newIdentNode("c"))))
iterbody.insert(i + 2, quote do:
for event in `fieldIterIdent`():
yield event
)
i += 3
impl = newStmtList(newAssignment(newIdentNode("result"), newProc(
newEmptyNode(), [newIdentNode("YamlStreamEvent")], iterBody,
nnkIteratorDef)))
representProc[6] = impl
result.add(representProc)
proc safeTagUri*(id: TagId): string {.raises: [].} =
## Internal function. Do not call explicitly.
try:
let uri = serializationTagLibrary.uri(id)
if uri.len > 0 and uri[0] == '!':
return uri[1..uri.len - 1]
else:
return uri
else: return uri
except KeyError:
# cannot happen (theoretically, you known)
assert(false)
template constructScalarItem(bs: var YamlStream, item: YamlStreamEvent,
name: string, t: TagId, content: stmt) =
template constructScalarItem*(bs: var YamlStream, item: YamlStreamEvent,
name: string, content: stmt) =
item = bs.next()
if item.kind != yamlScalar:
raise newException(YamlConstructionError, "Expected scalar")
if item.scalarTag notin [yTagQuestionMark, yTagExclamationMark, t]:
raise newException(YamlConstructionError, "Wrong tag for " & name)
try:
content
except YamlConstructionError:
raise
try: content
except YamlConstructionError: raise
except Exception:
var e = newException(YamlConstructionError,
"Cannot construct to " & name & ": " & item.scalarContent)
e.parent = getCurrentException()
raise e
proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
result: var T)
{.raises: [YamlConstructionError, YamlStreamError].}
## Used for implementing ``constructObject`` on a non-scalar type. Call it
## for constructing child values of the object that is constructed. It will
## ensure correct tag and anchor on the input stream for the child object
## and then call ``constructObject`` on the child object.
proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
result: var ref O)
{.raises: [YamlConstructionError, YamlStreamError].}
## Used for implementing ``constructObject`` on a non-scalar type. Call it
## for constructing child values of the object that is constructed. It will
## handle anchors, aliases and nil values, and then call ``constructChild``
## on the base type.
proc yamlTag*(T: typedesc[string]): TagId {.inline, noSideEffect, raises: [].} =
yTagString
@ -295,7 +128,7 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
result: var string)
{.raises: [YamlConstructionError, YamlStreamError].} =
var item: YamlStreamEvent
constructScalarItem(s, item, "string", yTagString):
constructScalarItem(s, item, "string"):
result = item.scalarContent
proc representObject*(value: string, ts: TagStyle = tsNone,
@ -307,7 +140,7 @@ 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), yamlTag(T)):
constructScalarItem(s, item, name(T)):
result = T(parseBiggestInt(item.scalarContent))
template constructObject*(s: var YamlStream, c: ConstructionContext,
@ -342,7 +175,7 @@ proc constructObject*[T: uint8|uint16|uint32|uint64](
s: var YamlStream, c: ConstructionContext, result: var T)
{.raises: [YamlConstructionError, YamlStreamError].} =
var item: YamlStreamEvent
constructScalarItem(s, item, name[T], yamlTag(T)):
constructScalarItem(s, item, name[T]):
result = T(parseBiggestUInt(item.scalarContent))
template constructObject*(s: var YamlStream, c: ConstructionContext,
@ -367,7 +200,7 @@ proc constructObject*[T: float32|float64](
s: var YamlStream, c: ConstructionContext, result: var T)
{.raises: [YamlConstructionError, YamlStreamError].} =
var item: YamlStreamEvent
constructScalarItem(s, item, name(T), yamlTag(T)):
constructScalarItem(s, item, name(T)):
let hint = guessType(item.scalarContent)
case hint
of yTypeFloat:
@ -394,14 +227,10 @@ proc representObject*[T: float32|float64](value: T, ts: TagStyle,
var
asString: string
case value
of Inf:
asString = ".inf"
of NegInf:
asString = "-.inf"
of NaN:
asString = ".nan"
else:
asString = $value
of Inf: asString = ".inf"
of NegInf: asString = "-.inf"
of NaN: asString = ".nan"
else: asString = $value
yield scalarEvent(asString, presentTag(T, ts), yAnchorNone)
template representObject*(value: float, tagStyle: TagStyle,
@ -414,7 +243,7 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
result: var bool)
{.raises: [YamlConstructionError, YamlStreamError].} =
var item: YamlStreamEvent
constructScalarItem(s, item, "bool", yTagBoolean):
constructScalarItem(s, item, "bool"):
case guessType(item.scalarContent)
of yTypeBoolTrue:
result = true
@ -434,7 +263,7 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
result: var char)
{.raises: [YamlConstructionError, YamlStreamError].} =
var item: YamlStreamEvent
constructScalarItem(s, item, "char", yTagNimChar):
constructScalarItem(s, item, "char"):
if item.scalarContent.len != 1:
raise newException(YamlConstructionError,
"Cannot construct to char (length != 1): " &
@ -457,17 +286,10 @@ proc constructObject*[T](s: var YamlStream, c: ConstructionContext,
let event = s.next()
if event.kind != yamlStartSequence:
raise newException(YamlConstructionError, "Expected sequence start")
if event.seqTag notin [yTagQuestionMark, yamlTag(seq[T])]:
raise newException(YamlConstructionError, "Wrong tag for seq[T]")
result = newSeq[T]()
while s.peek().kind != yamlEndSequence:
var item: T
try: constructObject(s, c, item)
except AssertionError, YamlConstructionError,
YamlStreamError: raise
except:
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
assert(false)
constructChild(s, c, item)
result.add(item)
discard s.next()
@ -508,20 +330,13 @@ proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext,
if event.kind != yamlStartMap:
raise newException(YamlConstructionError, "Expected map start, got " &
$event.kind)
if event.mapTag notin [yTagQuestionMark, yamlTag(Table[K, V])]:
raise newException(YamlConstructionError, "Wrong tag for Table[K, V]")
result = initTable[K, V]()
while s.peek.kind != yamlEndMap:
var
key: K
value: V
try:
constructObject(s, c, key)
constructObject(s, c, value)
except AssertionError: raise
except Exception:
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
assert(false)
constructChild(s, c, key)
constructChild(s, c, value)
result[key] = value
discard s.next()
@ -566,10 +381,6 @@ template yamlTag*(T: typedesc[tuple]): expr =
try: serializationTagLibrary.tags[uri]
except KeyError: serializationTagLibrary.registerUri(uri)
proc constructObject*[O](s: var YamlStream, c: ConstructionContext,
result: var ref O)
{.raises: [YamlConstructionError, YamlStreamError].}
proc constructObject*[O: object|tuple](s: var YamlStream,
c: ConstructionContext,
result: var O)
@ -578,8 +389,6 @@ proc constructObject*[O: object|tuple](s: var YamlStream,
if e.kind != yamlStartMap:
raise newException(YamlConstructionError, "Expected map start, got " &
$e.kind)
if e.mapAnchor != yAnchorNone:
raise newException(YamlConstructionError, "Anchor on a non-ref type")
while s.peek.kind != yamlEndMap:
let e = s.next()
if e.kind != yamlScalar:
@ -588,7 +397,7 @@ proc constructObject*[O: object|tuple](s: var YamlStream,
let name = e.scalarContent
for fname, value in fieldPairs(result):
if fname == name:
constructObject(s, c, value)
constructChild(s, c, value)
break
discard s.next()
@ -614,11 +423,6 @@ 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 '" &
@ -633,12 +437,38 @@ proc representObject*[O: enum](value: O, ts: TagStyle,
proc yamlTag*[O](T: typedesc[ref O]): TagId {.inline, raises: [].} = yamlTag(O)
proc constructObject*[O](s: var YamlStream, c: ConstructionContext,
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")
of yamlStartSequence:
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,
result: var ref O) =
var e = s.peek()
if e.kind == yamlScalar:
if e.scalarTag == yTagNull or (
e.scalarTag in [yTagQuestionMark, yTagExclamationMark] and
e.scalarTag == yTagQuestionMark and
guessType(e.scalarContent) == yTypeNull):
result = nil
discard s.next()
@ -664,7 +494,7 @@ proc constructObject*[O](s: var YamlStream, c: ConstructionContext,
else: assert(false)
s.peek = e
try:
constructObject(s, c, result[])
constructChild(s, c, result[])
except YamlConstructionError, YamlStreamError, AssertionError:
raise
except Exception:
@ -726,7 +556,7 @@ proc construct*[T](s: var YamlStream, target: var T)
var e = s.next()
assert(e.kind == yamlStartDocument)
constructObject(s, context, target)
constructChild(s, context, target)
e = s.next()
assert(e.kind == yamlEndDocument)
except YamlConstructionError, YamlStreamError, AssertionError:
@ -745,8 +575,12 @@ proc load*[K](input: Stream, target: var K)
events = parser.parse(input)
try:
construct(events, target)
except YamlConstructionError, AssertionError:
raise
except YamlConstructionError:
var e = (ref YamlConstructionError)(getCurrentException())
e.line = parser.getLineNumber()
e.column = parser.getColNumber()
e.lineContent = parser.getLineContent()
raise e
except YamlStreamError:
let e = (ref YamlStreamError)(getCurrentException())
if e.parent of IOError:
@ -755,9 +589,6 @@ proc load*[K](input: Stream, target: var K)
raise (ref YamlParserError)(e.parent)
else:
assert(false)
except Exception:
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
assert(false)
proc setAnchor(a: var AnchorId, q: var seq[RefNodeData], n: var AnchorId)
{.inline.} =
@ -770,8 +601,7 @@ proc setAnchor(a: var AnchorId, q: var seq[RefNodeData], n: var AnchorId)
q[i].anchor = n
a = n
n = AnchorId(int(n) + 1)
else:
a = yAnchorNone
else: a = yAnchorNone
break
proc setAliasAnchor(a: var AnchorId, q: var seq[RefNodeData]) {.inline.} =

View File

@ -1,5 +1,5 @@
import "../yaml"
import unittest
import unittest, strutils
type
MyTuple = tuple
@ -19,8 +19,29 @@ type
value: string
next: ref Node
BetterInt = int
setTagUriForType(TrafficLight, "!tl")
setTagUriForType(Node, "!example.net:Node")
setTagUriForType(BetterInt, "!test:BetterInt")
proc representObject*(value: BetterInt, ts: TagStyle = tsNone,
c: SerializationContext): RawYamlStream {.raises: [].} =
result = iterator(): YamlStreamEvent =
var
val = $value
i = val.len - 3
while i > 0:
val.insert("_", i)
i -= 3
yield scalarEvent(val, presentTag(BetterInt, ts), yAnchorNone)
proc constructObject*(s: var YamlStream, c: ConstructionContext,
result: var BetterInt)
{.raises: [YamlConstructionError, YamlStreamError].} =
var item: YamlStreamEvent
constructScalarItem(s, item, "BetterInt"):
result = BetterInt(parseBiggestInt(item.scalarContent) + 1)
template assertStringEqual(expected, actual: string) =
for i in countup(0, min(expected.len, actual.len)):
@ -40,11 +61,8 @@ suite "Serialization":
test "Serialization: Load string sequence":
let input = newStringStream(" - a\n - b")
var
result: seq[string]
parser = newYamlParser(tagLib)
events = parser.parse(input)
construct(events, result)
var result: seq[string]
load(input, result)
assert result.len == 2
assert result[0] == "a"
assert result[1] == "b"
@ -57,11 +75,8 @@ suite "Serialization":
test "Serialization: Load Table[int, string]":
let input = newStringStream("23: dreiundzwanzig\n42: zweiundvierzig")
var
result: Table[int32, string]
parser = newYamlParser(tagLib)
events = parser.parse(input)
construct(events, result)
var result: Table[int32, string]
load(input, result)
assert result.len == 2
assert result[23] == "dreiundzwanzig"
assert result[42] == "zweiundvierzig"
@ -78,11 +93,8 @@ suite "Serialization":
test "Serialization: Load Sequences in Sequence":
let input = newStringStream(" - [1, 2, 3]\n - [4, 5]\n - [6]")
var
result: seq[seq[int32]]
parser = newYamlParser(tagLib)
events = parser.parse(input)
construct(events, result)
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]
@ -98,11 +110,8 @@ suite "Serialization":
test "Serialization: Load Enum":
let input = newStringStream("!nim:system:seq(tl)\n- !tl tlRed\n- tlGreen\n- tlYellow")
var
result: seq[TrafficLight]
parser = newYamlParser(tagLib)
events = parser.parse(input)
construct(events, result)
var result: seq[TrafficLight]
load(input, result)
assert result.len == 3
assert result[0] == tlRed
assert result[1] == tlGreen
@ -117,11 +126,8 @@ suite "Serialization":
test "Serialization: Load Tuple":
let input = newStringStream("str: value\ni: 42\nb: true")
var
result: MyTuple
parser = newYamlParser(tagLib)
events = parser.parse(input)
construct(events, result)
var result: MyTuple
load(input, result)
assert result.str == "value"
assert result.i == 42
assert result.b == true
@ -135,11 +141,8 @@ suite "Serialization":
test "Serialization: Load custom object":
let input = newStringStream("firstnamechar: P\nsurname: Pan\nage: 12")
var
result: Person
parser = newYamlParser(tagLib)
events = parser.parse(input)
construct(events, result)
var result: Person
load(input, result)
assert result.firstnamechar == 'P'
assert result.surname == "Pan"
assert result.age == 12
@ -155,11 +158,8 @@ suite "Serialization":
test "Serialization: Load sequence with explicit tags":
let input = newStringStream("--- !nim:system:seq(" &
"tag:yaml.org,2002:str)\n- !!str one\n- !!str two")
var
result: seq[string]
parser = newYamlParser(tagLib)
events = parser.parse(input)
construct(events, result)
var result: seq[string]
load(input, result)
assert result[0] == "one"
assert result[1] == "two"
@ -174,11 +174,8 @@ suite "Serialization":
test "Serialization: Load custom object with explicit root tag":
let input = newStringStream(
"--- !nim:custom:Person\nfirstnamechar: P\nsurname: Pan\nage: 12")
var
result: Person
parser = newYamlParser(tagLib)
events = parser.parse(input)
construct(events, result)
var result: Person
load(input, result)
assert result.firstnamechar == 'P'
assert result.surname == "Pan"
assert result.age == 12
@ -223,17 +220,12 @@ next:
- *b
- *c
""")
var
result: seq[ref Node]
parser = newYamlParser(tagLib)
events = parser.parse(input)
try:
construct(events, result)
var result: seq[ref Node]
try: load(input, result)
except YamlConstructionError:
let ex = (ref YamlConstructionError)(getCurrentException())
echo "line ", parser.getLineNumber, ", column ",
parser.getColNumber, ": ", ex.msg
echo parser.getLineContent
echo "line ", ex.line, ", column ", ex.column, ": ", ex.msg
echo ex.lineContent
raise ex
assert(result.len == 3)
@ -246,17 +238,12 @@ next:
test "Serialization: Load nil values":
let input = newStringStream("- ~\n- !!str ~")
var
result: seq[ref string]
parser = newYamlParser(tagLib)
events = parser.parse(input)
try:
construct(events, result)
var result: seq[ref string]
try: load(input, result)
except YamlConstructionError:
let ex = (ref YamlConstructionError)(getCurrentException())
echo "line ", parser.getLineNumber, ", column ",
parser.getColNumber, ": ", ex.msg
echo parser.getLineContent
echo "line ", ex.line, ", column ", ex.column, ": ", ex.msg
echo ex.lineContent
raise ex
assert(result.len == 2)
@ -273,3 +260,20 @@ next:
assertStringEqual "%YAML 1.2\n--- !nim:system:seq(tag:yaml.org,2002:str) \n- !!null ~\n- !!str ~",
output.data
test "Serialization: Custom constructObject":
let input = newStringStream("- 1\n- !test:BetterInt 2")
var result: seq[BetterInt]
load(input, result)
assert(result.len == 2)
assert(result[0] == 2)
assert(result[1] == 3)
test "Serialization: Custom representObject":
let input = @[1.BetterInt, 9998887.BetterInt, 98312.BetterInt]
var output = newStringStream()
dump(input, output, psBlockOnly, tsAll)
assertStringEqual """%YAML 1.2
--- !nim:system:seq(test:BetterInt)
- !test:BetterInt 1
- !test:BetterInt 9_998_887
- !test:BetterInt 98_312""", output.data