mirror of https://github.com/status-im/NimYAML.git
Can construct basic types and custom objects
* Added construct() procs for some basic types * Added macro make_serializable
This commit is contained in:
parent
6617033fd5
commit
dc1a3c0fe2
|
@ -2,6 +2,7 @@ nimcache
|
|||
test/tests
|
||||
test/parsing
|
||||
test/lexing
|
||||
test/serializing
|
||||
test/*.exe
|
||||
test/*.pdb
|
||||
test/*.ilk
|
||||
|
|
|
@ -18,6 +18,11 @@ task parserTests, "Run parser tests":
|
|||
--verbosity:0
|
||||
setCommand "c", "test/parsing"
|
||||
|
||||
task serializationTests, "Run serialization tests":
|
||||
--r
|
||||
--verbosity:0
|
||||
setCommand "c", "test/serializing"
|
||||
|
||||
task doc, "Generate documentation":
|
||||
setCommand "doc2", "yaml"
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import "../yaml/serialization"
|
||||
import unittest
|
||||
|
||||
make_serializable:
|
||||
type
|
||||
Person = object
|
||||
firstname, surname: string
|
||||
age: int
|
||||
|
||||
suite "Serialization":
|
||||
setup:
|
||||
var parser = newParser(coreTagLibrary())
|
||||
|
||||
test "Load string sequence":
|
||||
let input = newStringStream(" - a\n - b")
|
||||
var
|
||||
result: seq[string]
|
||||
events = parser.parse(input)
|
||||
assert events().kind == yamlStartDocument
|
||||
construct(events, result)
|
||||
assert events().kind == yamlEndDocument
|
||||
assert result.len == 2
|
||||
assert result[0] == "a"
|
||||
assert result[1] == "b"
|
||||
|
||||
test "Load Table[int, string]":
|
||||
let input = newStringStream("23: dreiundzwanzig\n42: zweiundvierzig")
|
||||
var
|
||||
result: Table[int, string]
|
||||
events = parser.parse(input)
|
||||
assert events().kind == yamlStartDocument
|
||||
construct(events, result)
|
||||
assert events().kind == yamlEndDocument
|
||||
assert result.len == 2
|
||||
assert result[23] == "dreiundzwanzig"
|
||||
assert result[42] == "zweiundvierzig"
|
||||
|
||||
test "Load Sequences in Sequence":
|
||||
let input = newStringStream(" - [1, 2, 3]\n - [4, 5]\n - [6]")
|
||||
var
|
||||
result: seq[seq[int]]
|
||||
events = parser.parse(input)
|
||||
assert events().kind == yamlStartDocument
|
||||
construct(events, result)
|
||||
assert events().kind == yamlEndDocument
|
||||
assert result.len == 3
|
||||
assert result[0] == @[1, 2, 3]
|
||||
assert result[1] == @[4, 5]
|
||||
assert result[2] == @[6]
|
||||
|
||||
test "Load custom object":
|
||||
let input = newStringStream("firstname: Peter\nsurname: Pan\nage: 12")
|
||||
var
|
||||
result: Person
|
||||
events = parser.parse(input)
|
||||
assert events().kind == yamlStartDocument
|
||||
construct(events, result)
|
||||
assert events().kind == yamlEndDocument
|
||||
assert result.firstname == "Peter"
|
||||
assert result.surname == "Pan"
|
||||
assert result.age == 12
|
|
@ -1 +1 @@
|
|||
import lexing, parsing
|
||||
import lexing, parsing, serializing
|
Binary file not shown.
|
@ -0,0 +1,172 @@
|
|||
import "../yaml"
|
||||
import macros, strutils, streams, tables, json, hashes
|
||||
export yaml, streams, tables, json
|
||||
|
||||
static:
|
||||
iterator objectFields(n: NimNode): tuple[name: NimNode, t: NimNode] =
|
||||
assert n.kind == nnkRecList
|
||||
for identDefs in n.children:
|
||||
let numFields = identDefs.len - 2
|
||||
for i in 0..numFields - 1:
|
||||
yield (name: identDefs[i], t: identDefs[^2])
|
||||
|
||||
macro make_serializable*(types: stmt): stmt =
|
||||
assert types.kind == nnkTypeSection
|
||||
result = newStmtList(types)
|
||||
for typedef in types.children:
|
||||
assert typedef.kind == nnkTypeDef
|
||||
let
|
||||
tName = $typedef[0].symbol
|
||||
tIdent = newIdentNode(tName)
|
||||
assert typedef[1].kind == nnkEmpty
|
||||
let objectTy = typedef[2]
|
||||
assert objectTy.kind == nnkObjectTy
|
||||
assert objectTy[0].kind == nnkEmpty
|
||||
assert objectTy[1].kind == nnkEmpty
|
||||
let recList = objectTy[2]
|
||||
assert recList.kind == nnkRecList
|
||||
var constructProc = newProc(newIdentNode("construct"), [
|
||||
newEmptyNode(),
|
||||
newIdentDefs(newIdentNode("s"), newNimNode(nnkVarTy).add(
|
||||
newIdentNode("YamlStream"))),
|
||||
newIdentDefs(newIdentNode("result"),
|
||||
newNimNode(nnkVarTy).add(tIdent))])
|
||||
var impl = quote do:
|
||||
var event = s()
|
||||
if finished(s) or event.kind != yamlStartMap:
|
||||
raise newException(ValueError, "Construction error!" & $event.scalarContent)
|
||||
if event.mapTag != yTagQuestionMark:
|
||||
raise newException(ValueError, "Wrong tag for " & `tName`)
|
||||
event = s()
|
||||
if finished(s):
|
||||
raise newException(ValueError, "Construction error! b")
|
||||
while event.kind != yamlEndMap:
|
||||
assert event.kind == yamlScalar
|
||||
assert event.scalarTag == yTagQuestionMark
|
||||
case hash(event.scalarContent)
|
||||
else:
|
||||
raise newException(ValueError, "Unknown key for " &
|
||||
`tName` & ": " & event.scalarContent)
|
||||
event = s()
|
||||
if finished(s):
|
||||
raise newException(ValueError, "Construction error! c")
|
||||
var keyCase = impl[5][1][2]
|
||||
assert keyCase.kind == nnkCaseStmt
|
||||
for field in objectFields(recList):
|
||||
let nameHash = hash($field.name.ident)
|
||||
keyCase.insert(1, newNimNode(nnkOfBranch).add(
|
||||
newIntLitNode(nameHash)).add(newStmtList(
|
||||
newCall("construct", [newIdentNode("s"), newDotExpr(
|
||||
newIdentNode("result"), field.name)])
|
||||
))
|
||||
)
|
||||
|
||||
constructProc[6] = impl
|
||||
result.add(constructProc)
|
||||
|
||||
proc prepend*(event: YamlStreamEvent, s: YamlStream): YamlStream =
|
||||
result = iterator(): YamlStreamEvent =
|
||||
yield event
|
||||
for e in s():
|
||||
yield e
|
||||
|
||||
proc construct*(s: var YamlStream, result: var string) =
|
||||
let item = s()
|
||||
if finished(s) or item.kind != yamlScalar:
|
||||
raise newException(ValueError, "Construction error!")
|
||||
if item.scalarTag notin [yTagQuestionMark, yTagExclamationMark, yTagString]:
|
||||
raise newException(ValueError, "Wrong tag for string.")
|
||||
result = item.scalarContent
|
||||
|
||||
proc construct*(s: var YamlStream, result: var int) =
|
||||
let item = s()
|
||||
if finished(s) or item.kind != yamlScalar:
|
||||
raise newException(ValueError, "Construction error!")
|
||||
if item.scalarTag notin [yTagQuestionMark, yTagInteger] or
|
||||
item.scalarType != yTypeInteger:
|
||||
raise newException(ValueError, "Wrong scalar type for int.")
|
||||
result = parseInt(item.scalarContent)
|
||||
|
||||
proc contruct*(s: var YamlStream, result: var int64) =
|
||||
let item = s()
|
||||
if finished(s) or item.kind != yamlScalar:
|
||||
raise newException(ValueError, "Construction error!")
|
||||
if item.scalarTag notin [yTagQuestionMark, yTagInteger] or
|
||||
item.scalarType != yTypeInteger:
|
||||
raise newException(ValueError, "Wrong scalar type for int64.")
|
||||
result = parseBiggestInt(item.scalarContent)
|
||||
|
||||
proc construct*(s: var YamlStream, result: var float) =
|
||||
let item = s()
|
||||
if finished(s) or item.kind != yamlScalar:
|
||||
raise newException(ValueError, "Construction error!")
|
||||
if item.scalarTag notin [yTagQuestionMark, yTagFloat]:
|
||||
raise newException(ValueError, "Wrong scalar type for float.")
|
||||
case item.scalarType
|
||||
of yTypeFloat:
|
||||
result = parseFloat(item.scalarContent)
|
||||
of yTypeFloatInf:
|
||||
if item.scalarContent[0] == '-':
|
||||
result = NegInf
|
||||
else:
|
||||
result = Inf
|
||||
of yTypeFloatNaN:
|
||||
result = NaN
|
||||
else:
|
||||
raise newException(ValueError, "Wrong scalar type for float.")
|
||||
|
||||
proc construct*(s: var YamlStream, result: var bool) =
|
||||
let item = s()
|
||||
if finished(s) or item.kind != yamlScalar:
|
||||
raise newException(ValueError, "Construction error!")
|
||||
if item.scalarTag notin [yTagQuestionMark, yTagBoolean]:
|
||||
raise newException(ValueError, "Wrong scalar type for bool.")
|
||||
case item.scalarType
|
||||
of yTypeBoolTrue:
|
||||
result = true
|
||||
of yTypeBoolFalse:
|
||||
result = false
|
||||
else:
|
||||
raise newException(ValueError, "Wrong scalar type for bool.")
|
||||
|
||||
proc construct*[T](s: var YamlStream, result: var seq[T]) =
|
||||
var event = s()
|
||||
if finished(s) or event.kind != yamlStartSequence:
|
||||
raise newException(ValueError, "Construction error!")
|
||||
if event.seqTag != yTagQuestionMark:
|
||||
raise newException(ValueError, "Wrong sequence type for seq[T]")
|
||||
result = newSeq[T]()
|
||||
event = s()
|
||||
if finished(s):
|
||||
raise newException(ValueError, "Construction error!")
|
||||
while event.kind != yamlEndSequence:
|
||||
var
|
||||
item: T
|
||||
events = prepend(event, s)
|
||||
construct(events, item)
|
||||
result.add(item)
|
||||
event = s()
|
||||
if finished(s):
|
||||
raise newException(ValueError, "Construction error!")
|
||||
|
||||
proc construct*[K, V](s: var YamlStream, result: var Table[K, V]) =
|
||||
var event = s()
|
||||
if finished(s) or event.kind != yamlStartMap:
|
||||
raise newException(ValueError, "Construction error!")
|
||||
if event.mapTag != yTagQuestionMark:
|
||||
raise newException(ValueError, "Wrong map type for Table[K, V]")
|
||||
result = initTable[K, V]()
|
||||
event = s()
|
||||
if finished(s):
|
||||
raise newException(ValueError, "Construction error!")
|
||||
while event.kind != yamlEndMap:
|
||||
var
|
||||
key: K
|
||||
value: V
|
||||
events = prepend(event, s)
|
||||
construct(events, key)
|
||||
construct(s, value)
|
||||
result[key] = value
|
||||
event = s()
|
||||
if finished(s):
|
||||
raise newException(ValueError, "Construction error!")
|
Loading…
Reference in New Issue