1#!/usr/bin/env python3 2# ex: set filetype=python: 3 4"""Generate code to handle XDR pointer types""" 5 6from jinja2 import Environment 7 8from generators import SourceGenerator, kernel_c_type 9from generators import create_jinja2_environment, get_jinja2_template 10 11from xdr_ast import _XdrBasic, _XdrString 12from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque 13from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray 14from xdr_ast import _XdrOptionalData, _XdrPointer, _XdrDeclaration 15from xdr_ast import public_apis, get_header_name 16from xdr_ast import pages_members, pages_member_maxsize, pages_member_is_decoded 17 18 19def emit_pointer_declaration(environment: Environment, node: _XdrPointer) -> None: 20 """Emit a declaration pair for an XDR pointer type""" 21 if node.name in public_apis: 22 template = get_jinja2_template(environment, "declaration", "close") 23 print(template.render(name=node.name)) 24 25 26def emit_pointer_member_definition( 27 environment: Environment, field: _XdrDeclaration, struct_name: str, peer: str 28) -> None: 29 """Emit a definition for one field in an XDR struct""" 30 if peer == "server" and pages_member_is_decoded(struct_name, field.name): 31 template = get_jinja2_template(environment, "definition", "pages_opaque") 32 print(template.render(name=field.name)) 33 return 34 if isinstance(field, _XdrBasic): 35 template = get_jinja2_template(environment, "definition", field.template) 36 print( 37 template.render( 38 name=field.name, 39 type=kernel_c_type(field.spec), 40 classifier=field.spec.c_classifier, 41 ) 42 ) 43 elif isinstance(field, _XdrFixedLengthOpaque): 44 template = get_jinja2_template(environment, "definition", field.template) 45 print( 46 template.render( 47 name=field.name, 48 size=field.size, 49 ) 50 ) 51 elif isinstance(field, _XdrVariableLengthOpaque): 52 template = get_jinja2_template(environment, "definition", field.template) 53 print(template.render(name=field.name)) 54 elif isinstance(field, _XdrString): 55 template = get_jinja2_template(environment, "definition", field.template) 56 print(template.render(name=field.name)) 57 elif isinstance(field, _XdrFixedLengthArray): 58 template = get_jinja2_template(environment, "definition", field.template) 59 print( 60 template.render( 61 name=field.name, 62 type=kernel_c_type(field.spec), 63 size=field.size, 64 ) 65 ) 66 elif isinstance(field, _XdrVariableLengthArray): 67 template = get_jinja2_template(environment, "definition", field.template) 68 print( 69 template.render( 70 name=field.name, 71 type=kernel_c_type(field.spec), 72 classifier=field.spec.c_classifier, 73 ) 74 ) 75 elif isinstance(field, _XdrOptionalData): 76 template = get_jinja2_template(environment, "definition", field.template) 77 print( 78 template.render( 79 name=field.name, 80 type=kernel_c_type(field.spec), 81 classifier=field.spec.c_classifier, 82 ) 83 ) 84 85 86def emit_pointer_definition( 87 environment: Environment, node: _XdrPointer, peer: str 88) -> None: 89 """Emit a definition for an XDR pointer type""" 90 template = get_jinja2_template(environment, "definition", "open") 91 print(template.render(name=node.name)) 92 93 for field in node.fields[0:-1]: 94 emit_pointer_member_definition(environment, field, node.name, peer) 95 96 template = get_jinja2_template(environment, "definition", "close") 97 print(template.render(name=node.name)) 98 99 100def emit_pointer_member_decoder( 101 environment: Environment, 102 field: _XdrDeclaration, 103 struct_name: str, 104 peer: str, 105) -> None: 106 """Emit a decoder for one field in an XDR pointer""" 107 if peer == "server" and pages_member_is_decoded(struct_name, field.name): 108 template = get_jinja2_template(environment, "decoder", "pages_opaque") 109 print( 110 template.render( 111 name=field.name, 112 maxsize=pages_member_maxsize(field), 113 ) 114 ) 115 return 116 if isinstance(field, _XdrBasic): 117 template = get_jinja2_template(environment, "decoder", field.template) 118 print( 119 template.render( 120 name=field.name, 121 type=field.spec.type_name, 122 classifier=field.spec.c_classifier, 123 ) 124 ) 125 elif isinstance(field, _XdrFixedLengthOpaque): 126 template = get_jinja2_template(environment, "decoder", field.template) 127 print( 128 template.render( 129 name=field.name, 130 size=field.size, 131 ) 132 ) 133 elif isinstance(field, _XdrVariableLengthOpaque): 134 template = get_jinja2_template(environment, "decoder", field.template) 135 print( 136 template.render( 137 name=field.name, 138 maxsize=field.maxsize, 139 ) 140 ) 141 elif isinstance(field, _XdrString): 142 template = get_jinja2_template(environment, "decoder", field.template) 143 print( 144 template.render( 145 name=field.name, 146 maxsize=field.maxsize, 147 ) 148 ) 149 elif isinstance(field, _XdrFixedLengthArray): 150 template = get_jinja2_template(environment, "decoder", field.template) 151 print( 152 template.render( 153 name=field.name, 154 type=field.spec.type_name, 155 size=field.size, 156 classifier=field.spec.c_classifier, 157 ) 158 ) 159 elif isinstance(field, _XdrVariableLengthArray): 160 template = get_jinja2_template(environment, "decoder", field.template) 161 print( 162 template.render( 163 name=field.name, 164 type=field.spec.type_name, 165 maxsize=field.maxsize, 166 classifier=field.spec.c_classifier, 167 ) 168 ) 169 elif isinstance(field, _XdrOptionalData): 170 template = get_jinja2_template(environment, "decoder", field.template) 171 print( 172 template.render( 173 name=field.name, 174 type=field.spec.type_name, 175 classifier=field.spec.c_classifier, 176 ) 177 ) 178 179 180def emit_pointer_decoder( 181 environment: Environment, node: _XdrPointer, peer: str 182) -> None: 183 """Emit one decoder function for an XDR pointer type""" 184 template = get_jinja2_template(environment, "decoder", "open") 185 print(template.render(name=node.name)) 186 187 for field in node.fields[0:-1]: 188 emit_pointer_member_decoder(environment, field, node.name, peer) 189 190 template = get_jinja2_template(environment, "decoder", "close") 191 print(template.render()) 192 193 194def emit_pointer_member_encoder( 195 environment: Environment, 196 field: _XdrDeclaration, 197 struct_name: str, 198 peer: str, 199) -> None: 200 """Emit an encoder for one field in a XDR pointer""" 201 if (struct_name, field.name) in pages_members: 202 if peer != "server": 203 raise NotImplementedError( 204 "pragma pages is server-side only; " 205 + peer 206 + " generation is not yet supported" 207 ) 208 # Both representations carry the length field, which is all the 209 # pages encoder reads, so pages_member_is_decoded() does not 210 # gate this site. 211 template = get_jinja2_template(environment, "encoder", "pages_opaque") 212 print( 213 template.render( 214 name=field.name, 215 maxsize=pages_member_maxsize(field), 216 ) 217 ) 218 return 219 if isinstance(field, _XdrBasic): 220 template = get_jinja2_template(environment, "encoder", field.template) 221 print( 222 template.render( 223 name=field.name, 224 type=field.spec.type_name, 225 ) 226 ) 227 elif isinstance(field, _XdrFixedLengthOpaque): 228 template = get_jinja2_template(environment, "encoder", field.template) 229 print( 230 template.render( 231 name=field.name, 232 size=field.size, 233 ) 234 ) 235 elif isinstance(field, _XdrVariableLengthOpaque): 236 template = get_jinja2_template(environment, "encoder", field.template) 237 print( 238 template.render( 239 name=field.name, 240 maxsize=field.maxsize, 241 ) 242 ) 243 elif isinstance(field, _XdrString): 244 template = get_jinja2_template(environment, "encoder", field.template) 245 print( 246 template.render( 247 name=field.name, 248 maxsize=field.maxsize, 249 ) 250 ) 251 elif isinstance(field, _XdrFixedLengthArray): 252 template = get_jinja2_template(environment, "encoder", field.template) 253 print( 254 template.render( 255 name=field.name, 256 type=field.spec.type_name, 257 size=field.size, 258 ) 259 ) 260 elif isinstance(field, _XdrVariableLengthArray): 261 template = get_jinja2_template(environment, "encoder", field.template) 262 print( 263 template.render( 264 name=field.name, 265 type=field.spec.type_name, 266 maxsize=field.maxsize, 267 ) 268 ) 269 elif isinstance(field, _XdrOptionalData): 270 template = get_jinja2_template(environment, "encoder", field.template) 271 print( 272 template.render( 273 name=field.name, 274 type=field.spec.type_name, 275 classifier=field.spec.c_classifier, 276 ) 277 ) 278 279 280def emit_pointer_encoder( 281 environment: Environment, node: _XdrPointer, peer: str 282) -> None: 283 """Emit one encoder function for an XDR pointer type""" 284 template = get_jinja2_template(environment, "encoder", "open") 285 print(template.render(name=node.name)) 286 287 for field in node.fields[0:-1]: 288 emit_pointer_member_encoder(environment, field, node.name, peer) 289 290 template = get_jinja2_template(environment, "encoder", "close") 291 print(template.render()) 292 293 294def emit_pointer_maxsize(environment: Environment, node: _XdrPointer) -> None: 295 """Emit one maxsize macro for an XDR pointer type""" 296 macro_name = get_header_name().upper() + "_" + node.name + "_sz" 297 template = get_jinja2_template(environment, "maxsize", "pointer") 298 print( 299 template.render( 300 macro=macro_name, 301 width=" + ".join(node.symbolic_width()), 302 ) 303 ) 304 305 306class XdrPointerGenerator(SourceGenerator): 307 """Generate source code for XDR pointer""" 308 309 def __init__(self, language: str, peer: str): 310 """Initialize an instance of this class""" 311 self.environment = create_jinja2_environment(language, "pointer") 312 self.peer = peer 313 314 def emit_declaration(self, node: _XdrPointer) -> None: 315 """Emit one declaration pair for an XDR pointer type""" 316 emit_pointer_declaration(self.environment, node) 317 318 def emit_definition(self, node: _XdrPointer) -> None: 319 """Emit one declaration for an XDR pointer type""" 320 emit_pointer_definition(self.environment, node, self.peer) 321 322 def emit_decoder(self, node: _XdrPointer) -> None: 323 """Emit one decoder function for an XDR pointer type""" 324 emit_pointer_decoder(self.environment, node, self.peer) 325 326 def emit_encoder(self, node: _XdrPointer) -> None: 327 """Emit one encoder function for an XDR pointer type""" 328 emit_pointer_encoder(self.environment, node, self.peer) 329 330 def emit_maxsize(self, node: _XdrPointer) -> None: 331 """Emit one maxsize macro for an XDR pointer type""" 332 emit_pointer_maxsize(self.environment, node) 333