1 #!/usr/bin/env python3 2 # ex: set filetype=python: 3 4 """Generate code to handle XDR unions""" 5 6 from jinja2 import Environment 7 8 from generators import SourceGenerator 9 from generators import create_jinja2_environment, get_jinja2_template 10 11 from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid 12 from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis 13 14 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)) 20 21 22 def emit_union_switch_spec_definition( 23 environment: Environment, node: _XdrDeclaration 24 ) -> 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 37 def emit_union_case_spec_definition( 38 environment: Environment, node: _XdrDeclaration 39 ) -> None: 40 """Emit a definition for an XDR union's case arm""" 41 if isinstance(node.arm, _XdrVoid): 42 return 43 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 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)) 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 71 def emit_union_switch_spec_decoder( 72 environment: Environment, node: _XdrDeclaration 73 ) -> 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 80 def 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 return 85 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 104 def 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.default 107 108 # Avoid a gcc warning about a default case with boolean discriminant 109 if default_case is None and node.discriminant.spec.type_name == "bool": 110 return 111 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 return 119 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 131 def 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 147 def emit_union_switch_spec_encoder( 148 environment: Environment, node: _XdrDeclaration 149 ) -> 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 156 def 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 return 161 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 179 def 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.default 182 183 # Avoid a gcc warning about a default case with boolean discriminant 184 if default_case is None and node.discriminant.spec.type_name == "bool": 185 return 186 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 return 194 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 205 def 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 221 class 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 = peer 228 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)
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.