mirror of https://github.com/status-im/NimYAML.git
Improved and fixed issues with error reporting
This commit is contained in:
parent
a8d68d1696
commit
2ad41d349e
|
@ -44,7 +44,8 @@ type
|
||||||
folded: bool
|
folded: bool
|
||||||
chomp: ChompType
|
chomp: ChompType
|
||||||
c: char
|
c: char
|
||||||
tokenLineGetter: proc(lex: YamlLexer, marker: bool): string {.raises: [].}
|
tokenLineGetter: proc(lex: YamlLexer, pos: tuple[line, column: int],
|
||||||
|
marker: bool): string {.raises: [].}
|
||||||
searchColonImpl: proc(lex: YamlLexer): bool
|
searchColonImpl: proc(lex: YamlLexer): bool
|
||||||
|
|
||||||
YamlLexer* = ref YamlLexerObj
|
YamlLexer* = ref YamlLexerObj
|
||||||
|
@ -190,26 +191,26 @@ proc afterMark(lex: YamlLexer, t: typedesc[StringSource], m: int):
|
||||||
int {.inline.} =
|
int {.inline.} =
|
||||||
lex.sSource.pos - m
|
lex.sSource.pos - m
|
||||||
|
|
||||||
proc lineWithMarker(lex: YamlLexer, t: typedesc[BaseLexer], marker: bool):
|
proc lineWithMarker(lex: YamlLexer, pos: tuple[line, column: int],
|
||||||
string =
|
t: typedesc[BaseLexer], marker: bool): string =
|
||||||
if lex.curStartPos.line == lex.blSource.lineNumber:
|
if pos.line == lex.blSource.lineNumber:
|
||||||
result = lex.blSource.getCurrentLine(false)
|
result = lex.blSource.getCurrentLine(false)
|
||||||
if marker: result.add(spaces(lex.curStartPos.column - 1) & "^\n")
|
if marker: result.add(spaces(pos.column - 1) & "^\n")
|
||||||
else: result = ""
|
else: result = ""
|
||||||
|
|
||||||
proc lineWithMarker(lex: YamlLexer, t: typedesc[StringSource], marker: bool):
|
proc lineWithMarker(lex: YamlLexer, pos: tuple[line, column: int],
|
||||||
string =
|
t: typedesc[StringSource], marker: bool): string =
|
||||||
var
|
var
|
||||||
lineStartIndex = lex.sSource.pos
|
lineStartIndex = lex.sSource.pos
|
||||||
lineEndIndex: int
|
lineEndIndex: int
|
||||||
curLine = lex.sSource.line
|
curLine = lex.sSource.line
|
||||||
if lex.curStartPos.line == curLine:
|
if pos.line == curLine:
|
||||||
lineEndIndex = lex.sSource.pos
|
lineEndIndex = lex.sSource.pos
|
||||||
while lex.sSource.src[lineEndIndex] notin lineEnd: inc(lineEndIndex)
|
while lex.sSource.src[lineEndIndex] notin lineEnd: inc(lineEndIndex)
|
||||||
while true:
|
while true:
|
||||||
while lineStartIndex >= 0 and lex.sSource.src[lineStartIndex] notin lineEnd:
|
while lineStartIndex >= 0 and lex.sSource.src[lineStartIndex] notin lineEnd:
|
||||||
dec(lineStartIndex)
|
dec(lineStartIndex)
|
||||||
if curLine == lex.curStartPos.line:
|
if curLine == pos.line:
|
||||||
inc(lineStartIndex)
|
inc(lineStartIndex)
|
||||||
break
|
break
|
||||||
let wasLF = lex.sSource.src[lineStartIndex] == '\l'
|
let wasLF = lex.sSource.src[lineStartIndex] == '\l'
|
||||||
|
@ -220,7 +221,7 @@ proc lineWithMarker(lex: YamlLexer, t: typedesc[StringSource], marker: bool):
|
||||||
dec(lineEndIndex)
|
dec(lineEndIndex)
|
||||||
dec(curLine)
|
dec(curLine)
|
||||||
result = lex.sSource.src.substr(lineStartIndex, lineEndIndex - 1) & "\n"
|
result = lex.sSource.src.substr(lineStartIndex, lineEndIndex - 1) & "\n"
|
||||||
if marker: result.add(spaces(lex.curStartPos.column - 1) & "^\n")
|
if marker: result.add(spaces(pos.column - 1) & "^\n")
|
||||||
|
|
||||||
# lexer states
|
# lexer states
|
||||||
|
|
||||||
|
@ -246,7 +247,7 @@ proc docEndAfterBlockScalar[T](lex: YamlLexer): bool
|
||||||
proc tagHandle[T](lex: YamlLexer): bool
|
proc tagHandle[T](lex: YamlLexer): bool
|
||||||
proc anchor[T](lex: YamlLexer): bool
|
proc anchor[T](lex: YamlLexer): bool
|
||||||
proc alias[T](lex: YamlLexer): bool
|
proc alias[T](lex: YamlLexer): bool
|
||||||
proc streamEnd(lex: YamlLexer): bool
|
proc streamEnd[T](lex: YamlLexer): bool
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
@ -371,8 +372,7 @@ proc expectLineEnd[T](lex: YamlLexer): bool =
|
||||||
lex.advance(T)
|
lex.advance(T)
|
||||||
while lex.c notin lineEnd: lex.advance(T)
|
while lex.c notin lineEnd: lex.advance(T)
|
||||||
of EndOfFile:
|
of EndOfFile:
|
||||||
startToken[T](lex)
|
lex.nextState = streamEnd[T]
|
||||||
lex.nextState = streamEnd
|
|
||||||
break
|
break
|
||||||
of '\l':
|
of '\l':
|
||||||
lex.lexLF(T)
|
lex.lexLF(T)
|
||||||
|
@ -857,7 +857,7 @@ proc blockScalarLineStart[T](lex: YamlLexer, recentWasMoreIndented: var bool):
|
||||||
lex.lexCR(T)
|
lex.lexCR(T)
|
||||||
lex.indentation = 0
|
lex.indentation = 0
|
||||||
of EndOfFile:
|
of EndOfFile:
|
||||||
lex.nextState = streamEnd
|
lex.nextState = streamEnd[T]
|
||||||
return false
|
return false
|
||||||
of ' ', '\t':
|
of ' ', '\t':
|
||||||
recentWasMoreIndented = true
|
recentWasMoreIndented = true
|
||||||
|
@ -886,7 +886,7 @@ proc blockScalar[T](lex: YamlLexer): bool =
|
||||||
lex.lexCR(T)
|
lex.lexCR(T)
|
||||||
lex.newlines.inc()
|
lex.newlines.inc()
|
||||||
of EndOfFile:
|
of EndOfFile:
|
||||||
lex.nextState = streamEnd
|
lex.nextState = streamEnd[T]
|
||||||
break outer
|
break outer
|
||||||
else:
|
else:
|
||||||
if lex.blockScalarIndent <= lex.indentation:
|
if lex.blockScalarIndent <= lex.indentation:
|
||||||
|
@ -1032,13 +1032,15 @@ proc alias[T](lex: YamlLexer): bool =
|
||||||
lex.cur = ltAlias
|
lex.cur = ltAlias
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc streamEnd(lex: YamlLexer): bool =
|
proc streamEnd[T](lex: YamlLexer): bool =
|
||||||
debug("lex: streamEnd")
|
debug("lex: streamEnd")
|
||||||
|
startToken[T](lex)
|
||||||
lex.cur = ltStreamEnd
|
lex.cur = ltStreamEnd
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc tokenLine[T](lex: YamlLexer, marker: bool): string =
|
proc tokenLine[T](lex: YamlLexer, pos: tuple[line, column: int], marker: bool):
|
||||||
result = lex.lineWithMarker(T, marker)
|
string =
|
||||||
|
result = lex.lineWithMarker(pos, T, marker)
|
||||||
|
|
||||||
proc searchColon[T](lex: YamlLexer): bool =
|
proc searchColon[T](lex: YamlLexer): bool =
|
||||||
var flowDepth = if lex.cur in [ltBraceOpen, ltBracketOpen]: 1 else: 0
|
var flowDepth = if lex.cur in [ltBraceOpen, ltBracketOpen]: 1 else: 0
|
||||||
|
@ -1180,7 +1182,11 @@ proc endBlockScalar*(lex: YamlLexer) =
|
||||||
lex.folded = true
|
lex.folded = true
|
||||||
|
|
||||||
proc getTokenLine*(lex: YamlLexer, marker: bool = true): string =
|
proc getTokenLine*(lex: YamlLexer, marker: bool = true): string =
|
||||||
result = lex.tokenLineGetter(lex, marker)
|
result = lex.tokenLineGetter(lex, lex.curStartPos, marker)
|
||||||
|
|
||||||
|
proc getTokenLine*(lex: YamlLexer, pos: tuple[line, column: int],
|
||||||
|
marker: bool = true): string =
|
||||||
|
result = lex.tokenLineGetter(lex, pos, marker)
|
||||||
|
|
||||||
proc isImplicitKeyStart*(lex: YamlLexer): bool =
|
proc isImplicitKeyStart*(lex: YamlLexer): bool =
|
||||||
result = lex.searchColonImpl(lex)
|
result = lex.searchColonImpl(lex)
|
||||||
|
|
|
@ -69,6 +69,16 @@ template assertStringEqual(expected, actual: string) =
|
||||||
echo "expected:\n", expected, "\nactual:\n", actual
|
echo "expected:\n", expected, "\nactual:\n", actual
|
||||||
assert(false)
|
assert(false)
|
||||||
|
|
||||||
|
template expectConstructionError(l, c: int, body: typed) =
|
||||||
|
try:
|
||||||
|
body
|
||||||
|
echo "Expected YamlConstructionError, but none was raised!"
|
||||||
|
fail()
|
||||||
|
except YamlConstructionError:
|
||||||
|
let e = (ref YamlConstructionError)(getCurrentException())
|
||||||
|
doAssert l == e.line, "Expected error line " & $l & ", was " & $e.line
|
||||||
|
doAssert c == e.column, "Expected error column " & $c & ", was " & $e.column
|
||||||
|
|
||||||
proc newNode(v: string): ref Node =
|
proc newNode(v: string): ref Node =
|
||||||
new(result)
|
new(result)
|
||||||
result.value = v
|
result.value = v
|
||||||
|
@ -305,19 +315,19 @@ suite "Serialization":
|
||||||
test "Load Tuple - unknown field":
|
test "Load Tuple - unknown field":
|
||||||
let input = "str: value\nfoo: bar\ni: 42\nb: true"
|
let input = "str: value\nfoo: bar\ni: 42\nb: true"
|
||||||
var result: MyTuple
|
var result: MyTuple
|
||||||
expect(YamlConstructionError):
|
expectConstructionError(2, 1):
|
||||||
load(input, result)
|
load(input, result)
|
||||||
|
|
||||||
test "Load Tuple - missing field":
|
test "Load Tuple - missing field":
|
||||||
let input = "str: value\nb: true"
|
let input = "str: value\nb: true"
|
||||||
var result: MyTuple
|
var result: MyTuple
|
||||||
expect(YamlConstructionError):
|
expectConstructionError(2, 8):
|
||||||
load(input, result)
|
load(input, result)
|
||||||
|
|
||||||
test "Load Tuple - duplicate field":
|
test "Load Tuple - duplicate field":
|
||||||
let input = "str: value\ni: 42\nb: true\nb: true"
|
let input = "str: value\ni: 42\nb: true\nb: true"
|
||||||
var result: MyTuple
|
var result: MyTuple
|
||||||
expect(YamlConstructionError):
|
expectConstructionError(4, 1):
|
||||||
load(input, result)
|
load(input, result)
|
||||||
|
|
||||||
test "Load Multiple Documents":
|
test "Load Multiple Documents":
|
||||||
|
@ -350,21 +360,21 @@ suite "Serialization":
|
||||||
"%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12", output)
|
"%YAML 1.2\n--- \nfirstnamechar: P\nsurname: Pan\nage: 12", output)
|
||||||
|
|
||||||
test "Load custom object - unknown field":
|
test "Load custom object - unknown field":
|
||||||
let input = "firstnamechar: P\nsurname: Pan\nage: 12\noccupation: free"
|
let input = " firstnamechar: P\n surname: Pan\n age: 12\n occupation: free"
|
||||||
var result: Person
|
var result: Person
|
||||||
expect(YamlConstructionError):
|
expectConstructionError(4, 3):
|
||||||
load(input, result)
|
load(input, result)
|
||||||
|
|
||||||
test "Load custom object - missing field":
|
test "Load custom object - missing field":
|
||||||
let input = "surname: Pan\nage: 12"
|
let input = "surname: Pan\nage: 12\n "
|
||||||
var result: Person
|
var result: Person
|
||||||
expect(YamlConstructionError):
|
expectConstructionError(3, 3):
|
||||||
load(input, result)
|
load(input, result)
|
||||||
|
|
||||||
test "Load custom object - duplicate field":
|
test "Load custom object - duplicate field":
|
||||||
let input = "firstnamechar: P\nsurname: Pan\nage: 12\nsurname: Pan"
|
let input = "firstnamechar: P\nsurname: Pan\nage: 12\nsurname: Pan"
|
||||||
var result: Person
|
var result: Person
|
||||||
expect(YamlConstructionError):
|
expectConstructionError(4, 1):
|
||||||
load(input, result)
|
load(input, result)
|
||||||
|
|
||||||
test "Load sequence with explicit tags":
|
test "Load sequence with explicit tags":
|
||||||
|
@ -433,9 +443,9 @@ suite "Serialization":
|
||||||
barkometer: 13""", output
|
barkometer: 13""", output
|
||||||
|
|
||||||
test "Load custom variant object - missing field":
|
test "Load custom variant object - missing field":
|
||||||
let input = "{name: Bastet, kind: akCat}"
|
let input = "[{name: Bastet}, {kind: akCat}]"
|
||||||
var result: Animal
|
var result: Animal
|
||||||
expect(YamlConstructionError):
|
expectConstructionError(1, 32):
|
||||||
load(input, result)
|
load(input, result)
|
||||||
|
|
||||||
test "Dump cyclic data structure":
|
test "Dump cyclic data structure":
|
||||||
|
|
|
@ -56,6 +56,7 @@ type
|
||||||
nextAnchorId: AnchorId
|
nextAnchorId: AnchorId
|
||||||
newlines: int
|
newlines: int
|
||||||
explicitFlowKey: bool
|
explicitFlowKey: bool
|
||||||
|
plainScalarStart: tuple[line, column: int]
|
||||||
|
|
||||||
LevelEndResult = enum
|
LevelEndResult = enum
|
||||||
lerNothing, lerOne, lerAdditionalMapEnd
|
lerNothing, lerOne, lerAdditionalMapEnd
|
||||||
|
@ -126,7 +127,6 @@ proc illegalToken(c: ParserContext, expected: string = ""):
|
||||||
if expected.len > 0: msg.add(" (expected " & expected & ")")
|
if expected.len > 0: msg.add(" (expected " & expected & ")")
|
||||||
msg.add(": " & $c.lex.cur)
|
msg.add(": " & $c.lex.cur)
|
||||||
result = c.generateError(msg)
|
result = c.generateError(msg)
|
||||||
echo result.line, ", ", result.column
|
|
||||||
|
|
||||||
proc callCallback(c: ParserContext, msg: string) {.raises: [YamlParserError].} =
|
proc callCallback(c: ParserContext, msg: string) {.raises: [YamlParserError].} =
|
||||||
try:
|
try:
|
||||||
|
@ -332,6 +332,14 @@ proc handleFlowPlainScalar(c: ParserContext) =
|
||||||
c.advance()
|
c.advance()
|
||||||
c.lex.newlines = 0
|
c.lex.newlines = 0
|
||||||
|
|
||||||
|
proc lastTokenContext(s: YamlStream, line, column: var int,
|
||||||
|
lineContent: var string): bool =
|
||||||
|
let c = ParserContext(s)
|
||||||
|
line = c.lex.curStartPos.line
|
||||||
|
column = c.lex.curStartPos.column
|
||||||
|
lineContent = c.lex.getTokenLine(true)
|
||||||
|
result = true
|
||||||
|
|
||||||
# --- macros for defining parser states ---
|
# --- macros for defining parser states ---
|
||||||
|
|
||||||
template capitalize(s: string): string =
|
template capitalize(s: string): string =
|
||||||
|
@ -409,7 +417,7 @@ macro parserState(name: untyped, impl: untyped): typed =
|
||||||
|
|
||||||
parserStates(initial, blockLineStart, blockObjectStart, blockAfterObject,
|
parserStates(initial, blockLineStart, blockObjectStart, blockAfterObject,
|
||||||
scalarEnd, plainScalarEnd, objectEnd, expectDocEnd, startDoc,
|
scalarEnd, plainScalarEnd, objectEnd, expectDocEnd, startDoc,
|
||||||
afterDocument, closeMoreIndentedLevels,
|
afterDocument, closeMoreIndentedLevels, afterPlainScalarYield,
|
||||||
emitEmptyScalar, tagHandle, anchor, alias, flow, leaveFlowMap,
|
emitEmptyScalar, tagHandle, anchor, alias, flow, leaveFlowMap,
|
||||||
leaveFlowSeq, flowAfterObject, leaveFlowSinglePairMap)
|
leaveFlowSeq, flowAfterObject, leaveFlowSinglePairMap)
|
||||||
|
|
||||||
|
@ -592,7 +600,7 @@ parserState blockObjectStart:
|
||||||
state = scalarEnd
|
state = scalarEnd
|
||||||
of ltScalarPart:
|
of ltScalarPart:
|
||||||
result = c.handleBlockItemStart(e)
|
result = c.handleBlockItemStart(e)
|
||||||
let cachedPos = c.lex.curStartPos
|
c.plainScalarStart = c.lex.curStartPos
|
||||||
while true:
|
while true:
|
||||||
c.advance()
|
c.advance()
|
||||||
case c.lex.cur
|
case c.lex.cur
|
||||||
|
@ -602,7 +610,6 @@ parserState blockObjectStart:
|
||||||
of ltScalarPart: discard
|
of ltScalarPart: discard
|
||||||
of ltEmptyLine: c.lex.newlines.inc()
|
of ltEmptyLine: c.lex.newlines.inc()
|
||||||
else: break
|
else: break
|
||||||
c.lex.curStartPos = cachedPos
|
|
||||||
c.lex.newlines = 0
|
c.lex.newlines = 0
|
||||||
state = plainScalarEnd
|
state = plainScalarEnd
|
||||||
stored = blockAfterObject
|
stored = blockAfterObject
|
||||||
|
@ -640,9 +647,19 @@ parserState scalarEnd:
|
||||||
parserState plainScalarEnd:
|
parserState plainScalarEnd:
|
||||||
c.currentScalar(e)
|
c.currentScalar(e)
|
||||||
result = true
|
result = true
|
||||||
state = objectEnd
|
c.lastTokenContextImpl = proc(s: YamlStream, line, column: var int,
|
||||||
|
lineContent: var string): bool {.raises: [].} =
|
||||||
|
let c = ParserContext(s)
|
||||||
|
(line, column) = c.plainScalarStart
|
||||||
|
lineContent = c.lex.getTokenLine(c.plainScalarStart, true)
|
||||||
|
result = true
|
||||||
|
state = afterPlainScalarYield
|
||||||
stored = blockAfterObject
|
stored = blockAfterObject
|
||||||
|
|
||||||
|
parserState afterPlainScalarYield:
|
||||||
|
c.lastTokenContextImpl = lastTokenContext
|
||||||
|
state = objectEnd
|
||||||
|
|
||||||
parserState blockAfterObject:
|
parserState blockAfterObject:
|
||||||
case c.lex.cur
|
case c.lex.cur
|
||||||
of ltIndentation, ltEmptyLine:
|
of ltIndentation, ltEmptyLine:
|
||||||
|
@ -1002,14 +1019,6 @@ parserState flowAfterObject:
|
||||||
else:
|
else:
|
||||||
raise c.generateError("Unexpected content (expected flow indicator)")
|
raise c.generateError("Unexpected content (expected flow indicator)")
|
||||||
|
|
||||||
proc lastTokenContext(s: YamlStream, line, column: var int,
|
|
||||||
lineContent: var string): bool =
|
|
||||||
let c = ParserContext(s)
|
|
||||||
line = c.lex.curStartPos.line
|
|
||||||
column = c.lex.curStartPos.column
|
|
||||||
lineContent = c.lex.getTokenLine(true)
|
|
||||||
result = true
|
|
||||||
|
|
||||||
# --- parser initialization ---
|
# --- parser initialization ---
|
||||||
|
|
||||||
proc init(c: ParserContext, p: YamlParser) =
|
proc init(c: ParserContext, p: YamlParser) =
|
||||||
|
|
|
@ -106,6 +106,12 @@ proc safeTagUri(id: TagId): string {.raises: [].} =
|
||||||
else: return uri
|
else: return uri
|
||||||
except KeyError: internalError("Unexpected KeyError for TagId " & $id)
|
except KeyError: internalError("Unexpected KeyError for TagId " & $id)
|
||||||
|
|
||||||
|
proc constructionError(s: YamlStream, msg: string): ref YamlConstructionError =
|
||||||
|
result = newException(YamlConstructionError, msg)
|
||||||
|
if not s.getLastTokenContext(result.line, result.column, result.lineContent):
|
||||||
|
(result.line, result.column) = (-1, -1)
|
||||||
|
result.lineContent = ""
|
||||||
|
|
||||||
template constructScalarItem*(s: var YamlStream, i: untyped,
|
template constructScalarItem*(s: var YamlStream, i: untyped,
|
||||||
t: typedesc, content: untyped) =
|
t: typedesc, content: untyped) =
|
||||||
## Helper template for implementing ``constructObject`` for types that
|
## Helper template for implementing ``constructObject`` for types that
|
||||||
|
@ -113,13 +119,14 @@ template constructScalarItem*(s: var YamlStream, i: untyped,
|
||||||
## the scalar as ``YamlStreamEvent`` in the content. Exceptions raised in
|
## the scalar as ``YamlStreamEvent`` in the content. Exceptions raised in
|
||||||
## the content will be automatically catched and wrapped in
|
## the content will be automatically catched and wrapped in
|
||||||
## ``YamlConstructionError``, which will then be raised.
|
## ``YamlConstructionError``, which will then be raised.
|
||||||
|
bind constructionError
|
||||||
let i = s.next()
|
let i = s.next()
|
||||||
if i.kind != yamlScalar:
|
if i.kind != yamlScalar:
|
||||||
raise newException(YamlConstructionError, "Expected scalar")
|
raise constructionError(s, "Expected scalar")
|
||||||
try: content
|
try: content
|
||||||
except YamlConstructionError: raise
|
except YamlConstructionError: raise
|
||||||
except Exception:
|
except Exception:
|
||||||
var e = newException(YamlConstructionError,
|
var e = constructionError(s,
|
||||||
"Cannot construct to " & name(t) & ": " & item.scalarContent)
|
"Cannot construct to " & name(t) & ": " & item.scalarContent)
|
||||||
e.parent = getCurrentException()
|
e.parent = getCurrentException()
|
||||||
raise e
|
raise e
|
||||||
|
@ -139,22 +146,28 @@ proc representObject*(value: string, ts: TagStyle,
|
||||||
## represents a string as YAML scalar
|
## represents a string as YAML scalar
|
||||||
c.put(scalarEvent(value, tag, yAnchorNone))
|
c.put(scalarEvent(value, tag, yAnchorNone))
|
||||||
|
|
||||||
proc parseHex[T: int8|int16|int32|int64|uint8|uint16|uint32|uint64](s: string): T =
|
proc parseHex[T: int8|int16|int32|int64|uint8|uint16|uint32|uint64](
|
||||||
|
s: YamlStream, val: string): T =
|
||||||
result = 0
|
result = 0
|
||||||
for i in 2..<s.len:
|
for i in 2..<val.len:
|
||||||
case s[i]
|
case val[i]
|
||||||
of '_': discard
|
of '_': discard
|
||||||
of '0'..'9': result = result shl 4 or T(ord(s[i]) - ord('0'))
|
of '0'..'9': result = result shl 4 or T(ord(val[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(val[i]) - ord('a') + 10)
|
||||||
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(val[i]) - ord('A') + 10)
|
||||||
else: raise newException(ValueError, "Invalid character in hex: " & escape("" & s[i]))
|
else:
|
||||||
|
raise s.constructionError("Invalid character in hex: " &
|
||||||
|
escape("" & val[i]))
|
||||||
|
|
||||||
proc parseOctal[T: int8|int16|int32|int64|uint8|uint16|uint32|uint64](s: string): T =
|
proc parseOctal[T: int8|int16|int32|int64|uint8|uint16|uint32|uint64](
|
||||||
for i in 2..<s.len:
|
s: YamlStream, val: string): T =
|
||||||
case s[i]
|
for i in 2..<val.len:
|
||||||
|
case val[i]
|
||||||
of '_': discard
|
of '_': discard
|
||||||
of '0'..'7': result = result shl 3 + T((ord(s[i]) - ord('0')))
|
of '0'..'7': result = result shl 3 + T((ord(val[i]) - ord('0')))
|
||||||
else: raise newException(ValueError, "Invalid character in hex: " & escape("" & s[i]))
|
else:
|
||||||
|
raise s.constructionError("Invalid character in hex: " &
|
||||||
|
escape("" & val[i]))
|
||||||
|
|
||||||
proc constructObject*[T: int8|int16|int32|int64](
|
proc constructObject*[T: int8|int16|int32|int64](
|
||||||
s: var YamlStream, c: ConstructionContext, result: var T)
|
s: var YamlStream, c: ConstructionContext, result: var T)
|
||||||
|
@ -162,9 +175,9 @@ proc constructObject*[T: int8|int16|int32|int64](
|
||||||
## constructs an integer value from a YAML scalar
|
## constructs an integer value from a YAML scalar
|
||||||
constructScalarItem(s, item, T):
|
constructScalarItem(s, item, T):
|
||||||
if item.scalarContent[0] == '0' and item.scalarContent[1] in {'x', 'X' }:
|
if item.scalarContent[0] == '0' and item.scalarContent[1] in {'x', 'X' }:
|
||||||
result = parseHex[T](item.scalarContent)
|
result = parseHex[T](s, item.scalarContent)
|
||||||
elif item.scalarContent[0] == '0' and item.scalarContent[1] in {'o', 'O'}:
|
elif item.scalarContent[0] == '0' and item.scalarContent[1] in {'o', 'O'}:
|
||||||
result = parseOctal[T](item.scalarContent)
|
result = parseOctal[T](s, item.scalarContent)
|
||||||
else:
|
else:
|
||||||
result = T(parseBiggestInt(item.scalarContent))
|
result = T(parseBiggestInt(item.scalarContent))
|
||||||
|
|
||||||
|
@ -201,9 +214,9 @@ proc constructObject*[T: uint8|uint16|uint32|uint64](
|
||||||
## construct an unsigned integer value from a YAML scalar
|
## construct an unsigned integer value from a YAML scalar
|
||||||
constructScalarItem(s, item, T):
|
constructScalarItem(s, item, T):
|
||||||
if item.scalarContent[0] == '0' and item.scalarContent[1] in {'x', 'X'}:
|
if item.scalarContent[0] == '0' and item.scalarContent[1] in {'x', 'X'}:
|
||||||
result = parseHex[T](item.scalarContent)
|
result = parseHex[T](s, item.scalarContent)
|
||||||
elif item.scalarContent[0] == '0' and item.scalarContent[1] in {'o', 'O'}:
|
elif item.scalarContent[0] == '0' and item.scalarContent[1] in {'o', 'O'}:
|
||||||
result = parseOctal[T](item.scalarContent)
|
result = parseOctal[T](s, item.scalarContent)
|
||||||
else: result = T(parseBiggestUInt(item.scalarContent))
|
else: result = T(parseBiggestUInt(item.scalarContent))
|
||||||
|
|
||||||
proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
||||||
|
@ -251,8 +264,8 @@ proc constructObject*[T: float|float32|float64](
|
||||||
else: result = Inf
|
else: result = Inf
|
||||||
of yTypeFloatNaN: result = NaN
|
of yTypeFloatNaN: result = NaN
|
||||||
else:
|
else:
|
||||||
raise newException(YamlConstructionError,
|
raise s.constructionError("Cannot construct to float: " &
|
||||||
"Cannot construct to float: " & item.scalarContent)
|
escape(item.scalarContent))
|
||||||
|
|
||||||
proc representObject*[T: float|float32|float64](value: T, ts: TagStyle,
|
proc representObject*[T: float|float32|float64](value: T, ts: TagStyle,
|
||||||
c: SerializationContext, tag: TagId) {.raises: [].} =
|
c: SerializationContext, tag: TagId) {.raises: [].} =
|
||||||
|
@ -274,8 +287,8 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
||||||
of yTypeBoolTrue: result = true
|
of yTypeBoolTrue: result = true
|
||||||
of yTypeBoolFalse: result = false
|
of yTypeBoolFalse: result = false
|
||||||
else:
|
else:
|
||||||
raise newException(YamlConstructionError,
|
raise s.constructionError("Cannot construct to bool: " &
|
||||||
"Cannot construct to bool: " & item.scalarContent)
|
escape(item.scalarContent))
|
||||||
|
|
||||||
proc representObject*(value: bool, ts: TagStyle, c: SerializationContext,
|
proc representObject*(value: bool, ts: TagStyle, c: SerializationContext,
|
||||||
tag: TagId) {.raises: [].} =
|
tag: TagId) {.raises: [].} =
|
||||||
|
@ -288,8 +301,8 @@ proc constructObject*(s: var YamlStream, c: ConstructionContext,
|
||||||
## constructs a char value from a YAML scalar
|
## constructs a char value from a YAML scalar
|
||||||
constructScalarItem(s, item, char):
|
constructScalarItem(s, item, char):
|
||||||
if item.scalarContent.len != 1:
|
if item.scalarContent.len != 1:
|
||||||
raise newException(YamlConstructionError,
|
raise s.constructionError("Cannot construct to char (length != 1): " &
|
||||||
"Cannot construct to char (length != 1): " & item.scalarContent)
|
escape(item.scalarContent))
|
||||||
else: result = item.scalarContent[0]
|
else: result = item.scalarContent[0]
|
||||||
|
|
||||||
proc representObject*(value: char, ts: TagStyle, c: SerializationContext,
|
proc representObject*(value: char, ts: TagStyle, c: SerializationContext,
|
||||||
|
@ -311,7 +324,7 @@ proc constructObject*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
## constructs a Nim seq from a YAML sequence
|
## constructs a Nim seq from a YAML sequence
|
||||||
let event = s.next()
|
let event = s.next()
|
||||||
if event.kind != yamlStartSeq:
|
if event.kind != yamlStartSeq:
|
||||||
raise newException(YamlConstructionError, "Expected sequence start")
|
raise s.constructionError("Expected sequence start")
|
||||||
result = newSeq[T]()
|
result = newSeq[T]()
|
||||||
while s.peek().kind != yamlEndSeq:
|
while s.peek().kind != yamlEndSeq:
|
||||||
var item: T
|
var item: T
|
||||||
|
@ -325,7 +338,7 @@ proc constructObject*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
## constructs a Nim seq from a YAML sequence
|
## constructs a Nim seq from a YAML sequence
|
||||||
let event = s.next()
|
let event = s.next()
|
||||||
if event.kind != yamlStartSeq:
|
if event.kind != yamlStartSeq:
|
||||||
raise newException(YamlConstructionError, "Expected sequence start")
|
raise s.constructionError("Expected sequence start")
|
||||||
result = {}
|
result = {}
|
||||||
while s.peek().kind != yamlEndSeq:
|
while s.peek().kind != yamlEndSeq:
|
||||||
var item: T
|
var item: T
|
||||||
|
@ -354,15 +367,15 @@ proc constructObject*[I, T](s: var YamlStream, c: ConstructionContext,
|
||||||
## constructs a Nim array from a YAML sequence
|
## constructs a Nim array from a YAML sequence
|
||||||
var event = s.next()
|
var event = s.next()
|
||||||
if event.kind != yamlStartSeq:
|
if event.kind != yamlStartSeq:
|
||||||
raise newException(YamlConstructionError, "Expected sequence start")
|
raise s.constructionError("Expected sequence start")
|
||||||
for index in low(I)..high(I):
|
for index in low(I)..high(I):
|
||||||
event = s.peek()
|
event = s.peek()
|
||||||
if event.kind == yamlEndSeq:
|
if event.kind == yamlEndSeq:
|
||||||
raise newException(YamlConstructionError, "Too few array values")
|
raise s.constructionError("Too few array values")
|
||||||
constructChild(s, c, result[index])
|
constructChild(s, c, result[index])
|
||||||
event = s.next()
|
event = s.next()
|
||||||
if event.kind != yamlEndSeq:
|
if event.kind != yamlEndSeq:
|
||||||
raise newException(YamlConstructionError, "Too much array values")
|
raise s.constructionError("Too many array values")
|
||||||
|
|
||||||
proc representObject*[I, T](value: array[I, T], ts: TagStyle,
|
proc representObject*[I, T](value: array[I, T], ts: TagStyle,
|
||||||
c: SerializationContext, tag: TagId) =
|
c: SerializationContext, tag: TagId) =
|
||||||
|
@ -388,8 +401,7 @@ proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext,
|
||||||
## constructs a Nim Table from a YAML mapping
|
## constructs a Nim Table from a YAML mapping
|
||||||
let event = s.next()
|
let event = s.next()
|
||||||
if event.kind != yamlStartMap:
|
if event.kind != yamlStartMap:
|
||||||
raise newException(YamlConstructionError, "Expected map start, got " &
|
raise s.constructionError("Expected map start, got " & $event.kind)
|
||||||
$event.kind)
|
|
||||||
result = initTable[K, V]()
|
result = initTable[K, V]()
|
||||||
while s.peek.kind != yamlEndMap:
|
while s.peek.kind != yamlEndMap:
|
||||||
var
|
var
|
||||||
|
@ -398,7 +410,7 @@ proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext,
|
||||||
constructChild(s, c, key)
|
constructChild(s, c, key)
|
||||||
constructChild(s, c, value)
|
constructChild(s, c, value)
|
||||||
if result.contains(key):
|
if result.contains(key):
|
||||||
raise newException(YamlConstructionError, "Duplicate table key!")
|
raise s.constructionError("Duplicate table key!")
|
||||||
result[key] = value
|
result[key] = value
|
||||||
discard s.next()
|
discard s.next()
|
||||||
|
|
||||||
|
@ -426,25 +438,24 @@ proc constructObject*[K, V](s: var YamlStream, c: ConstructionContext,
|
||||||
result: var OrderedTable[K, V])
|
result: var OrderedTable[K, V])
|
||||||
{.raises: [YamlConstructionError, YamlStreamError].} =
|
{.raises: [YamlConstructionError, YamlStreamError].} =
|
||||||
## constructs a Nim OrderedTable from a YAML mapping
|
## constructs a Nim OrderedTable from a YAML mapping
|
||||||
let event = s.next()
|
var event = s.next()
|
||||||
if event.kind != yamlStartSeq:
|
if event.kind != yamlStartSeq:
|
||||||
raise newException(YamlConstructionError, "Expected seq start, got " &
|
raise s.constructionError("Expected seq start, got " & $event.kind)
|
||||||
$event.kind)
|
|
||||||
result = initOrderedTable[K, V]()
|
result = initOrderedTable[K, V]()
|
||||||
while s.peek.kind != yamlEndSeq:
|
while s.peek.kind != yamlEndSeq:
|
||||||
var
|
var
|
||||||
key: K
|
key: K
|
||||||
value: V
|
value: V
|
||||||
if s.next().kind != yamlStartMap:
|
event = s.next()
|
||||||
raise newException(YamlConstructionError,
|
if event.kind != yamlStartMap:
|
||||||
"Expected map start, got " & $event.kind)
|
raise s.constructionError("Expected map start, got " & $event.kind)
|
||||||
constructChild(s, c, key)
|
constructChild(s, c, key)
|
||||||
constructChild(s, c, value)
|
constructChild(s, c, value)
|
||||||
if s.next().kind != yamlEndMap:
|
event = s.next()
|
||||||
raise newException(YamlConstructionError,
|
if event.kind != yamlEndMap:
|
||||||
"Expected map end, got " & $event.kind)
|
raise s.constructionError("Expected map end, got " & $event.kind)
|
||||||
if result.contains(key):
|
if result.contains(key):
|
||||||
raise newException(YamlConstructionError, "Duplicate table key!")
|
raise s.constructionError("Duplicate table key!")
|
||||||
result.add(key, value)
|
result.add(key, value)
|
||||||
discard s.next()
|
discard s.next()
|
||||||
|
|
||||||
|
@ -499,41 +510,42 @@ macro matchMatrix(t: typedesc): untyped =
|
||||||
for i in 0..<numFields:
|
for i in 0..<numFields:
|
||||||
result.add(newLit(false))
|
result.add(newLit(false))
|
||||||
|
|
||||||
proc checkDuplicate(t: typedesc, name: string, i: int, matched: NimNode):
|
proc checkDuplicate(s: NimNode, t: typedesc, name: string, i: int,
|
||||||
NimNode {.compileTime.} =
|
matched: NimNode): NimNode {.compileTime.} =
|
||||||
result = newIfStmt((newNimNode(nnkBracketExpr).add(matched, newLit(i)),
|
result = newIfStmt((newNimNode(nnkBracketExpr).add(matched, newLit(i)),
|
||||||
newNimNode(nnkRaiseStmt).add(newCall("newException", newIdentNode(
|
newNimNode(nnkRaiseStmt).add(newCall(bindSym("constructionError"), s,
|
||||||
"YamlConstructionError"), newLit("While constructing " &
|
newLit("While constructing " & typetraits.name(t) &
|
||||||
typetraits.name(t) & ": Duplicate field: " & escape(name))))))
|
": Duplicate field: " & escape(name))))))
|
||||||
|
|
||||||
proc checkMissing(t: typedesc, name: string, i: int, matched: NimNode):
|
proc checkMissing(s: NimNode, t: typedesc, name: string, i: int,
|
||||||
NimNode {.compileTime.} =
|
matched: NimNode): NimNode {.compileTime.} =
|
||||||
result = newIfStmt((newCall("not", newNimNode(nnkBracketExpr).add(matched,
|
result = newIfStmt((newCall("not", newNimNode(nnkBracketExpr).add(matched,
|
||||||
newLit(i))), newNimNode(nnkRaiseStmt).add(newCall("newException",
|
newLit(i))), newNimNode(nnkRaiseStmt).add(newCall(
|
||||||
newIdentNode("YamlConstructionError"), newLit("While constructing " &
|
bindSym("constructionError"), s, newLit("While constructing " &
|
||||||
typetraits.name(t) & ": Missing field: " & escape(name))))))
|
typetraits.name(t) & ": Missing field: " & escape(name))))))
|
||||||
|
|
||||||
proc markAsFound(i: int, matched: NimNode): NimNode {.compileTime.} =
|
proc markAsFound(i: int, matched: NimNode): NimNode {.compileTime.} =
|
||||||
newAssignment(newNimNode(nnkBracketExpr).add(matched, newLit(i)),
|
newAssignment(newNimNode(nnkBracketExpr).add(matched, newLit(i)),
|
||||||
newLit(true))
|
newLit(true))
|
||||||
|
|
||||||
macro ensureAllFieldsPresent(t: typedesc, o: typed, matched: typed): typed =
|
macro ensureAllFieldsPresent(s: YamlStream, t: typedesc, o: typed,
|
||||||
|
matched: typed): typed =
|
||||||
result = newStmtList()
|
result = newStmtList()
|
||||||
let
|
let
|
||||||
tDesc = getType(getType(t)[1])
|
tDesc = getType(getType(t)[1])
|
||||||
var field = 0
|
var field = 0
|
||||||
for child in tDesc[2].children:
|
for child in tDesc[2].children:
|
||||||
if child.kind == nnkRecCase:
|
if child.kind == nnkRecCase:
|
||||||
result.add(checkMissing(t, $child[0], field, matched))
|
result.add(checkMissing(s, t, $child[0], field, matched))
|
||||||
for bIndex in 1 .. len(child) - 1:
|
for bIndex in 1 .. len(child) - 1:
|
||||||
let discChecks = newStmtList()
|
let discChecks = newStmtList()
|
||||||
for item in child[bIndex][1].children:
|
for item in child[bIndex][1].children:
|
||||||
inc(field)
|
inc(field)
|
||||||
discChecks.add(checkMissing(t, $item, field, matched))
|
discChecks.add(checkMissing(s, t, $item, field, matched))
|
||||||
result.add(newIfStmt((infix(newDotExpr(o, newIdentNode($child[0])),
|
result.add(newIfStmt((infix(newDotExpr(o, newIdentNode($child[0])),
|
||||||
"==", child[bIndex][0]), discChecks)))
|
"==", child[bIndex][0]), discChecks)))
|
||||||
else:
|
else:
|
||||||
result.add(checkMissing(t, $child, field, matched))
|
result.add(checkMissing(s, t, $child, field, matched))
|
||||||
inc(field)
|
inc(field)
|
||||||
|
|
||||||
macro constructFieldValue(t: typedesc, stream: untyped, context: untyped,
|
macro constructFieldValue(t: typedesc, stream: untyped, context: untyped,
|
||||||
|
@ -548,7 +560,7 @@ macro constructFieldValue(t: typedesc, stream: untyped, context: untyped,
|
||||||
discType = newCall("type", discriminant)
|
discType = newCall("type", discriminant)
|
||||||
var disOb = newNimNode(nnkOfBranch).add(newStrLitNode($child[0]))
|
var disOb = newNimNode(nnkOfBranch).add(newStrLitNode($child[0]))
|
||||||
disOb.add(newStmtList(
|
disOb.add(newStmtList(
|
||||||
checkDuplicate(t, $child[0], fieldIndex, matched),
|
checkDuplicate(stream, t, $child[0], fieldIndex, matched),
|
||||||
newNimNode(nnkVarSection).add(
|
newNimNode(nnkVarSection).add(
|
||||||
newNimNode(nnkIdentDefs).add(
|
newNimNode(nnkIdentDefs).add(
|
||||||
newIdentNode("value"), discType, newEmptyNode())),
|
newIdentNode("value"), discType, newEmptyNode())),
|
||||||
|
@ -566,24 +578,24 @@ macro constructFieldValue(t: typedesc, stream: untyped, context: untyped,
|
||||||
var ifStmt = newIfStmt((cond: discTest, body: newStmtList(
|
var ifStmt = newIfStmt((cond: discTest, body: newStmtList(
|
||||||
newCall("constructChild", stream, context, field))))
|
newCall("constructChild", stream, context, field))))
|
||||||
ifStmt.add(newNimNode(nnkElse).add(newNimNode(nnkRaiseStmt).add(
|
ifStmt.add(newNimNode(nnkElse).add(newNimNode(nnkRaiseStmt).add(
|
||||||
newCall("newException", newIdentNode("YamlConstructionError"),
|
newCall(bindSym("constructionError"), stream,
|
||||||
infix(newStrLitNode("Field " & $item & " not allowed for " &
|
infix(newStrLitNode("Field " & $item & " not allowed for " &
|
||||||
$child[0] & " == "), "&", prefix(discriminant, "$"))))))
|
$child[0] & " == "), "&", prefix(discriminant, "$"))))))
|
||||||
ob.add(newStmtList(checkDuplicate(t, $item, fieldIndex, matched),
|
ob.add(newStmtList(checkDuplicate(stream, t, $item, fieldIndex,
|
||||||
ifStmt, markAsFound(fieldIndex, matched)))
|
matched), ifStmt, markAsFound(fieldIndex, matched)))
|
||||||
result.add(ob)
|
result.add(ob)
|
||||||
else:
|
else:
|
||||||
yAssert child.kind == nnkSym
|
yAssert child.kind == nnkSym
|
||||||
var ob = newNimNode(nnkOfBranch).add(newStrLitNode($child))
|
var ob = newNimNode(nnkOfBranch).add(newStrLitNode($child))
|
||||||
let field = newDotExpr(o, newIdentNode($child))
|
let field = newDotExpr(o, newIdentNode($child))
|
||||||
ob.add(newStmtList(
|
ob.add(newStmtList(
|
||||||
checkDuplicate(t, $child, fieldIndex, matched),
|
checkDuplicate(stream, t, $child, fieldIndex, matched),
|
||||||
newCall("constructChild", stream, context, field),
|
newCall("constructChild", stream, context, field),
|
||||||
markAsFound(fieldIndex, matched)))
|
markAsFound(fieldIndex, matched)))
|
||||||
result.add(ob)
|
result.add(ob)
|
||||||
inc(fieldIndex)
|
inc(fieldIndex)
|
||||||
result.add(newNimNode(nnkElse).add(newNimNode(nnkRaiseStmt).add(
|
result.add(newNimNode(nnkElse).add(newNimNode(nnkRaiseStmt).add(
|
||||||
newCall("newException", newIdentNode("YamlConstructionError"),
|
newCall(bindSym("constructionError"), stream,
|
||||||
infix(newLit("While constructing " & typetraits.name(t) &
|
infix(newLit("While constructing " & typetraits.name(t) &
|
||||||
": Unknown field: "), "&", name)))))
|
": Unknown field: "), "&", name)))))
|
||||||
|
|
||||||
|
@ -604,8 +616,8 @@ proc constructObject*[O: object|tuple](
|
||||||
startKind = when isVariantObject(O): yamlStartSeq else: yamlStartMap
|
startKind = when isVariantObject(O): yamlStartSeq else: yamlStartMap
|
||||||
endKind = when isVariantObject(O): yamlEndSeq else: yamlEndMap
|
endKind = when isVariantObject(O): yamlEndSeq else: yamlEndMap
|
||||||
if e.kind != startKind:
|
if e.kind != startKind:
|
||||||
raise newException(YamlConstructionError, "While constructing " &
|
raise s.constructionError("While constructing " &
|
||||||
typetraits.name(O) & ": Expected map start, got " & $e.kind)
|
typetraits.name(O) & ": Expected " & $startKind & ", got " & $e.kind)
|
||||||
when isVariantObject(O): reset(result) # make discriminants writeable
|
when isVariantObject(O): reset(result) # make discriminants writeable
|
||||||
while s.peek.kind != endKind:
|
while s.peek.kind != endKind:
|
||||||
# todo: check for duplicates in input and raise appropriate exception
|
# todo: check for duplicates in input and raise appropriate exception
|
||||||
|
@ -613,12 +625,10 @@ proc constructObject*[O: object|tuple](
|
||||||
e = s.next()
|
e = s.next()
|
||||||
when isVariantObject(O):
|
when isVariantObject(O):
|
||||||
if e.kind != yamlStartMap:
|
if e.kind != yamlStartMap:
|
||||||
raise newException(YamlConstructionError,
|
raise s.constructionError("Expected single-pair map, got " & $e.kind)
|
||||||
"Expected single-pair map, got " & $e.kind)
|
|
||||||
e = s.next()
|
e = s.next()
|
||||||
if e.kind != yamlScalar:
|
if e.kind != yamlScalar:
|
||||||
raise newException(YamlConstructionError,
|
raise s.constructionError("Expected field name, got " & $e.kind)
|
||||||
"Expected field name, got " & $e.kind)
|
|
||||||
let name = e.scalarContent
|
let name = e.scalarContent
|
||||||
when result is tuple:
|
when result is tuple:
|
||||||
var i = 0
|
var i = 0
|
||||||
|
@ -626,7 +636,7 @@ proc constructObject*[O: object|tuple](
|
||||||
for fname, value in fieldPairs(result):
|
for fname, value in fieldPairs(result):
|
||||||
if fname == name:
|
if fname == name:
|
||||||
if matched[i]:
|
if matched[i]:
|
||||||
raise newException(YamlConstructionError, "While constructing " &
|
raise s.constructionError("While constructing " &
|
||||||
typetraits.name(O) & ": Duplicate field: " & escape(name))
|
typetraits.name(O) & ": Duplicate field: " & escape(name))
|
||||||
constructChild(s, c, value)
|
constructChild(s, c, value)
|
||||||
matched[i] = true
|
matched[i] = true
|
||||||
|
@ -634,24 +644,24 @@ proc constructObject*[O: object|tuple](
|
||||||
break
|
break
|
||||||
inc(i)
|
inc(i)
|
||||||
if not found:
|
if not found:
|
||||||
raise newException(YamlConstructionError, "While constructing " &
|
raise s.constructionError("While constructing " &
|
||||||
typetraits.name(O) & ": Unknown field: " & escape(name))
|
typetraits.name(O) & ": Unknown field: " & escape(name))
|
||||||
else:
|
else:
|
||||||
constructFieldValue(O, s, c, name, result, matched)
|
constructFieldValue(O, s, c, name, result, matched)
|
||||||
when isVariantObject(O):
|
when isVariantObject(O):
|
||||||
e = s.next()
|
e = s.next()
|
||||||
if e.kind != yamlEndMap:
|
if e.kind != yamlEndMap:
|
||||||
raise newException(YamlConstructionError,
|
raise s.constructionError("Expected end of single-pair map, got " &
|
||||||
"Expected end of single-pair map, got " & $e.kind)
|
$e.kind)
|
||||||
discard s.next()
|
discard s.next()
|
||||||
when result is tuple:
|
when result is tuple:
|
||||||
var i = 0
|
var i = 0
|
||||||
for fname, value in fieldPairs(result):
|
for fname, value in fieldPairs(result):
|
||||||
if not matched[i]:
|
if not matched[i]:
|
||||||
raise newException(YamlConstructionError, "While constructing " &
|
raise s.constructionError("While constructing " &
|
||||||
typetraits.name(O) & ": Field missing: " & escape(fname))
|
typetraits.name(O) & ": Field missing: " & escape(fname))
|
||||||
inc(i)
|
inc(i)
|
||||||
else: ensureAllFieldsPresent(O, result, matched)
|
else: ensureAllFieldsPresent(s, O, result, matched)
|
||||||
|
|
||||||
proc representObject*[O: object|tuple](value: O, ts: TagStyle,
|
proc representObject*[O: object|tuple](value: O, ts: TagStyle,
|
||||||
c: SerializationContext, tag: TagId) =
|
c: SerializationContext, tag: TagId) =
|
||||||
|
@ -674,12 +684,11 @@ proc constructObject*[O: enum](s: var YamlStream, c: ConstructionContext,
|
||||||
## constructs a Nim enum from a YAML scalar
|
## constructs a Nim enum from a YAML scalar
|
||||||
let e = s.next()
|
let e = s.next()
|
||||||
if e.kind != yamlScalar:
|
if e.kind != yamlScalar:
|
||||||
raise newException(YamlConstructionError, "Expected scalar, got " &
|
raise s.constructionError("Expected scalar, got " & $e.kind)
|
||||||
$e.kind)
|
|
||||||
try: result = parseEnum[O](e.scalarContent)
|
try: result = parseEnum[O](e.scalarContent)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
var ex = newException(YamlConstructionError, "Cannot parse '" &
|
var ex = s.constructionError("Cannot parse '" &
|
||||||
e.scalarContent & "' as " & type(O).name)
|
escape(e.scalarContent) & "' as " & type(O).name)
|
||||||
ex.parent = getCurrentException()
|
ex.parent = getCurrentException()
|
||||||
raise ex
|
raise ex
|
||||||
|
|
||||||
|
@ -715,7 +724,7 @@ macro constructImplicitVariantObject(s, c, r, possibleTagIds: untyped,
|
||||||
branch.add(branchContent)
|
branch.add(branchContent)
|
||||||
ifStmt.add(branch)
|
ifStmt.add(branch)
|
||||||
let raiseStmt = newNimNode(nnkRaiseStmt).add(
|
let raiseStmt = newNimNode(nnkRaiseStmt).add(
|
||||||
newCall("newException", newIdentNode("YamlConstructionError"),
|
newCall(bindSym("constructionError"), s,
|
||||||
infix(newStrLitNode("This value type does not map to any field in " &
|
infix(newStrLitNode("This value type does not map to any field in " &
|
||||||
typetraits.name(t) & ": "), "&",
|
typetraits.name(t) & ": "), "&",
|
||||||
newCall("uri", newIdentNode("serializationTagLibrary"),
|
newCall("uri", newIdentNode("serializationTagLibrary"),
|
||||||
|
@ -751,7 +760,7 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
of yTypeBoolTrue, yTypeBoolFalse:
|
of yTypeBoolTrue, yTypeBoolFalse:
|
||||||
possibleTagIds.add(yamlTag(bool))
|
possibleTagIds.add(yamlTag(bool))
|
||||||
of yTypeNull:
|
of yTypeNull:
|
||||||
raise newException(YamlConstructionError, "not implemented!")
|
raise s.constructionError("not implemented!")
|
||||||
of yTypeUnknown:
|
of yTypeUnknown:
|
||||||
possibleTagIds.add(yamlTag(string))
|
possibleTagIds.add(yamlTag(string))
|
||||||
of yTagExclamationMark:
|
of yTagExclamationMark:
|
||||||
|
@ -760,12 +769,12 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
possibleTagIds.add(item.scalarTag)
|
possibleTagIds.add(item.scalarTag)
|
||||||
of yamlStartMap:
|
of yamlStartMap:
|
||||||
if item.mapTag in [yTagQuestionMark, yTagExclamationMark]:
|
if item.mapTag in [yTagQuestionMark, yTagExclamationMark]:
|
||||||
raise newException(YamlConstructionError,
|
raise s.constructionError(
|
||||||
"Complex value of implicit variant object type must have a tag.")
|
"Complex value of implicit variant object type must have a tag.")
|
||||||
possibleTagIds.add(item.mapTag)
|
possibleTagIds.add(item.mapTag)
|
||||||
of yamlStartSeq:
|
of yamlStartSeq:
|
||||||
if item.seqTag in [yTagQuestionMark, yTagExclamationMark]:
|
if item.seqTag in [yTagQuestionMark, yTagExclamationMark]:
|
||||||
raise newException(YamlConstructionError,
|
raise s.constructionError(
|
||||||
"Complex value of implicit variant object type must have a tag.")
|
"Complex value of implicit variant object type must have a tag.")
|
||||||
possibleTagIds.add(item.seqTag)
|
possibleTagIds.add(item.seqTag)
|
||||||
else: internalError("Unexpected item kind: " & $item.kind)
|
else: internalError("Unexpected item kind: " & $item.kind)
|
||||||
|
@ -775,22 +784,19 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
of yamlScalar:
|
of yamlScalar:
|
||||||
if item.scalarTag notin [yTagQuestionMark, yTagExclamationMark,
|
if item.scalarTag notin [yTagQuestionMark, yTagExclamationMark,
|
||||||
yamlTag(T)]:
|
yamlTag(T)]:
|
||||||
raise newException(YamlConstructionError, "Wrong tag for " &
|
raise s.constructionError("Wrong tag for " & typetraits.name(T))
|
||||||
typetraits.name(T))
|
|
||||||
elif item.scalarAnchor != yAnchorNone:
|
elif item.scalarAnchor != yAnchorNone:
|
||||||
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
raise s.constructionError("Anchor on non-ref type")
|
||||||
of yamlStartMap:
|
of yamlStartMap:
|
||||||
if item.mapTag notin [yTagQuestionMark, yamlTag(T)]:
|
if item.mapTag notin [yTagQuestionMark, yamlTag(T)]:
|
||||||
raise newException(YamlConstructionError, "Wrong tag for " &
|
raise s.constructionError("Wrong tag for " & typetraits.name(T))
|
||||||
typetraits.name(T))
|
|
||||||
elif item.mapAnchor != yAnchorNone:
|
elif item.mapAnchor != yAnchorNone:
|
||||||
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
raise s.constructionError("Anchor on non-ref type")
|
||||||
of yamlStartSeq:
|
of yamlStartSeq:
|
||||||
if item.seqTag notin [yTagQuestionMark, yamlTag(T)]:
|
if item.seqTag notin [yTagQuestionMark, yamlTag(T)]:
|
||||||
raise newException(YamlConstructionError, "Wrong tag for " &
|
raise s.constructionError("Wrong tag for " & typetraits.name(T))
|
||||||
typetraits.name(T))
|
|
||||||
elif item.seqAnchor != yAnchorNone:
|
elif item.seqAnchor != yAnchorNone:
|
||||||
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
raise s.constructionError("Anchor on non-ref type")
|
||||||
else: internalError("Unexpected item kind: " & $item.kind)
|
else: internalError("Unexpected item kind: " & $item.kind)
|
||||||
constructObject(s, c, result)
|
constructObject(s, c, result)
|
||||||
|
|
||||||
|
@ -804,9 +810,9 @@ proc constructChild*(s: var YamlStream, c: ConstructionContext,
|
||||||
return
|
return
|
||||||
elif item.scalarTag notin
|
elif item.scalarTag notin
|
||||||
[yTagQuestionMark, yTagExclamationMark, yamlTag(string)]:
|
[yTagQuestionMark, yTagExclamationMark, yamlTag(string)]:
|
||||||
raise newException(YamlConstructionError, "Wrong tag for string")
|
raise s.constructionError("Wrong tag for string")
|
||||||
elif item.scalarAnchor != yAnchorNone:
|
elif item.scalarAnchor != yAnchorNone:
|
||||||
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
raise s.constructionError("Anchor on non-ref type")
|
||||||
constructObject(s, c, result)
|
constructObject(s, c, result)
|
||||||
|
|
||||||
proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
|
@ -819,10 +825,9 @@ proc constructChild*[T](s: var YamlStream, c: ConstructionContext,
|
||||||
return
|
return
|
||||||
elif item.kind == yamlStartSeq:
|
elif item.kind == yamlStartSeq:
|
||||||
if item.seqTag notin [yTagQuestionMark, yamlTag(seq[T])]:
|
if item.seqTag notin [yTagQuestionMark, yamlTag(seq[T])]:
|
||||||
raise newException(YamlConstructionError, "Wrong tag for " &
|
raise s.constructionError("Wrong tag for " & typetraits.name(seq[T]))
|
||||||
typetraits.name(seq[T]))
|
|
||||||
elif item.seqAnchor != yAnchorNone:
|
elif item.seqAnchor != yAnchorNone:
|
||||||
raise newException(YamlConstructionError, "Anchor on non-ref type")
|
raise s.constructionError("Anchor on non-ref type")
|
||||||
constructObject(s, c, result)
|
constructObject(s, c, result)
|
||||||
|
|
||||||
proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
|
proc constructChild*[O](s: var YamlStream, c: ConstructionContext,
|
||||||
|
@ -948,10 +953,6 @@ proc load*[K](input: Stream | string, target: var K)
|
||||||
parser = newYamlParser(serializationTagLibrary)
|
parser = newYamlParser(serializationTagLibrary)
|
||||||
events = parser.parse(input)
|
events = parser.parse(input)
|
||||||
try: construct(events, target)
|
try: construct(events, target)
|
||||||
except YamlConstructionError:
|
|
||||||
var e = (ref YamlConstructionError)(getCurrentException())
|
|
||||||
discard events.getLastTokenContext(e.line, e.column, e.lineContent)
|
|
||||||
raise e
|
|
||||||
except YamlStreamError:
|
except YamlStreamError:
|
||||||
let e = (ref YamlStreamError)(getCurrentException())
|
let e = (ref YamlStreamError)(getCurrentException())
|
||||||
if e.parent of IOError: raise (ref IOError)(e.parent)
|
if e.parent of IOError: raise (ref IOError)(e.parent)
|
||||||
|
|
Loading…
Reference in New Issue