244 lines · python
1#!/usr/bin/env python32# ex: set filetype=python:3 4"""Generate code to handle XDR unions"""5 6from jinja2 import Environment7 8from generators import SourceGenerator9from generators import create_jinja2_environment, get_jinja2_template10 11from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid12from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis13 14 15def 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))20 21 22def emit_union_switch_spec_definition(23 environment: Environment, node: _XdrDeclaration24) -> None:25 """Emit a definition for an XDR union's discriminant"""26 assert isinstance(node, _XdrBasic)27 template = get_jinja2_template(environment, "definition", "switch_spec")28 print(29 template.render(30 name=node.name,31 type=node.spec.type_name,32 classifier=node.spec.c_classifier,33 )34 )35 36 37def emit_union_case_spec_definition(38 environment: Environment, node: _XdrDeclaration39) -> None:40 """Emit a definition for an XDR union's case arm"""41 if isinstance(node.arm, _XdrVoid):42 return43 assert isinstance(node.arm, _XdrBasic)44 template = get_jinja2_template(environment, "definition", "case_spec")45 print(46 template.render(47 name=node.arm.name,48 type=node.arm.spec.type_name,49 classifier=node.arm.spec.c_classifier,50 )51 )52 53 54def 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))58 59 emit_union_switch_spec_definition(environment, node.discriminant)60 61 for case in node.cases:62 emit_union_case_spec_definition(environment, case)63 64 if node.default is not None:65 emit_union_case_spec_definition(environment, node.default)66 67 template = get_jinja2_template(environment, "definition", "close")68 print(template.render(name=node.name))69 70 71def emit_union_switch_spec_decoder(72 environment: Environment, node: _XdrDeclaration73) -> None: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))78 79 80def emit_union_case_spec_decoder(environment: Environment, node: _XdrCaseSpec) -> None:81 """Emit decoder functions for an XDR union's case arm"""82 83 if isinstance(node.arm, _XdrVoid):84 return85 86 template = get_jinja2_template(environment, "decoder", "case_spec")87 for case in node.values:88 print(template.render(case=case))89 90 assert isinstance(node.arm, _XdrBasic)91 template = get_jinja2_template(environment, "decoder", node.arm.template)92 print(93 template.render(94 name=node.arm.name,95 type=node.arm.spec.type_name,96 classifier=node.arm.spec.c_classifier,97 )98 )99 100 template = get_jinja2_template(environment, "decoder", "break")101 print(template.render())102 103 104def emit_union_default_spec_decoder(environment: Environment, node: _XdrUnion) -> None:105 """Emit a decoder function for an XDR union's default arm"""106 default_case = node.default107 108 # Avoid a gcc warning about a default case with boolean discriminant109 if default_case is None and node.discriminant.spec.type_name == "bool":110 return111 112 template = get_jinja2_template(environment, "decoder", "default_spec")113 print(template.render())114 115 if default_case is None or isinstance(default_case.arm, _XdrVoid):116 template = get_jinja2_template(environment, "decoder", "break")117 print(template.render())118 return119 120 assert isinstance(default_case.arm, _XdrBasic)121 template = get_jinja2_template(environment, "decoder", default_case.arm.template)122 print(123 template.render(124 name=default_case.arm.name,125 type=default_case.arm.spec.type_name,126 classifier=default_case.arm.spec.c_classifier,127 )128 )129 130 131def emit_union_decoder(environment: Environment, node: _XdrUnion) -> None:132 """Emit one XDR union decoder"""133 template = get_jinja2_template(environment, "decoder", "open")134 print(template.render(name=node.name))135 136 emit_union_switch_spec_decoder(environment, node.discriminant)137 138 for case in node.cases:139 emit_union_case_spec_decoder(environment, case)140 141 emit_union_default_spec_decoder(environment, node)142 143 template = get_jinja2_template(environment, "decoder", "close")144 print(template.render())145 146 147def emit_union_switch_spec_encoder(148 environment: Environment, node: _XdrDeclaration149) -> None:150 """Emit an encoder for an XDR union's discriminant"""151 assert isinstance(node, _XdrBasic)152 template = get_jinja2_template(environment, "encoder", "switch_spec")153 print(template.render(name=node.name, type=node.spec.type_name))154 155 156def emit_union_case_spec_encoder(environment: Environment, node: _XdrCaseSpec) -> None:157 """Emit encoder functions for an XDR union's case arm"""158 159 if isinstance(node.arm, _XdrVoid):160 return161 162 template = get_jinja2_template(environment, "encoder", "case_spec")163 for case in node.values:164 print(template.render(case=case))165 166 assert isinstance(node.arm, _XdrBasic)167 template = get_jinja2_template(environment, "encoder", node.arm.template)168 print(169 template.render(170 name=node.arm.name,171 type=node.arm.spec.type_name,172 )173 )174 175 template = get_jinja2_template(environment, "encoder", "break")176 print(template.render())177 178 179def emit_union_default_spec_encoder(environment: Environment, node: _XdrUnion) -> None:180 """Emit an encoder function for an XDR union's default arm"""181 default_case = node.default182 183 # Avoid a gcc warning about a default case with boolean discriminant184 if default_case is None and node.discriminant.spec.type_name == "bool":185 return186 187 template = get_jinja2_template(environment, "encoder", "default_spec")188 print(template.render())189 190 if default_case is None or isinstance(default_case.arm, _XdrVoid):191 template = get_jinja2_template(environment, "encoder", "break")192 print(template.render())193 return194 195 assert isinstance(default_case.arm, _XdrBasic)196 template = get_jinja2_template(environment, "encoder", default_case.arm.template)197 print(198 template.render(199 name=default_case.arm.name,200 type=default_case.arm.spec.type_name,201 )202 )203 204 205def emit_union_encoder(environment, node: _XdrUnion) -> None:206 """Emit one XDR union encoder"""207 template = get_jinja2_template(environment, "encoder", "open")208 print(template.render(name=node.name))209 210 emit_union_switch_spec_encoder(environment, node.discriminant)211 212 for case in node.cases:213 emit_union_case_spec_encoder(environment, case)214 215 emit_union_default_spec_encoder(environment, node)216 217 template = get_jinja2_template(environment, "encoder", "close")218 print(template.render())219 220 221class XdrUnionGenerator(SourceGenerator):222 """Generate source code for XDR unions"""223 224 def __init__(self, language: str, peer: str):225 """Initialize an instance of this class"""226 self.environment = create_jinja2_environment(language, "union")227 self.peer = peer228 229 def emit_declaration(self, node: _XdrUnion) -> None:230 """Emit one declaration pair for an XDR union"""231 emit_union_declaration(self.environment, node)232 233 def emit_definition(self, node: _XdrUnion) -> None:234 """Emit one definition for an XDR union"""235 emit_union_definition(self.environment, node)236 237 def emit_decoder(self, node: _XdrUnion) -> None:238 """Emit one decoder function for an XDR union"""239 emit_union_decoder(self.environment, node)240 241 def emit_encoder(self, node: _XdrUnion) -> None:242 """Emit one encoder function for an XDR union"""243 emit_union_encoder(self.environment, node)244