aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2025-05-07 19:42:46 +0200
committerPřemysl Eric Janouch <p@janouch.name>2025-05-07 19:42:46 +0200
commitb69d3f8692b1d34f9b8616e046cdabe0d2fb67c0 (patch)
treebbbeb4fa30762d2f6b68f738c0d34691c1ba590a
parent9a26284a642252d678809bbbf299b8f31d81416e (diff)
downloadliberty-b69d3f8692b1d34f9b8616e046cdabe0d2fb67c0.tar.gz
liberty-b69d3f8692b1d34f9b8616e046cdabe0d2fb67c0.tar.xz
liberty-b69d3f8692b1d34f9b8616e046cdabe0d2fb67c0.zip
LibertyXDR: add support for default in unions
-rw-r--r--libertyxdr.adoc6
-rw-r--r--tests/lxdrgen.lxdr2
-rw-r--r--tools/lxdrgen.awk29
3 files changed, 30 insertions, 7 deletions
diff --git a/libertyxdr.adoc b/libertyxdr.adoc
index d3255ed..0002184 100644
--- a/libertyxdr.adoc
+++ b/libertyxdr.adoc
@@ -93,10 +93,12 @@ and always-present field, which must be a tag *enum*:
case CAR: void;
case LORRY: i8 axles;
case PLANE: i8 engines;
+ default: void;
};
-All possible enumeration values must be named, and there is no *case*
-fall-through.
+There is no *case* fall-through.
+Unless *default* is present, only the listed enumeration values are valid.
+Any *default* must currently be empty.
Framing
-------
diff --git a/tests/lxdrgen.lxdr b/tests/lxdrgen.lxdr
index d332336..8bfa8f7 100644
--- a/tests/lxdrgen.lxdr
+++ b/tests/lxdrgen.lxdr
@@ -25,5 +25,7 @@ struct Struct {
union Onion switch (Enum tag) {
case NOTHING:
void;
+ default:
+ void;
} o;
};
diff --git a/tools/lxdrgen.awk b/tools/lxdrgen.awk
index 5a51d2d..b3bb696 100644
--- a/tools/lxdrgen.awk
+++ b/tools/lxdrgen.awk
@@ -1,6 +1,6 @@
# lxdrgen.awk: an XDR-derived code generator for network protocols.
#
-# Copyright (c) 2022 - 2023, Přemysl Eric Janouch <p@janouch.name>
+# Copyright (c) 2022 - 2025, Přemysl Eric Janouch <p@janouch.name>
# SPDX-License-Identifier: 0BSD
#
# Usage: env LC_ALL=C awk -f lxdrgen.awk -f lxdrgen-{c,go,mjs}.awk \
@@ -218,7 +218,7 @@ function defstruct( name, d, cg) {
}
function defunion( name, tag, tagtype, tagvalue, cg, scg, d, a, i,
- unseen, exhaustive) {
+ unseen, defaulted, exhaustive) {
delete cg[0]
delete scg[0]
delete d[0]
@@ -249,9 +249,22 @@ function defunion( name, tag, tagtype, tagvalue, cg, scg, d, a, i,
if (!unseen[tagvalue]--)
fatal("no such value or duplicate case: " tagtype "." tagvalue)
codegen_struct_tag(tag, scg)
+ } else if (accept("default")) {
+ if (tagvalue)
+ codegen_union_struct(name, tagvalue, cg, scg)
+
+ expect(accept(":"))
+ if (defaulted)
+ fatal("duplicate default")
+
+ tagvalue = ""
+ defaulted = 1
} else if (tagvalue) {
if (readfield(d))
codegen_struct_field(d, scg)
+ } else if (defaulted) {
+ if (readfield(d))
+ fatal("default must not contain fields")
} else {
fatal("union fields must fall under a case")
}
@@ -259,11 +272,17 @@ function defunion( name, tag, tagtype, tagvalue, cg, scg, d, a, i,
if (tagvalue)
codegen_union_struct(name, tagvalue, cg, scg)
- # Unseen cases are simply not recognized/allowed.
+ # Unseen cases are only recognized/allowed when default is present.
exhaustive = 1
for (i in unseen)
- if (i && unseen[i])
- exhaustive = 0
+ if (i && unseen[i]) {
+ if (defaulted) {
+ codegen_struct_tag(tag, scg)
+ codegen_union_struct(name, i, cg, scg)
+ } else {
+ exhaustive = 0
+ }
+ }
Types[name] = "union"
codegen_union(name, cg, exhaustive)