2 # ex: set filetype=python:
4 """Generate code to handle XDR unions"""
6 from jinja2
import Environment
8 from generators
import SourceGenerator
9 from generators
import create_jinja2_environment
, get_jinja2_template
11 from xdr_ast
import _XdrBasic
, _XdrUnion
, _XdrVoid
, get_header_name
12 from xdr_ast
import _XdrDeclaration
, _XdrCaseSpec
, public_apis
, big_endian
15 def emit_union_declaration(environment
: Environment
, node
: _XdrUnion
) -> None:
16 """Emit one declaration pair for an XDR union type"""
17 if node
.name
in public_apis
:
18 template
= get_jinja2_template(environment
, "declaration", "close")
19 print(template
.render(name
=node
.name
))
22 def emit_union_switch_spec_definition(
23 environment
: Environment
, node
: _XdrDeclaration
25 """Emit a definition for an XDR union's discriminant"""
26 assert isinstance(node
, _XdrBasic
)
27 template
= get_jinja2_template(environment
, "definition", "switch_spec")
31 type=node
.spec
.type_name
,
32 classifier
=node
.spec
.c_classifier
,
37 def emit_union_case_spec_definition(
38 environment
: Environment
, node
: _XdrDeclaration
40 """Emit a definition for an XDR union's case arm"""
41 if isinstance(node
.arm
, _XdrVoid
):
43 assert isinstance(node
.arm
, _XdrBasic
)
44 template
= get_jinja2_template(environment
, "definition", "case_spec")
48 type=node
.arm
.spec
.type_name
,
49 classifier
=node
.arm
.spec
.c_classifier
,
54 def emit_union_definition(environment
: Environment
, node
: _XdrUnion
) -> None:
55 """Emit one XDR union definition"""
56 template
= get_jinja2_template(environment
, "definition", "open")
57 print(template
.render(name
=node
.name
))
59 emit_union_switch_spec_definition(environment
, node
.discriminant
)
61 for case
in node
.cases
:
62 emit_union_case_spec_definition(environment
, case
)
64 if node
.default
is not None:
65 emit_union_case_spec_definition(environment
, node
.default
)
67 template
= get_jinja2_template(environment
, "definition", "close")
68 print(template
.render(name
=node
.name
))
71 def emit_union_switch_spec_decoder(
72 environment
: Environment
, node
: _XdrDeclaration
74 """Emit a decoder for an XDR union's discriminant"""
75 assert isinstance(node
, _XdrBasic
)
76 template
= get_jinja2_template(environment
, "decoder", "switch_spec")
77 print(template
.render(name
=node
.name
, type=node
.spec
.type_name
))
80 def emit_union_case_spec_decoder(
81 environment
: Environment
, node
: _XdrCaseSpec
, big_endian_discriminant
: bool
83 """Emit decoder functions for an XDR union's case arm"""
85 if isinstance(node
.arm
, _XdrVoid
):
88 if big_endian_discriminant
:
89 template
= get_jinja2_template(environment
, "decoder", "case_spec_be")
91 template
= get_jinja2_template(environment
, "decoder", "case_spec")
92 for case
in node
.values
:
93 print(template
.render(case
=case
))
95 assert isinstance(node
.arm
, _XdrBasic
)
96 template
= get_jinja2_template(environment
, "decoder", node
.arm
.template
)
100 type=node
.arm
.spec
.type_name
,
101 classifier
=node
.arm
.spec
.c_classifier
,
105 template
= get_jinja2_template(environment
, "decoder", "break")
106 print(template
.render())
109 def emit_union_default_spec_decoder(environment
: Environment
, node
: _XdrUnion
) -> None:
110 """Emit a decoder function for an XDR union's default arm"""
111 default_case
= node
.default
113 # Avoid a gcc warning about a default case with boolean discriminant
114 if default_case
is None and node
.discriminant
.spec
.type_name
== "bool":
117 template
= get_jinja2_template(environment
, "decoder", "default_spec")
118 print(template
.render())
120 if default_case
is None or isinstance(default_case
.arm
, _XdrVoid
):
121 template
= get_jinja2_template(environment
, "decoder", "break")
122 print(template
.render())
125 assert isinstance(default_case
.arm
, _XdrBasic
)
126 template
= get_jinja2_template(environment
, "decoder", default_case
.arm
.template
)
129 name
=default_case
.arm
.name
,
130 type=default_case
.arm
.spec
.type_name
,
131 classifier
=default_case
.arm
.spec
.c_classifier
,
136 def emit_union_decoder(environment
: Environment
, node
: _XdrUnion
) -> None:
137 """Emit one XDR union decoder"""
138 template
= get_jinja2_template(environment
, "decoder", "open")
139 print(template
.render(name
=node
.name
))
141 emit_union_switch_spec_decoder(environment
, node
.discriminant
)
143 for case
in node
.cases
:
144 emit_union_case_spec_decoder(
147 node
.discriminant
.spec
.type_name
in big_endian
,
150 emit_union_default_spec_decoder(environment
, node
)
152 template
= get_jinja2_template(environment
, "decoder", "close")
153 print(template
.render())
156 def emit_union_switch_spec_encoder(
157 environment
: Environment
, node
: _XdrDeclaration
159 """Emit an encoder for an XDR union's discriminant"""
160 assert isinstance(node
, _XdrBasic
)
161 template
= get_jinja2_template(environment
, "encoder", "switch_spec")
162 print(template
.render(name
=node
.name
, type=node
.spec
.type_name
))
165 def emit_union_case_spec_encoder(
166 environment
: Environment
, node
: _XdrCaseSpec
, big_endian_discriminant
: bool
168 """Emit encoder functions for an XDR union's case arm"""
170 if isinstance(node
.arm
, _XdrVoid
):
173 if big_endian_discriminant
:
174 template
= get_jinja2_template(environment
, "encoder", "case_spec_be")
176 template
= get_jinja2_template(environment
, "encoder", "case_spec")
177 for case
in node
.values
:
178 print(template
.render(case
=case
))
180 template
= get_jinja2_template(environment
, "encoder", node
.arm
.template
)
184 type=node
.arm
.spec
.type_name
,
188 template
= get_jinja2_template(environment
, "encoder", "break")
189 print(template
.render())
192 def emit_union_default_spec_encoder(environment
: Environment
, node
: _XdrUnion
) -> None:
193 """Emit an encoder function for an XDR union's default arm"""
194 default_case
= node
.default
196 # Avoid a gcc warning about a default case with boolean discriminant
197 if default_case
is None and node
.discriminant
.spec
.type_name
== "bool":
200 template
= get_jinja2_template(environment
, "encoder", "default_spec")
201 print(template
.render())
203 if default_case
is None or isinstance(default_case
.arm
, _XdrVoid
):
204 template
= get_jinja2_template(environment
, "encoder", "break")
205 print(template
.render())
208 template
= get_jinja2_template(environment
, "encoder", default_case
.arm
.template
)
211 name
=default_case
.arm
.name
,
212 type=default_case
.arm
.spec
.type_name
,
217 def emit_union_encoder(environment
, node
: _XdrUnion
) -> None:
218 """Emit one XDR union encoder"""
219 template
= get_jinja2_template(environment
, "encoder", "open")
220 print(template
.render(name
=node
.name
))
222 emit_union_switch_spec_encoder(environment
, node
.discriminant
)
224 for case
in node
.cases
:
225 emit_union_case_spec_encoder(
228 node
.discriminant
.spec
.type_name
in big_endian
,
231 emit_union_default_spec_encoder(environment
, node
)
233 template
= get_jinja2_template(environment
, "encoder", "close")
234 print(template
.render())
237 def emit_union_maxsize(environment
: Environment
, node
: _XdrUnion
) -> None:
238 """Emit one maxsize macro for an XDR union type"""
239 macro_name
= get_header_name().upper() + "_" + node
.name
+ "_sz"
240 template
= get_jinja2_template(environment
, "maxsize", "union")
244 width
=" + ".join(node
.symbolic_width()),
249 class XdrUnionGenerator(SourceGenerator
):
250 """Generate source code for XDR unions"""
252 def __init__(self
, language
: str, peer
: str):
253 """Initialize an instance of this class"""
254 self
.environment
= create_jinja2_environment(language
, "union")
257 def emit_declaration(self
, node
: _XdrUnion
) -> None:
258 """Emit one declaration pair for an XDR union"""
259 emit_union_declaration(self
.environment
, node
)
261 def emit_definition(self
, node
: _XdrUnion
) -> None:
262 """Emit one definition for an XDR union"""
263 emit_union_definition(self
.environment
, node
)
265 def emit_decoder(self
, node
: _XdrUnion
) -> None:
266 """Emit one decoder function for an XDR union"""
267 emit_union_decoder(self
.environment
, node
)
269 def emit_encoder(self
, node
: _XdrUnion
) -> None:
270 """Emit one encoder function for an XDR union"""
271 emit_union_encoder(self
.environment
, node
)
273 def emit_maxsize(self
, node
: _XdrUnion
) -> None:
274 """Emit one maxsize macro for an XDR union"""
275 emit_union_maxsize(self
.environment
, node
)