Merge branch 'master' of github.com:flyx/NimYAML

This commit is contained in:
Felix Krause 2016-01-24 21:41:16 +01:00
commit daafa8b8e8
10 changed files with 331 additions and 205 deletions

View File

@ -26,7 +26,7 @@ a list:
"""
var
parser = newParser(coreTagLibrary())
parser = newYamlParser(initCoreTagLibrary())
events = parser.parse(newStringStream(input))
for event in events():
@ -60,13 +60,13 @@ import yaml, streams
proc example(): YamlStream =
result = iterator(): YamlStreamEvent =
yield startDocEvent()
yield startMapEvent(mayHaveKeyObjects = false)
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, typeHint = yTypeBoolFalse)
yield scalarEvent("no", tag = yTagBoolean)
yield scalarEvent("")
yield endSeqEvent()
yield scalarEvent("a float")
@ -74,11 +74,11 @@ proc example(): YamlStream =
yield endMapEvent()
yield endDocEvent()
present(example(), newFileStream(stdout), coreTagLibrary(), yDumpBlockOnly)
present(example(), newFileStream(stdout), initCoreTagLibrary(), psBlockOnly)
echo "\n\n"
present(example(), newFileStream(stdout), coreTagLibrary(), yDumpCanonical)
present(example(), newFileStream(stdout), initCoreTagLibrary(), psCanonical)
echo "\n\n"
present(example(), newFileStream(stdout), coreTagLibrary(), yDumpJson)
present(example(), newFileStream(stdout), initCoreTagLibrary(), psJson)
```
Output:
@ -129,7 +129,7 @@ a float: !!float 3.14159
import yaml.serialization
import tables
make_serializable:
serializable:
type
Person = object
firstname, surname: string
@ -162,7 +162,7 @@ assert persons[1].additionalAttributes["location"] == "Celle"
# dumping
dump(persons, newFileStream(stdout), ypsCanonical)
dump(persons, newFileStream(stdout), psCanonical)
```
Output:
@ -177,9 +177,9 @@ Output:
? !!str "surname"
: !!str "Pan",
? !!str "age"
: !!int "12",
: !nim:int "12",
? !!str "additionalAttributes"
: {
: !nim:Table(tag:yaml.org,2002:str,tag:yaml.org,2002:str) {
? !!str "canFly"
: !!str "yes",
? !!str "location"
@ -192,9 +192,9 @@ Output:
? !!str "surname"
: !!str "Koch",
? !!str "age"
: !!int "23",
: !nim:int "23",
? !!str "additionalAttributes"
: {
: !nim:Table(tag:yaml.org,2002:str,tag:yaml.org,2002:str) {
? !!str "occupation"
: !!str "Hacker",
? !!str "location"
@ -208,7 +208,7 @@ Output:
* Documentation:
- Document yaml.serialization
* Lexer:
* Misc:
- Add type hints for more scalar types
* Serialization:
- Support for more standard library types
@ -225,10 +225,6 @@ Output:
- Possibly use `genSym` for predefined and generated `yamlTag` procs because
they are an implementation detail and should not be visible to the caller.
same goes for `lazyLoadTag` and `safeLoadUri`.
* General:
- Proper error handling (do not use `ValueError` for everything)
- Proper error handling, seriously
- Document exceptions with `raises` pragmas in code
## License

View File

@ -8,11 +8,6 @@ task tests, "Run all tests":
--verbosity:0
setCommand "c", "test/tests"
task lexerTests, "Run lexer tests":
--r
--verbosity:0
setCommand "c", "test/lexing"
task parserTests, "Run parser tests":
--r
--verbosity:0
@ -25,8 +20,8 @@ task serializationTests, "Run serialization tests":
task documentation, "Generate documentation":
exec "mkdir -p docout"
exec r"nim doc2 -o:docout/yaml.html yaml"
exec r"nim doc2 -o:docout/serialization.html yaml/serialization.nim"
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 doc2 -o:docout/serialization.html --docSeeSrcUrl:https://github.com/flyx/NimYAML/blob/`git log -n 1 --format=%H` yaml/serialization.nim"
exec r"nim rst2html -o:docout/index.html doc/index.txt"
exec "cp doc/docutils.css doc/style.css doc/testing.html docout"
setCommand "nop"

View File

@ -66,6 +66,15 @@ html {
background-color: rgba(252, 248, 244, 0.75);
}
/* necessary for links to scroll to the right position */
dt:before {
margin-top: -50px;
height: 50px;
content: ' ';
display: block;
visibility: hidden;
}
#testingground textarea {
width: 100%;
height: 100%;

View File

@ -136,7 +136,7 @@ template handleObjectStart(k: YamlStreamEventKind) {.dirty.} =
debug("started sequence at " & (if level.indentation == -1: $indentation else:
$level.indentation))
level.kind = fplSequence
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
if level.indentation == -1:
level.indentation = indentation
@ -183,7 +183,7 @@ template handleMapKeyIndicator() {.dirty.} =
of fplMapValue:
if level.indentation != indentation:
parserError("Invalid indentation of map key indicator")
yield scalarEvent("", yTagQuestionmark, yAnchorNone)
yield scalarEvent("", yTagQuestionMark, yAnchorNone)
level.kind = fplMapKey
ancestry.add(level)
level = FastParseLevel(kind: fplUnknown, indentation: -1)
@ -205,16 +205,16 @@ template handleMapValueIndicator() {.dirty.} =
of fplUnknown:
if level.indentation == -1:
handleObjectStart(yamlStartMap)
yield scalarEvent("", yTagQuestionmark, yAnchorNone)
yield scalarEvent("", yTagQuestionMark, yAnchorNone)
else:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
ancestry[ancestry.high].kind = fplMapValue
of fplMapKey:
if level.indentation != indentation:
parserError("Invalid indentation of map key indicator")
yield scalarEvent("", yTagQuestionmark, yAnchorNone)
yield scalarEvent("", yTagQuestionMark, yAnchorNone)
level.kind = fplMapValue
ancestry.add(level)
level = FastParseLevel(kind: fplUnknown, indentation: -1)
@ -238,14 +238,14 @@ template initDocValues() {.dirty.} =
shorthands["!!"] = "tag:yaml.org,2002:"
nextAnchorId = 0.AnchorId
level = FastParseLevel(kind: fplUnknown, indentation: -1)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
template handleTagHandle() {.dirty.} =
startToken()
if level.kind != fplUnknown:
parserError("Unexpected tag handle")
if tag != yTagQuestionmark:
if tag != yTagQuestionMark:
parserError("Only one tag handle is allowed per node")
content = ""
var
@ -281,7 +281,7 @@ template handleAlias() {.dirty.} =
startToken()
if level.kind != fplUnknown:
parserError("Unexpected token")
if anchor != yAnchorNone or tag != yTagQuestionmark:
if anchor != yAnchorNone or tag != yTagQuestionMark:
parserError("Alias may not have anchor or tag")
content = ""
p.lexer.anchorName(content)
@ -338,7 +338,7 @@ template handleBlockItemStart() {.dirty.} =
level = FastParseLevel(kind: fplUnknown, indentation: indentation)
of fplMapValue:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
level.kind = fplMapKey
ancestry.add(level)
@ -1313,8 +1313,8 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
var stateAfter: FastParseState
content = ""
p.lexer.blockScalar(content, stateAfter)
if tag == yTagQuestionmark:
tag = yTagExclamationmark
if tag == yTagQuestionMark:
tag = yTagExclamationMark
yield scalarEvent(content, tag, anchor)
handleObjectEnd(stateAfter)
of '-':
@ -1424,14 +1424,14 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
case level.kind
of fplMapValue:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
level.kind = fplMapKey
of fplMapKey:
if tag != yTagQuestionmark or anchor != yAnchorNone or
if tag != yTagQuestionMark or anchor != yAnchorNone or
explicitFlowKey:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
yield scalarEvent("", tag, anchor)
of fplSequence:
@ -1446,9 +1446,9 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
level = ancestry.pop()
case level.kind
of fplSequence:
if tag != yTagQuestionmark or anchor != yAnchorNone:
if tag != yTagQuestionMark or anchor != yAnchorNone:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
of fplMapKey, fplMapValue:
startToken()
@ -1463,17 +1463,17 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
case level.kind
of fplSequence:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
of fplMapValue:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
level.kind = fplMapKey
explicitFlowKey = false
of fplMapKey:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
yield scalarEvent("", tag, anchor)
explicitFlowKey = false
@ -1492,7 +1492,7 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
parserError("Unexpected token (expected ',')")
of fplMapKey:
yield scalarEvent("", tag, anchor)
tag = yTagQuestionmark
tag = yTagQuestionMark
anchor = yAnchorNone
level.kind = fplMapValue
of fplUnknown, fplScalar:
@ -1514,8 +1514,8 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
content = ""
startToken()
p.lexer.doubleQuotedScalar(content)
if tag == yTagQuestionmark:
tag = yTagExclamationmark
if tag == yTagQuestionMark:
tag = yTagExclamationMark
yield scalarEvent(content, tag, anchor)
handleObjectEnd(fpFlowAfterObject)
of '!':
@ -1567,7 +1567,7 @@ proc parse*(p: YamlParser, s: Stream): YamlStream =
of fplSequence:
discard
of fplMapValue:
yield scalarEvent("", yTagQuestionmark, yAnchorNone)
yield scalarEvent("", yTagQuestionMark, yAnchorNone)
level.kind = fplMapKey
explicitFlowKey = false
of fplMapKey:

View File

@ -206,9 +206,9 @@ proc loadToJson*(s: Stream): seq[JsonNode] =
raise e
except YamlConstructionStreamError:
let e = getCurrentException()
if e.parent is IOError:
if e.parent of IOError:
raise cast[ref IOError](e.parent)
elif e.parent is YamlParserError:
elif e.parent of YamlParserError:
raise cast[ref YamlParserError](e.parent)
else:
# can never happen

View File

@ -4,6 +4,8 @@
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
import typetraits
type
DumperState = enum
dBlockExplicitMapKey, dBlockImplicitMapKey, dBlockMapValue,
@ -12,7 +14,7 @@ type
dFlowSequenceStart
proc needsEscaping(scalar: string): bool {.raises: [].} =
scalar.len == 0 or
scalar.len == 0 or scalar[0] in ['@', '`'] or
scalar.find({'{', '}', '[', ']', ',', '#', '-', ':', '?', '%', '"',
'\'', '\x0A', '\c'}) != -1
@ -164,7 +166,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
if finished(s):
break
cached.enqueue(item)
except:
except Exception:
var e = newException(YamlPresenterStreamError, "")
e.parent = getCurrentException()
raise e
@ -208,10 +210,16 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
elif item.scalarTag in [yTagQuestionMark, yTagNull] and
hint == yTypeNull:
safeWrite("null")
elif item.scalarTag in [yTagQuestionMark, yTagInteger] and
hint == yTypeInteger:
safeWrite(item.scalarContent)
elif item.scalarTag in [yTagQuestionMark, yTagFloat] and
hint in [yTypeFloatInf, yTypeFloatNaN]:
raise newException(YamlPresenterJsonError,
"Infinity and not-a-number values cannot be presented as JSON!")
elif item.scalarTag in [yTagQuestionMark, yTagFloat] and
hint == yTypeFloat:
safeWrite(item.scalarContent)
else:
writeDoubleQuoted(item.scalarContent, target)
elif style == psCanonical or item.scalarContent.needsEscaping:
@ -251,7 +259,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
else:
length = high(int)
break
except:
except Exception:
var e = newException(YamlPresenterStreamError, "")
e.parent = getCurrentException()
raise e
@ -316,7 +324,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
break
else:
mps = mpNeedBlock
except:
except Exception:
var e = newException(YamlPresenterStreamError, "")
e.parent = getCurrentException()
raise e
@ -442,7 +450,7 @@ proc present*(s: YamlStream, target: Stream, tagLib: TagLibrary,
if finished(s):
break
cached.enqueue(next)
except:
except Exception:
var e = newException(YamlPresenterStreamError, "")
e.parent = getCurrentException()
raise e
@ -493,9 +501,9 @@ proc transform*(input: Stream, output: Stream, style: PresentationStyle,
present(events, output, tagLib, style, indentationStep)
except YamlPresenterStreamError:
let e = getCurrentException()
if e.parent is IOError:
if e.parent of IOError:
raise cast[ref IOError](e.parent)
elif e.parent is YamlParserError:
elif e.parent of YamlParserError:
raise cast[ref YamlParserError](e.parent)
else:
# never happens

46
test/constructingJson.nim Normal file
View File

@ -0,0 +1,46 @@
import "../yaml"
import unittest, json
proc wc(line, column: int, lineContent: string, message: string) =
echo "Warning (", line, ",", column, "): ", message, "\n", lineContent
proc ensureEqual(yamlIn, jsonIn: string) =
var
parser = newYamlParser(initCoreTagLibrary(), wc)
yamlResult = constructJson(parser.parse(newStringStream(yamlIn)))
jsonResult = parseJson(jsonIn)
assert yamlResult.len == 1
assert(jsonResult == yamlResult[0])
suite "Constructing JSON":
test "Constructing JSON: Simple Sequence":
ensureEqual("- 1\n- 2\n- 3", "[1, 2, 3]")
test "Constructing JSON: Simple Map":
ensureEqual("a: b\nc: d", """{"a": "b", "c": "d"}""")
test "Constructing JSON: Complex Structure":
ensureEqual("""
%YAML 1.2
---
Foo:
- - a
- b
- c
- bla: blubb
Numbers, bools, special values:
- 1
- true
- ~
- 42.23
- no
""", """{
"Foo": [
[ "a", "b", "c"],
{ "bla": "blubb"}
],
"Numbers, bools, special values": [
1, true, null, 42.23, false
]
}""")

View File

@ -1,7 +1,7 @@
import "../yaml/serialization"
import unittest
make_serializable:
serializable:
type
Person = object
firstname, surname: string

View File

@ -27,7 +27,7 @@ type
TypeHint* = enum
## A type hint can be computed from scalar content and tells you what
## NimYAML thinks the scalar's type is. It is generated by
## `guessType <#guessType,string,TypeHint>`_ The first matching RegEx
## `guessType <#guessType,string>`_ The first matching RegEx
## in the following table will be the type hint of a scalar string.
##
## You can use it to determine the type of YAML scalars that have a '?'
@ -118,14 +118,9 @@ type
TagLibrary* = ref object
## A ``TagLibrary`` maps tag URIs to ``TagId`` s.
##
## Three tag libraries are provided with this module:
## `failsafeTagLibrary <#failsafeTagLibrary>`_,
## `coreTagLibrary <#coreTagLibrary>`_, and
## `extendedTagLibrary <#extendedTagLibrary>`_.
##
## When `YamlParser <#YamlParser>`_ encounters tags not existing in the
## tag library, it will use
## `registerTagUri <#registerTagUri,TagLibrary,string,TagId>`_ to add
## `registerTagUri <#registerTagUri,TagLibrary,string>`_ to add
## the tag to the library.
##
## You can base your tag library on common tag libraries by initializing
@ -148,7 +143,7 @@ type
YamlParser* = ref object
## A parser object. Retains its ``TagLibrary`` across calls to
## `parse <#parse,YamlParser,Stream,YamlStream>`_. Can be used
## `parse <#parse,YamlParser,Stream>`_. Can be used
## to access anchor names while parsing a YAML character stream, but
## only until the document goes out of scope (i.e. until
## ``yamlEndDocument`` is yielded).

View File

@ -6,18 +6,27 @@ type
TagStyle* = enum
tsNone, tsRootOnly, tsAll
proc initSerializationTagLibrary(): TagLibrary =
const
yTagNimInt* = 100.TagId
yTagNimInt64* = 101.TagId
yTagNimFloat* = 102.TagId
yTagNimFloat64* = 103.TagId
proc initSerializationTagLibrary(): TagLibrary {.raises: [].} =
result = initTagLibrary()
result.tags["!"] = yTagExclamationMark
result.tags["?"] = yTagQuestionMark
result.tags["tag:yaml.org,2002:str"] = yTagString
result.tags["tag:yaml.org,2002:null"] = yTagNull
result.tags["tag:yaml.org,2002:bool"] = yTagBoolean
result.tags["tag:yaml.org,2002:int"] = yTagInteger
result.tags["tag:yaml.org,2002:float"] = yTagFloat
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:int"] = yTagNimInt
result.tags["!nim:int64"] = yTagNimInt64
result.tags["!nim:float"] = yTagNimFloat
result.tags["!nim:float64"] = yTagNimFloat64
var
serializationTagLibrary* = initSerializationTagLibrary() ## \
@ -26,11 +35,12 @@ var
## as those are not suited for Nim's static type system.
##
## Should not be modified manually. Will be extended by
## `make_serializable <#make_serializable,stmt,stmt`_.
## `serializable <#serializable,stmt,stmt>`_.
static:
iterator objectFields(n: NimNode): tuple[name: NimNode, t: NimNode] =
iterator objectFields(n: NimNode): tuple[name: NimNode, t: NimNode]
{.raises: [].} =
assert n.kind in [nnkRecList, nnkTupleTy]
for identDefs in n.children:
let numFields = identDefs.len - 2
@ -42,13 +52,13 @@ static:
template presentTag(t: typedesc, tagStyle: TagStyle): TagId =
if tagStyle == tsNone: yTagQuestionMark else: yamlTag(t)
proc lazyLoadTag*(uri: string): TagId {.inline.} =
proc lazyLoadTag*(uri: string): TagId {.inline, raises: [].} =
try:
result = serializationTagLibrary.tags[uri]
except KeyError:
result = serializationTagLibrary.registerUri(uri)
macro make_serializable*(types: stmt): stmt =
macro serializable*(types: stmt): stmt =
assert types.kind == nnkTypeSection
result = newStmtList(types)
for typedef in types.children:
@ -116,32 +126,36 @@ macro make_serializable*(types: stmt): stmt =
newIdentDefs(newIdentNode("s"), newIdentNode("YamlStream")),
newIdentDefs(newIdentNode("result"),
newNimNode(nnkVarTy).add(tIdent))])
constructProc[4] = newNimNode(nnkPragma).add(
newNimNode(nnkExprColonExpr).add(newIdentNode("raises"),
newNimNode(nnkBracket).add(
newIdentNode("YamlConstructionError"),
newIdentNode("YamlConstructionStreamError"))))
impl = quote do:
var event = s()
if finished(s) or event.kind != yamlStartMap:
raise newException(ValueError, "Construction error!")
raise newException(YamlConstructionError, "Expected map start")
if event.mapTag != yTagQuestionMark and
event.mapTag != yamlTag(type(`tIdent`)):
raise newException(ValueError, "Wrong tag for " & `tName`)
raise newException(YamlConstructionError,
"Wrong tag for " & `tName`)
event = s()
if finished(s):
raise newException(ValueError, "Construction error!")
assert(not finished(s))
while event.kind != yamlEndMap:
assert event.kind == yamlScalar
assert event.scalarTag in [yTagQuestionMark, yTagString]
case hash(event.scalarContent)
case event.scalarContent
else:
raise newException(ValueError, "Unknown key for " &
`tName` & ": " & event.scalarContent)
raise newException(YamlConstructionError,
"Unknown key for " & `tName` & ": " &
event.scalarContent)
event = s()
if finished(s):
raise newException(ValueError, "Construction error!")
assert(not finished(s))
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(
newStrLitNode($field.name.ident)).add(newStmtList(
newCall("construct", [newIdentNode("s"), newDotExpr(
newIdentNode("result"), field.name)])
))
@ -158,6 +172,9 @@ macro make_serializable*(types: stmt): stmt =
newIdentDefs(newIdentNode("tagStyle"),
newIdentNode("TagStyle"),
newIdentNode("tsNone"))])
serializeProc[4] = newNimNode(nnkPragma).add(
newNimNode(nnkExprColonExpr).add(newIdentNode("raises"),
newNimNode(nnkBracket)))
var iterBody = newStmtList(
newLetStmt(newIdentNode("childTagStyle"), newNimNode(nnkIfExpr).add(
newNimNode(nnkElifExpr).add(
@ -213,91 +230,114 @@ macro make_serializable*(types: stmt): stmt =
serializeProc[6] = impl
result.add(serializeProc)
proc prepend*(event: YamlStreamEvent, s: YamlStream): YamlStream =
proc prepend(event: YamlStreamEvent, s: YamlStream): YamlStream {.raises: [].} =
result = iterator(): YamlStreamEvent =
yield event
for e in s():
yield e
proc yamlTag*(T: typedesc[string]): TagId {.inline.} = yTagString
proc safeTagUri*(id: TagId): string {.raises: [].} =
try:
let uri = serializationTagLibrary.uri(id)
if uri.len > 0 and uri[0] == '!':
return uri[1..uri.len - 1]
else:
return uri
except KeyError:
# cannot happen (theoretically, you known)
assert(false)
proc safeTagUri*(id: TagId): string =
let uri = serializationTagLibrary.uri(id)
if uri.len > 0 and uri[0] == '!':
return uri[1..uri.len - 1]
else:
return uri
proc construct*(s: YamlStream, result: var string) =
let item = s()
template constructScalarItem(item: YamlStreamEvent, name: string, t: TagId,
content: stmt) =
try:
item = s()
except Exception:
var e = newException(YamlConstructionStreamError, "")
e.parent = getCurrentException()
raise e
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
raise newException(YamlConstructionError, "Expected scalar")
if item.scalarTag notin [yTagQuestionMark, yTagExclamationMark, t]:
raise newException(YamlConstructionError, "Wrong tag for " & name)
try:
content
except YamlConstructionError:
raise
except Exception:
var e = newException(YamlConstructionError,
"Cannot construct to " & name & ": " & item.scalarContent)
e.parent = getCurrentException()
raise e
template safeNextEvent(e: YamlStreamEvent, s: YamlStream) =
try:
e = s()
except Exception:
var ex = newException(YamlConstructionStreamError, "")
ex.parent = getCurrentException()
raise ex
proc yamlTag*(T: typedesc[string]): TagId {.inline, raises: [].} = yTagString
proc construct*(s: YamlStream, result: var string)
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
var item: YamlStreamEvent
constructScalarItem(item, "string", yTagString):
result = item.scalarContent
proc serialize*(value: string,
tagStyle: TagStyle = tsNone): YamlStream =
tagStyle: TagStyle = tsNone): YamlStream {.raises: [].} =
result = iterator(): YamlStreamEvent =
yield scalarEvent(value, presentTag(string, tagStyle), yAnchorNone)
proc yamlTag*(T: typedesc[int]): TagId {.inline.} = yTagInteger
proc yamlTag*(T: typedesc[int]): TagId {.inline.} = yTagNimInt
proc construct*(s: YamlStream, result: var int) =
let item = s()
if finished(s) or item.kind != yamlScalar:
raise newException(ValueError, "Construction error!")
if item.scalarTag != yTagInteger and not (
item.scalarTag == yTagQuestionMark and
guessType(item.scalarContent) == yTypeInteger):
raise newException(ValueError, "Wrong scalar type for int.")
result = parseInt(item.scalarContent)
proc construct*(s: YamlStream, result: var int)
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
var item: YamlStreamEvent
constructScalarItem(item, "int", yTagNimInt):
result = parseInt(item.scalarContent)
proc serialize*(value: int, tagStyle: TagStyle = tsNone): YamlStream =
result = iterator(): YamlStreamEvent =
result = iterator(): YamlStreamEvent {.raises: [].} =
yield scalarEvent($value, presentTag(int, tagStyle), yAnchorNone)
proc yamlTag*(T: typedesc[int64]): TagId {.inline.} = yTagInteger
proc yamlTag*(T: typedesc[int64]): TagId {.inline, raises: [].} = yTagNimInt64
proc contruct*(s: YamlStream, result: var int64) =
let item = s()
if finished(s) or item.kind != yamlScalar:
raise newException(ValueError, "Construction error!")
if item.scalarTag != yTagInteger and not (
item.scalarTag == yTagQuestionMark and
guessType(item.scalarContent) == yTypeInteger):
raise newException(ValueError, "Wrong scalar type for int64.")
result = parseBiggestInt(item.scalarContent)
proc contruct*(s: YamlStream, result: var int64)
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
var item: YamlStreamEvent
constructScalarItem(item, "int64", yTagNimInt64):
result = parseBiggestInt(item.scalarContent)
proc serialize*(value: int64, tagStyle: TagStyle = tsNone): YamlStream =
proc serialize*(value: int64, tagStyle: TagStyle = tsNone): YamlStream
{.raises: [].}=
result = iterator(): YamlStreamEvent =
yield scalarEvent($value, presentTag(int64, tagStyle), yAnchorNone)
proc yamlTag*(T: typedesc[float]): TagId {.inline.} = yTagFloat
proc yamlTag*(T: typedesc[float]): TagId {.inline, raises: [].} = yTagNimFloat
proc construct*(s: YamlStream, result: var float) =
let item = s()
if finished(s) or item.kind != yamlScalar:
raise newException(ValueError, "Construction error!")
let hint = guessType(item.scalarContent)
if item.scalarTag != yTagFloat and not (
item.scalarTag == yTagQuestionMark and
hint in [yTypeFloat, yTypeFloatInf, yTypeFloatNaN]):
raise newException(ValueError, "Wrong scalar type for float.")
case hint
of yTypeFloat:
result = parseFloat(item.scalarContent)
of yTypeFloatInf:
if item.scalarContent[0] == '-':
result = NegInf
proc construct*(s: YamlStream, result: var float)
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
var item: YamlStreamEvent
constructScalarItem(item, "float", yTagNimFloat):
let hint = guessType(item.scalarContent)
case hint
of yTypeFloat:
result = parseFloat(item.scalarContent)
of yTypeFloatInf:
if item.scalarContent[0] == '-':
result = NegInf
else:
result = Inf
of yTypeFloatNaN:
result = NaN
else:
result = Inf
of yTypeFloatNaN:
result = NaN
else:
raise newException(ValueError, "Wrong scalar type for float.")
raise newException(YamlConstructionError,
"Cannot construct to float: " & item.scalarContent)
proc serialize*(value: float, tagStyle: TagStyle = tsNone): YamlStream =
proc serialize*(value: float, tagStyle: TagStyle = tsNone): YamlStream
{.raises: [].}=
result = iterator(): YamlStreamEvent =
var
asString: string
@ -312,57 +352,57 @@ proc serialize*(value: float, tagStyle: TagStyle = tsNone): YamlStream =
asString = $value
yield scalarEvent(asString, presentTag(float, tagStyle), yAnchorNone)
proc yamlTag*(T: typedesc[bool]): TagId {.inline.} = yTagBoolean
proc yamlTag*(T: typedesc[bool]): TagId {.inline, raises: [].} = yTagBoolean
proc construct*(s: YamlStream, result: var bool) =
let item = s()
if finished(s) or item.kind != yamlScalar:
raise newException(ValueError, "Construction error!")
let hint = guessType(item.scalarContent)
case item.scalarTag
of yTagQuestionMark, yTagBoolean:
case hint
proc construct*(s: YamlStream, result: var bool)
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
var item: YamlStreamEvent
constructScalarItem(item, "bool", yTagBoolean):
case guessType(item.scalarContent)
of yTypeBoolTrue:
result = true
of yTypeBoolFalse:
result = false
else:
raise newException(ValueError,
"Not a boolean: " & item.scalarContent)
else:
raise newException(ValueError, "Wrong scalar type for bool")
raise newException(YamlConstructionError,
"Cannot construct to bool: " & item.scalarContent)
proc serialize*(value: bool, tagStyle: TagStyle = tsNone): YamlStream =
proc serialize*(value: bool, tagStyle: TagStyle = tsNone): YamlStream
{.raises: [].}=
result = iterator(): YamlStreamEvent =
yield scalarEvent(if value: "y" else: "n", presentTag(bool, tagStyle),
yAnchorNone)
proc yamlTag*[I](T: typedesc[seq[I]]): TagId {.inline.} =
proc yamlTag*[I](T: typedesc[seq[I]]): TagId {.inline, raises: [].} =
let uri = "!nim:seq(" & safeTagUri(yamlTag(I)) & ")"
result = lazyLoadTag(uri)
proc construct*[T](s: YamlStream, result: var seq[T]) =
var event = s()
proc construct*[T](s: YamlStream, result: var seq[T])
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
var event: YamlStreamEvent
safeNextEvent(event, s)
if finished(s) or event.kind != yamlStartSequence:
raise newException(ValueError, "Construction error!1")
if event.seqTag != yTagQuestionMark and
event.seqTag != yamlTag(seq[T]):
raise newException(ValueError, "Wrong sequence type for seq[T]")
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]()
event = s()
if finished(s):
raise newException(ValueError, "Construction error!2")
safeNextEvent(event, s)
assert(not finished(s))
while event.kind != yamlEndSequence:
var
item: T
events = prepend(event, s)
construct(events, item)
try:
construct(events, item)
except:
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
assert(false)
result.add(item)
event = s()
if finished(s):
raise newException(ValueError, "Construction error!3")
safeNextEvent(event, s)
assert(not finished(s))
proc serialize*[T](value: seq[T], tagStyle: TagStyle = tsNone): YamlStream =
proc serialize*[T](value: seq[T], tagStyle: TagStyle = tsNone): YamlStream
{.raises: [].} =
result = iterator(): YamlStreamEvent =
let childTagStyle = if tagStyle == tsRootOnly: tsNone else: tagStyle
yield YamlStreamEvent(kind: yamlStartSequence,
@ -374,41 +414,49 @@ proc serialize*[T](value: seq[T], tagStyle: TagStyle = tsNone): YamlStream =
yield event
yield YamlStreamEvent(kind: yamlEndSequence)
proc yamlTag*[K, V](T: typedesc[Table[K, V]]): TagId {.inline.} =
let
keyUri = serializationTagLibrary.uri(yamlTag(K))
valueUri = serializationTagLibrary.uri(yamlTag(V))
keyIdent = if keyUri[0] == '!': keyUri[1..keyUri.len - 1] else: keyUri
valueIdent = if valueUri[0] == '!':
valueUri[1..valueUri.len - 1] else: valueUri
uri = "!nim:Table(" & keyUri & "," & valueUri & ")"
result = lazyLoadTag(uri)
proc yamlTag*[K, V](T: typedesc[Table[K, V]]): TagId {.inline, raises: [].} =
try:
let
keyUri = serializationTagLibrary.uri(yamlTag(K))
valueUri = serializationTagLibrary.uri(yamlTag(V))
keyIdent = if keyUri[0] == '!': keyUri[1..keyUri.len - 1] else:
keyUri
valueIdent = if valueUri[0] == '!':
valueUri[1..valueUri.len - 1] else: valueUri
uri = "!nim:Table(" & keyUri & "," & valueUri & ")"
result = lazyLoadTag(uri)
except KeyError:
# cannot happen (theoretically, you known)
assert(false)
proc construct*[K, V](s: YamlStream, result: var Table[K, V]) =
var event = s()
proc construct*[K, V](s: YamlStream, result: var Table[K, V])
{.raises: [YamlConstructionError, YamlConstructionStreamError].} =
var event: YamlStreamEvent
safeNextEvent(event, s)
if finished(s) or event.kind != yamlStartMap:
raise newException(ValueError, "Construction error!")
if event.mapTag != yTagQuestionMark and
event.mapTag != yamlTag(Table[K, V]):
raise newException(ValueError, "Wrong map type for Table[K, V]")
raise newException(YamlConstructionError, "Expected map start")
if event.mapTag notin [yTagQuestionMark, yamlTag(Table[K, V])]:
raise newException(YamlConstructionError, "Wrong tag for Table[K, V]")
result = initTable[K, V]()
event = s()
if finished(s):
raise newException(ValueError, "Construction error!")
safeNextEvent(event, s)
assert(not finished(s))
while event.kind != yamlEndMap:
var
key: K
value: V
events = prepend(event, s)
construct(events, key)
construct(s, value)
try:
construct(events, key)
construct(s, value)
except Exception:
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
assert(false)
result[key] = value
event = s()
if finished(s):
raise newException(ValueError, "Construction error!")
safeNextEvent(event, s)
assert(not finished(s))
proc serialize*[K, V](value: Table[K, V],
tagStyle: TagStyle = tsNone): YamlStream =
tagStyle: TagStyle = tsNone): YamlStream {.raises: [].} =
result = iterator(): YamlStreamEvent =
let childTagStyle = if tagStyle == tsRootOnly: tsNone else: tagStyle
yield YamlStreamEvent(kind: yamlStartMap,
@ -423,21 +471,50 @@ proc serialize*[K, V](value: Table[K, V],
yield event
yield YamlStreamEvent(kind: yamlEndMap)
proc load*[K](input: Stream, target: var K) =
var
tagLib = serializationTagLibrary
events = parse(tagLib, input)
assert events().kind == yamlStartDocument
construct(events, target)
assert events().kind == yamlEndDocument
proc load*[K](input: Stream, target: var K)
{.raises: [YamlConstructionError, IOError, YamlParserError].} =
try:
var
parser = newYamlParser(serializationTagLibrary)
events = parser.parse(input)
assert events().kind == yamlStartDocument
construct(events, target)
assert events().kind == yamlEndDocument
except YamlConstructionError, IOError, YamlParserError:
raise
except YamlConstructionStreamError:
let e = cast[ref YamlConstructionError](getCurrentException())
if e.parent of IOError:
raise cast[ref IOError](e.parent)
elif e.parent of YamlParserError:
raise cast[ref YamlParserError](e.parent)
else:
assert(false)
except Exception:
# compiler bug: https://github.com/nim-lang/Nim/issues/3772
assert(false)
proc dump*[K](value: K, target: Stream, style: PresentationStyle = psDefault,
tagStyle: TagStyle = tsRootOnly, indentationStep: int = 2) =
tagStyle: TagStyle = tsRootOnly, indentationStep: int = 2)
{.raises: [YamlConstructionError, YamlConstructionStreamError,
YamlPresenterJsonError, YamlPresenterOutputError].} =
var serialized = serialize(value,
if style == psCanonical: tsAll else: tagStyle)
var events = iterator(): YamlStreamEvent =
yield YamlStreamEvent(kind: yamlStartDocument)
for event in serialized():
while true:
var event: YamlStreamEvent
try:
event = serialized()
if finished(serialized): break
except Exception:
# serializing object does not raise any errors, so we can
# ignore this
assert(false)
yield event
yield YamlStreamEvent(kind: yamlEndDocument)
present(events, target, serializationTagLibrary, style, indentationStep)
try:
present(events, target, serializationTagLibrary, style, indentationStep)
except YamlPresenterStreamError:
# serializing object does not raise any errors, so we can ignore this
assert(false)