Merge pull request #27 from GaveUp/devel

Add octal/hex support. Add multi doc support.
This commit is contained in:
flyx 2016-09-20 18:11:09 +02:00 committed by GitHub
commit 11a1de43be
2 changed files with 118 additions and 7 deletions

View File

@ -62,12 +62,34 @@ proc representObject*(value: string, ts: TagStyle,
## represents a string as YAML scalar
c.put(scalarEvent(value, tag, yAnchorNone))
proc parseHex[T: int8|int16|int32|int64|uint8|uint16|uint32|uint64](s: string): T =
result = 0
for i in 2..<s.len:
case s[i]
of '_': discard
of '0'..'9': result = result shl 4 or T(ord(s[i]) - ord('0'))
of 'a'..'f': result = result shl 4 or T(ord(s[i]) - ord('a') + 10)
of 'A'..'F': result = result shl 4 or T(ord(s[i]) - ord('A') + 10)
else: raise newException(ValueError, "Invalid character in hex: " & escape("" & s[i]))
proc parseOctal[T: int8|int16|int32|int64|uint8|uint16|uint32|uint64](s: string): T =
for i in 2..<s.len:
case s[i]
of '_': discard
of '0'..'7': result = result shl 3 + T((ord(s[i]) - ord('0')))
else: raise newException(ValueError, "Invalid character in hex: " & escape("" & s[i]))
proc constructObject*[T: int8|int16|int32|int64](
s: var YamlStream, c: ConstructionContext, result: var T)
{.raises: [YamlConstructionError, YamlStreamError].} =
## constructs an integer value from a YAML scalar
constructScalarItem(s, item, T):
result = T(parseBiggestInt(item.scalarContent))
if item.scalarContent[0] == '0' and item.scalarContent[1] in {'x', 'X' }:
result = parseHex[T](item.scalarContent)
elif item.scalarContent[0] == '0' and item.scalarContent[1] in {'o', 'O'}:
result = parseOctal[T](item.scalarContent)
else:
result = T(parseBiggestInt(item.scalarContent))
proc constructObject*(s: var YamlStream, c: ConstructionContext,
result: var int)
@ -99,10 +121,15 @@ proc representObject*(value: int, tagStyle: TagStyle,
{.push overflowChecks: on.}
proc parseBiggestUInt(s: string): uint64 =
result = 0
for c in s:
if c in {'0'..'9'}: result *= 10.uint64 + (uint64(c) - uint64('0'))
elif c == '_': discard
else: raise newException(ValueError, "Invalid char in uint: " & c)
if s[0] == '0' and s[1] in {'x', 'X'}:
result = parseHex[uint64](s)
elif s[0] == '0' and s[1] in {'o', 'O'}:
result = parseOctal[uint64](s)
else:
for c in s:
if c in {'0'..'9'}: result = result * 10.uint64 + (uint64(c) - uint64('0'))
elif c == '_': discard
else: raise newException(ValueError, "Invalid char in uint: " & c)
{.pop.}
proc constructObject*[T: uint8|uint16|uint32|uint64](
@ -110,7 +137,7 @@ proc constructObject*[T: uint8|uint16|uint32|uint64](
{.raises: [YamlConstructionError, YamlStreamError].} =
## construct an unsigned integer value from a YAML scalar
constructScalarItem(s, item, T):
result = T(parseBiggestUInt(item.scalarContent))
result = T(yaml.parseBiggestUInt(item.scalarContent))
proc constructObject*(s: var YamlStream, c: ConstructionContext,
result: var uint)
@ -773,6 +800,27 @@ proc load*[K](input: Stream | string, target: var K) =
elif e.parent of YamlParserError: raise (ref YamlParserError)(e.parent)
else: internalError("Unexpected exception: " & e.parent.repr)
proc loadMultiDoc*[K](input: Stream | string, target: var seq[K]) =
if target.isNil:
target = newSeq[K]()
var
parser = newYamlParser(serializationTagLibrary)
events = parser.parse(input)
try:
while not events.finished():
var item: K
construct(events, item)
target.add(item)
except YamlConstructionError:
var e = (ref YamlConstructionError)(getCurrentException())
discard events.getLastTokenContext(e.line, e.column, e.lineContent)
raise e
except YamlStreamError:
let e = (ref YamlStreamError)(getCurrentException())
if e.parent of IOError: raise (ref IOError)(e.parent)
elif e.parent of YamlParserError: raise (ref YamlParserError)(e.parent)
else: internalError("Unexpected exception: " & e.parent.repr)
proc setAnchor(a: var AnchorId, q: var Table[pointer, AnchorId])
{.inline.} =
if a != yAnchorNone: a = q.getOrDefault(cast[pointer](a))

View File

@ -101,6 +101,54 @@ suite "Serialization":
except: gotException = true
assert gotException, "Expected exception, got none."
test "Load Hex byte (0xFF)":
let input = newStringStream("0xFF")
var result: byte
load(input, result)
assert(result == 255)
test "Load Hex byte (0xC)":
let input = newStringStream("0xC")
var result: byte
load(input, result)
assert(result == 12)
test "Load Octal byte (0o14)":
let input = newStringStream("0o14")
var result: byte
load(input, result)
assert(result == 12)
test "Load byte (14)":
let input = newStringStream("14")
var result: byte
load(input, result)
assert(result == 14)
test "Load Hex int (0xFF)":
let input = newStringStream("0xFF")
var result: int
load(input, result)
assert(result == 255)
test "Load Hex int (0xC)":
let input = newStringStream("0xC")
var result: int
load(input, result)
assert(result == 12)
test "Load Octal int (0o14)":
let input = newStringStream("0o14")
var result: int
load(input, result)
assert(result == 12)
test "Load int (14)":
let input = newStringStream("14")
var result: int
load(input, result)
assert(result == 14)
test "Load nil string":
let input = newStringStream("!nim:nil:string \"\"")
var result: string
@ -253,6 +301,21 @@ suite "Serialization":
let input = (str: "value", i: 42.int32, b: true)
var output = dump(input, tsNone)
assertStringEqual "%YAML 1.2\n--- \nstr: value\ni: 42\nb: y", output
test "Load Multiple Documents":
let input = newStringStream("1\n---\n2")
var result: seq[int]
loadMultiDoc(input, result)
assert(result.len == 2)
assert result[0] == 1
assert result[1] == 2
test "Load Multiple Documents (Single Doc)":
let input = newStringStream("1")
var result: seq[int]
loadMultiDoc(input, result)
assert(result.len == 1)
assert result[0] == 1
test "Load custom object":
let input = newStringStream("firstnamechar: P\nsurname: Pan\nage: 12")
@ -268,7 +331,7 @@ suite "Serialization":
assertStringEqual(
"%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12", output)
test "Serialization: Load sequence with explicit tags":
test "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]