aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2018-04-27 19:23:10 +0300
committerOskari Timperi <oskari.timperi@iki.fi>2018-04-27 19:23:10 +0300
commit47eddf8d571a6cb292d945bc0a9ec8c5b67aae29 (patch)
tree2fc8bd2ccb6bf07da864cf33c5615bcff860fd94
parentc68904433166a8c44ed958a53942f207afb401e5 (diff)
downloadnimpb-47eddf8d571a6cb292d945bc0a9ec8c5b67aae29.tar.gz
nimpb-47eddf8d571a6cb292d945bc0a9ec8c5b67aae29.zip
Generate object variants for oneofs
This fixes a segfault problem that I had, when running the conformance test suite. The following piece of code segfaulted on the last assignment: msg.oneofUint32 = 1 msg.oneofString = "test" If the first assignment was `0`, then there was no problem. Now we use the object variant, which gives nim runtime the ability to track what data the union holds.
-rw-r--r--nimpb/compiler/generator.nim25
1 files changed, 20 insertions, 5 deletions
diff --git a/nimpb/compiler/generator.nim b/nimpb/compiler/generator.nim
index 809788e..452e49e 100644
--- a/nimpb/compiler/generator.nim
+++ b/nimpb/compiler/generator.nim
@@ -659,16 +659,22 @@ iterator genType(message: Message): string =
for oneof in message.oneofs:
yield ""
- yield &"{message.names}_{oneof.name}_OneOf* {{.union.}} = object"
+ yield indent(&"{message.names}_{oneof.name}_Kind* {{.pure.}} = enum", 0)
for field in oneof.fields:
- yield indent(&"{quoteReserved(field.name)}: {field.fullType}", 4)
+ yield indent(&"{field.name.capitalizeAscii}", 4)
+ yield ""
+ yield &"{message.names}_{oneof.name}_OneOf* = object"
+ yield indent(&"case kind*: {message.names}_{oneof.name}_Kind", 4)
+ for field in oneof.fields:
+ yield indent(&"of {message.names}_{oneof.name}_Kind.{field.name.capitalizeAscii}: {quoteReserved(field.name)}*: {field.fullType}", 4)
iterator genNewMessageProc(msg: Message): string =
yield &"proc new{msg.names}*(): {msg.names} ="
yield indent("new(result)", 4)
yield indent("initMessage(result[])", 4)
for field in msg.fields:
- yield indent(&"result.{field.accessor} = {defaultValue(field)}", 4)
+ if field.oneof == nil:
+ yield indent(&"result.{field.accessor} = {defaultValue(field)}", 4)
yield ""
iterator oneofSiblings(field: Field): Field =
@@ -680,7 +686,10 @@ iterator oneofSiblings(field: Field): Field =
iterator genClearFieldProc(msg: Message, field: Field): string =
yield &"proc clear{field.name}*(message: {msg.names}) ="
- yield indent(&"message.{field.accessor} = {defaultValue(field)}", 4)
+ if field.oneof == nil:
+ yield indent(&"message.{field.accessor} = {defaultValue(field)}", 4)
+ else:
+ yield indent(&"reset(message.{field.oneof.name})", 4)
var numbers: seq[int] = @[field.number]
for sibling in oneofSiblings(field):
add(numbers, sibling.number)
@@ -697,7 +706,13 @@ iterator genHasFieldProc(msg: Message, field: Field): string =
iterator genSetFieldProc(msg: Message, field: Field): string =
yield &"proc set{field.name}*(message: {msg.names}, value: {field.fullType}) ="
- yield indent(&"message.{field.accessor} = value", 4)
+ if field.oneof == nil:
+ yield indent(&"message.{field.accessor} = value", 4)
+ else:
+ yield indent(&"if message.{field.oneof.name}.kind != {msg.names}_{field.oneof.name}_Kind.{field.name.capitalizeAscii}:", 4)
+ yield indent(&"reset(message.{field.oneof.name})", 8)
+ yield indent(&"message.{field.oneof.name}.kind = {msg.names}_{field.oneof.name}_Kind.{field.name.capitalizeAscii}", 8)
+ yield indent(&"message.{field.accessor} = value", 4)
yield indent(&"setField(message, {field.number})", 4)
var numbers: seq[int] = @[]
for sibling in oneofSiblings(field):