mirror of https://github.com/status-im/NimYAML.git
Implemented setDefaultValue.
This commit is contained in:
parent
fd05f828ad
commit
6402433d2a
|
@ -54,6 +54,9 @@ type
|
|||
of deD:
|
||||
neverThere: int
|
||||
|
||||
WithDefault = object
|
||||
a, b, c, d: string
|
||||
|
||||
markAsTransient(NonVariantWithTransient, a)
|
||||
markAsTransient(NonVariantWithTransient, c)
|
||||
|
||||
|
@ -61,7 +64,8 @@ markAsTransient(VariantWithTransient, gTemporary)
|
|||
markAsTransient(VariantWithTransient, cTemporary)
|
||||
markAsTransient(VariantWithTransient, neverThere)
|
||||
|
||||
|
||||
setDefaultValue(WithDefault, b, "b")
|
||||
setDefaultValue(WithDefault, d, "d")
|
||||
|
||||
proc `$`(v: BetterInt): string {.borrow.}
|
||||
proc `==`(left, right: BetterInt): bool {.borrow.}
|
||||
|
@ -579,6 +583,24 @@ next:
|
|||
assert(result[1].next == result[2])
|
||||
assert(result[2].next == result[0])
|
||||
|
||||
test "Load object with default values":
|
||||
let input = "a: abc\nc: dce"
|
||||
var result: WithDefault
|
||||
load(input, result)
|
||||
assert result.a == "abc"
|
||||
assert result.b == "b"
|
||||
assert result.c == "dce"
|
||||
assert result.d == "d"
|
||||
|
||||
test "Load object with partly default values":
|
||||
let input = "a: abc\nb: bcd\nc: cde"
|
||||
var result: WithDefault
|
||||
load(input, result)
|
||||
assert result.a == "abc"
|
||||
assert result.b == "bcd"
|
||||
assert result.c == "cde"
|
||||
assert result.d == "d"
|
||||
|
||||
test "Load nil values":
|
||||
let input = newStringStream("- ~\n- !!str ~")
|
||||
var result: seq[ref string]
|
||||
|
|
|
@ -536,24 +536,45 @@ proc checkDuplicate(s: NimNode, tName: string, name: string, i: int,
|
|||
newLit("While constructing " & tName & ": Duplicate field: " &
|
||||
escape(name))))))
|
||||
|
||||
proc checkMissing(s: NimNode, tName: string, name: string, i: int,
|
||||
matched: NimNode): NimNode {.compileTime.} =
|
||||
result = newIfStmt((newCall("not", newNimNode(nnkBracketExpr).add(matched,
|
||||
newLit(i))), newNimNode(nnkRaiseStmt).add(newCall(
|
||||
bindSym("constructionError"), s, newLit("While constructing " &
|
||||
tName & ": Missing field: " & escape(name))))))
|
||||
|
||||
proc markAsFound(i: int, matched: NimNode): NimNode {.compileTime.} =
|
||||
newAssignment(newNimNode(nnkBracketExpr).add(matched, newLit(i)),
|
||||
newLit(true))
|
||||
|
||||
let
|
||||
implicitVariantObjectMarker {.compileTime.} =
|
||||
newIdentNode(":implicitVariantObject")
|
||||
transientBitvectorProc {.compileTime.} =
|
||||
newIdentNode(":transientObject")
|
||||
defaultBitvectorProc {.compileTime.} =
|
||||
newIdentNode(":defaultBitvector")
|
||||
defaultValueGetter {.compileTime.} =
|
||||
newIdentNode(":defaultValueGetter")
|
||||
|
||||
var transientVectors {.compileTime.} = newSeq[set[int16]]()
|
||||
var
|
||||
transientVectors {.compileTime.} = newSeq[set[int16]]()
|
||||
defaultVectors {.compileTime.} = newSeq[set[int16]]()
|
||||
|
||||
proc addDefaultOr(tName: string, i: int, o: NimNode,
|
||||
field, elseBranch, defaultValues: NimNode): NimNode {.compileTime.} =
|
||||
let
|
||||
dbp = defaultBitvectorProc
|
||||
t = newIdentNode(tName)
|
||||
result = quote do:
|
||||
when compiles(`dbp`(`t`)):
|
||||
when `i` in defaultVectors[`dbp`(`t`)]:
|
||||
`o`.`field` = `defaultValues`.`field`
|
||||
else: `elseBranch`
|
||||
else: `elseBranch`
|
||||
|
||||
proc checkMissing(s: NimNode, t: typedesc, tName: string, field: NimNode,
|
||||
i: int, matched, o, defaultValues: NimNode):
|
||||
NimNode {.compileTime.} =
|
||||
result = newIfStmt((newCall("not", newNimNode(nnkBracketExpr).add(matched,
|
||||
newLit(i))), addDefaultOr(tName, i, o, field,
|
||||
newNimNode(nnkRaiseStmt).add(newCall(
|
||||
bindSym("constructionError"), s, newLit("While constructing " &
|
||||
tName & ": Missing field: " & escape($field)))), defaultValues)))
|
||||
echo result.repr
|
||||
|
||||
proc markAsFound(i: int, matched: NimNode): NimNode {.compileTime.} =
|
||||
newAssignment(newNimNode(nnkBracketExpr).add(matched, newLit(i)),
|
||||
newLit(true))
|
||||
|
||||
proc ifNotTransient(tSym: NimNode, fieldIndex: int, content: openarray[NimNode],
|
||||
elseError: bool = false, s: NimNode = nil, tName, fName: string = nil):
|
||||
|
@ -570,7 +591,12 @@ proc ifNotTransient(tSym: NimNode, fieldIndex: int, content: openarray[NimNode],
|
|||
|
||||
macro ensureAllFieldsPresent(s: YamlStream, t: typedesc, tIndex: int, o: typed,
|
||||
matched: typed): typed =
|
||||
result = newStmtList()
|
||||
let
|
||||
dbp = defaultBitvectorProc
|
||||
defaultValues = genSym(nskConst, "defaultValues")
|
||||
result = quote do:
|
||||
when compiles(`dbp`(`t`)):
|
||||
const `defaultValues` = `defaultValueGetter`(`t`)
|
||||
let
|
||||
tDecl = getType(t)
|
||||
tName = $tDecl[1]
|
||||
|
@ -578,7 +604,8 @@ macro ensureAllFieldsPresent(s: YamlStream, t: typedesc, tIndex: int, o: typed,
|
|||
var field = 0
|
||||
for child in tDesc[2].children:
|
||||
if child.kind == nnkRecCase:
|
||||
result.add(checkMissing(s, tName, $child[0], field, matched))
|
||||
result.add(checkMissing(s, t, tName, child[0], field, matched, o,
|
||||
defaultValues))
|
||||
for bIndex in 1 .. len(child) - 1:
|
||||
let discChecks = newStmtList()
|
||||
var
|
||||
|
@ -594,13 +621,14 @@ macro ensureAllFieldsPresent(s: YamlStream, t: typedesc, tIndex: int, o: typed,
|
|||
else: internalError("Unexpected child kind: " & $child[bIndex].kind)
|
||||
for item in child[bIndex][recListIndex].children:
|
||||
inc(field)
|
||||
discChecks.add(checkMissing(s, tName, $item, field, matched))
|
||||
discChecks.add(checkMissing(s, t, tName, item, field, matched, o,
|
||||
defaultValues))
|
||||
result.add(ifNotTransient(tIndex, field,
|
||||
[newIfStmt((infix(newDotExpr(o, newIdentNode($child[0])),
|
||||
"in", curValues), discChecks))]))
|
||||
else:
|
||||
result.add(ifNotTransient(tIndex, field,
|
||||
[checkMissing(s, tName, $child, field, matched)]))
|
||||
[checkMissing(s, t, tName, child, field, matched, o, defaultValues)]))
|
||||
inc(field)
|
||||
|
||||
macro fetchTransientIndex(t: typedesc, tIndex: untyped): typed =
|
||||
|
@ -1288,3 +1316,24 @@ macro markAsTransient*(t: typedesc, field: untyped): typed =
|
|||
static: transientVectors.add({})
|
||||
static:
|
||||
transientVectors[`transientBitvectorProc`(`t`)].incl(getFieldIndex(`t`, `field`))
|
||||
|
||||
macro setDefaultValue*(t: typedesc, field: untyped, value: typed): typed =
|
||||
let
|
||||
dSym = genSym(nskVar, ":default")
|
||||
nextBitvectorIndex = defaultVectors.len
|
||||
result = quote do:
|
||||
when compiles(`transientBitvectorProc`(`t`)):
|
||||
{.fatal: "Cannot set default value of transient field".}
|
||||
elif compiles(`implicitVariantObjectMarker`(`t`)):
|
||||
{.fatal: "Cannot set default value of implicit variant objects.".}
|
||||
when not compiles(`defaultValueGetter`(`t`)):
|
||||
var `dSym` {.compileTime.}: `t`
|
||||
template `defaultValueGetter`(t: typedesc[`t`]): auto =
|
||||
`dSym`
|
||||
proc `defaultBitvectorProc`*(myType: typedesc[`t`]): int
|
||||
{.compileTime.} = `nextBitvectorIndex`
|
||||
static: defaultVectors.add({})
|
||||
static:
|
||||
`defaultValueGetter`(`t`).`field` = `value`
|
||||
defaultVectors[`defaultBitvectorProc`(`t`)].incl(getFieldIndex(`t`, `field`))
|
||||
echo result.repr
|
Loading…
Reference in New Issue