Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,121 @@
# SPDX-License-Identifier: GPL-2.0
"""Define a base code generator class"""
from pathlib import Path
from jinja2 import Environment, FileSystemLoader, Template
from xdr_ast import _XdrAst, Specification, _RpcProgram, _XdrTypeSpecifier
from xdr_ast import public_apis, pass_by_reference, structs, get_header_name
from xdr_parse import get_xdr_annotate
def create_jinja2_environment(language: str, xdr_type: str) -> Environment:
"""Open a set of templates based on output language"""
match language:
case "C":
templates_dir = (
Path(__file__).parent.parent / "templates" / language / xdr_type
)
environment = Environment(
loader=FileSystemLoader(templates_dir),
trim_blocks=True,
lstrip_blocks=True,
)
environment.globals["annotate"] = get_xdr_annotate()
environment.globals["public_apis"] = public_apis
environment.globals["pass_by_reference"] = pass_by_reference
environment.globals["structs"] = structs
return environment
case _:
raise NotImplementedError("Language not supported")
def get_jinja2_template(
environment: Environment, template_type: str, template_name: str
) -> Template:
"""Retrieve a Jinja2 template for emitting source code"""
return environment.get_template(template_type + "/" + template_name + ".j2")
def find_xdr_program_name(root: Specification) -> str:
"""Retrieve the RPC program name from an abstract syntax tree"""
raw_name = get_header_name()
if raw_name != "none":
return raw_name.lower()
for definition in root.definitions:
if isinstance(definition.value, _RpcProgram):
raw_name = definition.value.name
return raw_name.lower().removesuffix("_program").removesuffix("_prog")
return "noprog"
def header_guard_infix(filename: str) -> str:
"""Extract the header guard infix from the specification filename"""
return Path(filename).stem.upper()
def kernel_c_type(spec: _XdrTypeSpecifier) -> str:
"""Return name of C type"""
builtin_native_c_type = {
"bool": "bool",
"short": "s16",
"unsigned_short": "u16",
"int": "s32",
"unsigned_int": "u32",
"long": "s32",
"unsigned_long": "u32",
"hyper": "s64",
"unsigned_hyper": "u64",
}
if spec.type_name in builtin_native_c_type:
return builtin_native_c_type[spec.type_name]
return spec.type_name
class Boilerplate:
"""Base class to generate boilerplate for source files"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
raise NotImplementedError("No language support defined")
def emit_declaration(self, filename: str, root: Specification) -> None:
"""Emit declaration header boilerplate"""
raise NotImplementedError("Header boilerplate generation not supported")
def emit_definition(self, filename: str, root: Specification) -> None:
"""Emit definition header boilerplate"""
raise NotImplementedError("Header boilerplate generation not supported")
def emit_source(self, filename: str, root: Specification) -> None:
"""Emit generic source code for this XDR type"""
raise NotImplementedError("Source boilerplate generation not supported")
class SourceGenerator:
"""Base class to generate header and source code for XDR types"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
raise NotImplementedError("No language support defined")
def emit_declaration(self, node: _XdrAst) -> None:
"""Emit one function declaration for this XDR type"""
raise NotImplementedError("Declaration generation not supported")
def emit_decoder(self, node: _XdrAst) -> None:
"""Emit one decoder function for this XDR type"""
raise NotImplementedError("Decoder generation not supported")
def emit_definition(self, node: _XdrAst) -> None:
"""Emit one definition for this XDR type"""
raise NotImplementedError("Definition generation not supported")
def emit_encoder(self, node: _XdrAst) -> None:
"""Emit one encoder function for this XDR type"""
raise NotImplementedError("Encoder generation not supported")
def emit_maxsize(self, node: _XdrAst) -> None:
"""Emit one maxsize macro for this XDR type"""
raise NotImplementedError("Maxsize macro generation not supported")
@@ -0,0 +1,20 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate code to handle XDR constants"""
from generators import SourceGenerator, create_jinja2_environment
from xdr_ast import _XdrConstant
class XdrConstantGenerator(SourceGenerator):
"""Generate source code for XDR constants"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "constants")
self.peer = peer
def emit_definition(self, node: _XdrConstant) -> None:
"""Emit one definition for a constant"""
template = self.environment.get_template("definition.j2")
print(template.render(name=node.name, value=node.value))
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate code to handle XDR enum types"""
from generators import SourceGenerator, create_jinja2_environment
from xdr_ast import _XdrEnum, public_apis, big_endian, get_header_name
from xdr_parse import get_xdr_enum_validation
class XdrEnumGenerator(SourceGenerator):
"""Generate source code for XDR enum types"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "enum")
self.peer = peer
def emit_declaration(self, node: _XdrEnum) -> None:
"""Emit one declaration pair for an XDR enum type"""
if node.name in public_apis:
template = self.environment.get_template("declaration/enum.j2")
print(template.render(name=node.name))
def emit_definition(self, node: _XdrEnum) -> None:
"""Emit one definition for an XDR enum type"""
template = self.environment.get_template("definition/open.j2")
print(template.render(name=node.name))
template = self.environment.get_template("definition/enumerator.j2")
for enumerator in node.enumerators:
print(template.render(name=enumerator.name, value=enumerator.value))
if node.name in big_endian:
template = self.environment.get_template("definition/close_be.j2")
else:
template = self.environment.get_template("definition/close.j2")
print(template.render(name=node.name))
def emit_decoder(self, node: _XdrEnum) -> None:
"""Emit one decoder function for an XDR enum type"""
if node.name in big_endian:
template = self.environment.get_template("decoder/enum_be.j2")
else:
template = self.environment.get_template("decoder/enum.j2")
print(
template.render(
name=node.name,
enumerators=node.enumerators,
validate=get_xdr_enum_validation(),
)
)
def emit_encoder(self, node: _XdrEnum) -> None:
"""Emit one encoder function for an XDR enum type"""
if node.name in big_endian:
template = self.environment.get_template("encoder/enum_be.j2")
else:
template = self.environment.get_template("encoder/enum.j2")
print(template.render(name=node.name))
def emit_maxsize(self, node: _XdrEnum) -> None:
"""Emit one maxsize macro for an XDR enum type"""
macro_name = get_header_name().upper() + "_" + node.name + "_sz"
template = self.environment.get_template("maxsize/enum.j2")
print(
template.render(
macro=macro_name,
width=" + ".join(node.symbolic_width()),
)
)
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate header bottom boilerplate"""
import os.path
import time
from generators import Boilerplate, header_guard_infix
from generators import create_jinja2_environment, get_jinja2_template
from xdr_ast import Specification
class XdrHeaderBottomGenerator(Boilerplate):
"""Generate header boilerplate"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "header_bottom")
self.peer = peer
def emit_declaration(self, filename: str, root: Specification) -> None:
"""Emit the bottom header guard"""
template = get_jinja2_template(self.environment, "declaration", "header")
print(template.render(infix=header_guard_infix(filename)))
def emit_definition(self, filename: str, root: Specification) -> None:
"""Emit the bottom header guard"""
template = get_jinja2_template(self.environment, "definition", "header")
print(template.render(infix=header_guard_infix(filename)))
def emit_source(self, filename: str, root: Specification) -> None:
pass
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate header top boilerplate"""
import os.path
import time
from generators import Boilerplate, header_guard_infix
from generators import create_jinja2_environment, get_jinja2_template
from xdr_ast import Specification
class XdrHeaderTopGenerator(Boilerplate):
"""Generate header boilerplate"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "header_top")
self.peer = peer
def emit_declaration(self, filename: str, root: Specification) -> None:
"""Emit the top header guard"""
template = get_jinja2_template(self.environment, "declaration", "header")
print(
template.render(
infix=header_guard_infix(filename),
filename=filename,
mtime=time.ctime(os.path.getmtime(filename)),
)
)
def emit_definition(self, filename: str, root: Specification) -> None:
"""Emit the top header guard"""
template = get_jinja2_template(self.environment, "definition", "header")
print(
template.render(
infix=header_guard_infix(filename),
filename=filename,
mtime=time.ctime(os.path.getmtime(filename)),
)
)
def emit_source(self, filename: str, root: Specification) -> None:
pass
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate code for XDR pass-through lines"""
from generators import SourceGenerator, create_jinja2_environment
from xdr_ast import _XdrPassthru
class XdrPassthruGenerator(SourceGenerator):
"""Generate source code for XDR pass-through content"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "passthru")
self.peer = peer
def emit_definition(self, node: _XdrPassthru) -> None:
"""Emit one pass-through line"""
template = self.environment.get_template("definition.j2")
print(template.render(content=node.content))
def emit_decoder(self, node: _XdrPassthru) -> None:
"""Emit one pass-through line"""
template = self.environment.get_template("source.j2")
print(template.render(content=node.content))
@@ -0,0 +1,288 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate code to handle XDR pointer types"""
from jinja2 import Environment
from generators import SourceGenerator, kernel_c_type
from generators import create_jinja2_environment, get_jinja2_template
from xdr_ast import _XdrBasic, _XdrString
from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque
from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray
from xdr_ast import _XdrOptionalData, _XdrPointer, _XdrDeclaration
from xdr_ast import public_apis, get_header_name
def emit_pointer_declaration(environment: Environment, node: _XdrPointer) -> None:
"""Emit a declaration pair for an XDR pointer type"""
if node.name in public_apis:
template = get_jinja2_template(environment, "declaration", "close")
print(template.render(name=node.name))
def emit_pointer_member_definition(
environment: Environment, field: _XdrDeclaration
) -> None:
"""Emit a definition for one field in an XDR struct"""
if isinstance(field, _XdrBasic):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
type=kernel_c_type(field.spec),
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "definition", field.template)
print(template.render(name=field.name))
elif isinstance(field, _XdrString):
template = get_jinja2_template(environment, "definition", field.template)
print(template.render(name=field.name))
elif isinstance(field, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
type=kernel_c_type(field.spec),
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
type=kernel_c_type(field.spec),
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrOptionalData):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
type=kernel_c_type(field.spec),
classifier=field.spec.c_classifier,
)
)
def emit_pointer_definition(environment: Environment, node: _XdrPointer) -> None:
"""Emit a definition for an XDR pointer type"""
template = get_jinja2_template(environment, "definition", "open")
print(template.render(name=node.name))
for field in node.fields[0:-1]:
emit_pointer_member_definition(environment, field)
template = get_jinja2_template(environment, "definition", "close")
print(template.render(name=node.name))
def emit_pointer_member_decoder(
environment: Environment, field: _XdrDeclaration
) -> None:
"""Emit a decoder for one field in an XDR pointer"""
if isinstance(field, _XdrBasic):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrString):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
size=field.size,
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
maxsize=field.maxsize,
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrOptionalData):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
classifier=field.spec.c_classifier,
)
)
def emit_pointer_decoder(environment: Environment, node: _XdrPointer) -> None:
"""Emit one decoder function for an XDR pointer type"""
template = get_jinja2_template(environment, "decoder", "open")
print(template.render(name=node.name))
for field in node.fields[0:-1]:
emit_pointer_member_decoder(environment, field)
template = get_jinja2_template(environment, "decoder", "close")
print(template.render())
def emit_pointer_member_encoder(
environment: Environment, field: _XdrDeclaration
) -> None:
"""Emit an encoder for one field in a XDR pointer"""
if isinstance(field, _XdrBasic):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
)
)
elif isinstance(field, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrString):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrOptionalData):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
classifier=field.spec.c_classifier,
)
)
def emit_pointer_encoder(environment: Environment, node: _XdrPointer) -> None:
"""Emit one encoder function for an XDR pointer type"""
template = get_jinja2_template(environment, "encoder", "open")
print(template.render(name=node.name))
for field in node.fields[0:-1]:
emit_pointer_member_encoder(environment, field)
template = get_jinja2_template(environment, "encoder", "close")
print(template.render())
def emit_pointer_maxsize(environment: Environment, node: _XdrPointer) -> None:
"""Emit one maxsize macro for an XDR pointer type"""
macro_name = get_header_name().upper() + "_" + node.name + "_sz"
template = get_jinja2_template(environment, "maxsize", "pointer")
print(
template.render(
macro=macro_name,
width=" + ".join(node.symbolic_width()),
)
)
class XdrPointerGenerator(SourceGenerator):
"""Generate source code for XDR pointer"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "pointer")
self.peer = peer
def emit_declaration(self, node: _XdrPointer) -> None:
"""Emit one declaration pair for an XDR pointer type"""
emit_pointer_declaration(self.environment, node)
def emit_definition(self, node: _XdrPointer) -> None:
"""Emit one declaration for an XDR pointer type"""
emit_pointer_definition(self.environment, node)
def emit_decoder(self, node: _XdrPointer) -> None:
"""Emit one decoder function for an XDR pointer type"""
emit_pointer_decoder(self.environment, node)
def emit_encoder(self, node: _XdrPointer) -> None:
"""Emit one encoder function for an XDR pointer type"""
emit_pointer_encoder(self.environment, node)
def emit_maxsize(self, node: _XdrPointer) -> None:
"""Emit one maxsize macro for an XDR pointer type"""
emit_pointer_maxsize(self.environment, node)
@@ -0,0 +1,204 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate code for an RPC program's procedures"""
from jinja2 import Environment
from generators import SourceGenerator, create_jinja2_environment, get_jinja2_template
from xdr_ast import _RpcProgram, _RpcVersion, excluded_apis
from xdr_ast import max_widths, get_header_name
def emit_version_definitions(
environment: Environment, program: str, version: _RpcVersion
) -> None:
"""Emit procedure numbers for each RPC version's procedures"""
template = environment.get_template("definition/open.j2")
print(template.render(program=program.upper()))
template = environment.get_template("definition/procedure.j2")
for procedure in version.procedures:
if procedure.name not in excluded_apis:
print(
template.render(
name=procedure.name,
value=procedure.number,
)
)
template = environment.get_template("definition/close.j2")
print(template.render())
def emit_version_declarations(
environment: Environment, program: str, version: _RpcVersion
) -> None:
"""Emit declarations for each RPC version's procedures"""
arguments = dict.fromkeys([])
for procedure in version.procedures:
if procedure.name not in excluded_apis:
arguments[procedure.argument.type_name] = None
if len(arguments) > 0:
print("")
template = environment.get_template("declaration/argument.j2")
for argument in arguments:
print(template.render(program=program, argument=argument))
results = dict.fromkeys([])
for procedure in version.procedures:
if procedure.name not in excluded_apis:
results[procedure.result.type_name] = None
if len(results) > 0:
print("")
template = environment.get_template("declaration/result.j2")
for result in results:
print(template.render(program=program, result=result))
def emit_version_argument_decoders(
environment: Environment, program: str, version: _RpcVersion
) -> None:
"""Emit server argument decoders for each RPC version's procedures"""
arguments = dict.fromkeys([])
for procedure in version.procedures:
if procedure.name not in excluded_apis:
arguments[procedure.argument.type_name] = None
template = environment.get_template("decoder/argument.j2")
for argument in arguments:
print(template.render(program=program, argument=argument))
def emit_version_result_decoders(
environment: Environment, program: str, version: _RpcVersion
) -> None:
"""Emit client result decoders for each RPC version's procedures"""
results = dict.fromkeys([])
for procedure in version.procedures:
if procedure.name not in excluded_apis:
results[procedure.result.type_name] = None
template = environment.get_template("decoder/result.j2")
for result in results:
print(template.render(program=program, result=result))
def emit_version_argument_encoders(
environment: Environment, program: str, version: _RpcVersion
) -> None:
"""Emit client argument encoders for each RPC version's procedures"""
arguments = dict.fromkeys([])
for procedure in version.procedures:
if procedure.name not in excluded_apis:
arguments[procedure.argument.type_name] = None
template = environment.get_template("encoder/argument.j2")
for argument in arguments:
print(template.render(program=program, argument=argument))
def emit_version_result_encoders(
environment: Environment, program: str, version: _RpcVersion
) -> None:
"""Emit server result encoders for each RPC version's procedures"""
results = dict.fromkeys([])
for procedure in version.procedures:
if procedure.name not in excluded_apis:
results[procedure.result.type_name] = None
template = environment.get_template("encoder/result.j2")
for result in results:
print(template.render(program=program, result=result))
class XdrProgramGenerator(SourceGenerator):
"""Generate source code for an RPC program's procedures"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "program")
self.peer = peer
def emit_definition(self, node: _RpcProgram) -> None:
"""Emit procedure numbers for each of an RPC programs's procedures"""
raw_name = node.name
program = raw_name.lower().removesuffix("_program").removesuffix("_prog")
for version in node.versions:
emit_version_definitions(self.environment, program, version)
template = self.environment.get_template("definition/program.j2")
print(template.render(name=raw_name, value=node.number))
def emit_declaration(self, node: _RpcProgram) -> None:
"""Emit a declaration pair for each of an RPC programs's procedures"""
raw_name = node.name
program = raw_name.lower().removesuffix("_program").removesuffix("_prog")
for version in node.versions:
emit_version_declarations(self.environment, program, version)
def emit_decoder(self, node: _RpcProgram) -> None:
"""Emit all decoder functions for an RPC program's procedures"""
raw_name = node.name
program = raw_name.lower().removesuffix("_program").removesuffix("_prog")
match self.peer:
case "server":
for version in node.versions:
emit_version_argument_decoders(
self.environment, program, version,
)
case "client":
for version in node.versions:
emit_version_result_decoders(
self.environment, program, version,
)
def emit_encoder(self, node: _RpcProgram) -> None:
"""Emit all encoder functions for an RPC program's procedures"""
raw_name = node.name
program = raw_name.lower().removesuffix("_program").removesuffix("_prog")
match self.peer:
case "server":
for version in node.versions:
emit_version_result_encoders(
self.environment, program, version,
)
case "client":
for version in node.versions:
emit_version_argument_encoders(
self.environment, program, version,
)
def emit_maxsize(self, node: _RpcProgram) -> None:
"""Emit maxsize macro for maximum RPC argument size"""
header = get_header_name().upper()
# Find the largest argument across all versions
max_arg_width = 0
max_arg_name = None
for version in node.versions:
for procedure in version.procedures:
if procedure.name in excluded_apis:
continue
arg_name = procedure.argument.type_name
if arg_name == "void":
continue
if arg_name not in max_widths:
continue
if max_widths[arg_name] > max_arg_width:
max_arg_width = max_widths[arg_name]
max_arg_name = arg_name
if max_arg_name is None:
return
macro_name = header + "_MAX_ARGS_SZ"
template = get_jinja2_template(self.environment, "maxsize", "max_args")
print(
template.render(
macro=macro_name,
width=header + "_" + max_arg_name + "_sz",
)
)
@@ -0,0 +1,32 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate source code boilerplate"""
import os.path
import time
from generators import Boilerplate
from generators import find_xdr_program_name, create_jinja2_environment
from xdr_ast import _RpcProgram, Specification, get_header_name
class XdrSourceTopGenerator(Boilerplate):
"""Generate source code boilerplate"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "source_top")
self.peer = peer
def emit_source(self, filename: str, root: Specification) -> None:
"""Emit the top source boilerplate"""
name = find_xdr_program_name(root)
template = self.environment.get_template(self.peer + ".j2")
print(
template.render(
program=name,
filename=filename,
mtime=time.ctime(os.path.getmtime(filename)),
)
)
@@ -0,0 +1,288 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate code to handle XDR struct types"""
from jinja2 import Environment
from generators import SourceGenerator, kernel_c_type
from generators import create_jinja2_environment, get_jinja2_template
from xdr_ast import _XdrBasic, _XdrString
from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque
from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray
from xdr_ast import _XdrOptionalData, _XdrStruct, _XdrDeclaration
from xdr_ast import public_apis, get_header_name
def emit_struct_declaration(environment: Environment, node: _XdrStruct) -> None:
"""Emit one declaration pair for an XDR struct type"""
if node.name in public_apis:
template = get_jinja2_template(environment, "declaration", "close")
print(template.render(name=node.name))
def emit_struct_member_definition(
environment: Environment, field: _XdrDeclaration
) -> None:
"""Emit a definition for one field in an XDR struct"""
if isinstance(field, _XdrBasic):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
type=kernel_c_type(field.spec),
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "definition", field.template)
print(template.render(name=field.name))
elif isinstance(field, _XdrString):
template = get_jinja2_template(environment, "definition", field.template)
print(template.render(name=field.name))
elif isinstance(field, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
type=kernel_c_type(field.spec),
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
type=kernel_c_type(field.spec),
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrOptionalData):
template = get_jinja2_template(environment, "definition", field.template)
print(
template.render(
name=field.name,
type=kernel_c_type(field.spec),
classifier=field.spec.c_classifier,
)
)
def emit_struct_definition(environment: Environment, node: _XdrStruct) -> None:
"""Emit one definition for an XDR struct type"""
template = get_jinja2_template(environment, "definition", "open")
print(template.render(name=node.name))
for field in node.fields:
emit_struct_member_definition(environment, field)
template = get_jinja2_template(environment, "definition", "close")
print(template.render(name=node.name))
def emit_struct_member_decoder(
environment: Environment, field: _XdrDeclaration
) -> None:
"""Emit a decoder for one field in an XDR struct"""
if isinstance(field, _XdrBasic):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrString):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
size=field.size,
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
maxsize=field.maxsize,
classifier=field.spec.c_classifier,
)
)
elif isinstance(field, _XdrOptionalData):
template = get_jinja2_template(environment, "decoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
classifier=field.spec.c_classifier,
)
)
def emit_struct_decoder(environment: Environment, node: _XdrStruct) -> None:
"""Emit one decoder function for an XDR struct type"""
template = get_jinja2_template(environment, "decoder", "open")
print(template.render(name=node.name))
for field in node.fields:
emit_struct_member_decoder(environment, field)
template = get_jinja2_template(environment, "decoder", "close")
print(template.render())
def emit_struct_member_encoder(
environment: Environment, field: _XdrDeclaration
) -> None:
"""Emit an encoder for one field in an XDR struct"""
if isinstance(field, _XdrBasic):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
)
)
elif isinstance(field, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrString):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
size=field.size,
)
)
elif isinstance(field, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
maxsize=field.maxsize,
)
)
elif isinstance(field, _XdrOptionalData):
template = get_jinja2_template(environment, "encoder", field.template)
print(
template.render(
name=field.name,
type=field.spec.type_name,
classifier=field.spec.c_classifier,
)
)
def emit_struct_encoder(environment: Environment, node: _XdrStruct) -> None:
"""Emit one encoder function for an XDR struct type"""
template = get_jinja2_template(environment, "encoder", "open")
print(template.render(name=node.name))
for field in node.fields:
emit_struct_member_encoder(environment, field)
template = get_jinja2_template(environment, "encoder", "close")
print(template.render())
def emit_struct_maxsize(environment: Environment, node: _XdrStruct) -> None:
"""Emit one maxsize macro for an XDR struct type"""
macro_name = get_header_name().upper() + "_" + node.name + "_sz"
template = get_jinja2_template(environment, "maxsize", "struct")
print(
template.render(
macro=macro_name,
width=" + ".join(node.symbolic_width()),
)
)
class XdrStructGenerator(SourceGenerator):
"""Generate source code for XDR structs"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "struct")
self.peer = peer
def emit_declaration(self, node: _XdrStruct) -> None:
"""Emit one declaration pair for an XDR struct type"""
emit_struct_declaration(self.environment, node)
def emit_definition(self, node: _XdrStruct) -> None:
"""Emit one definition for an XDR struct type"""
emit_struct_definition(self.environment, node)
def emit_decoder(self, node: _XdrStruct) -> None:
"""Emit one decoder function for an XDR struct type"""
emit_struct_decoder(self.environment, node)
def emit_encoder(self, node: _XdrStruct) -> None:
"""Emit one encoder function for an XDR struct type"""
emit_struct_encoder(self.environment, node)
def emit_maxsize(self, node: _XdrStruct) -> None:
"""Emit one maxsize macro for an XDR struct type"""
emit_struct_maxsize(self.environment, node)
@@ -0,0 +1,271 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate code to handle XDR typedefs"""
from jinja2 import Environment
from generators import SourceGenerator, kernel_c_type
from generators import create_jinja2_environment, get_jinja2_template
from xdr_ast import _XdrBasic, _XdrTypedef, _XdrString
from xdr_ast import _XdrFixedLengthOpaque, _XdrVariableLengthOpaque
from xdr_ast import _XdrFixedLengthArray, _XdrVariableLengthArray
from xdr_ast import _XdrOptionalData, _XdrVoid, _XdrDeclaration
from xdr_ast import public_apis, get_header_name
def emit_typedef_declaration(environment: Environment, node: _XdrDeclaration) -> None:
"""Emit a declaration pair for one XDR typedef"""
if node.name not in public_apis:
return
if isinstance(node, _XdrBasic):
template = get_jinja2_template(environment, "declaration", node.template)
print(
template.render(
name=node.name,
type=kernel_c_type(node.spec),
classifier=node.spec.c_classifier,
)
)
elif isinstance(node, _XdrString):
template = get_jinja2_template(environment, "declaration", node.template)
print(template.render(name=node.name))
elif isinstance(node, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "declaration", node.template)
print(template.render(name=node.name, size=node.size))
elif isinstance(node, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "declaration", node.template)
print(template.render(name=node.name))
elif isinstance(node, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "declaration", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
size=node.size,
)
)
elif isinstance(node, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "declaration", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
classifier=node.spec.c_classifier,
)
)
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
def emit_type_definition(environment: Environment, node: _XdrDeclaration) -> None:
"""Emit a definition for one XDR typedef"""
if isinstance(node, _XdrBasic):
template = get_jinja2_template(environment, "definition", node.template)
print(
template.render(
name=node.name,
type=kernel_c_type(node.spec),
classifier=node.spec.c_classifier,
)
)
elif isinstance(node, _XdrString):
template = get_jinja2_template(environment, "definition", node.template)
print(template.render(name=node.name))
elif isinstance(node, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "definition", node.template)
print(template.render(name=node.name, size=node.size))
elif isinstance(node, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "definition", node.template)
print(template.render(name=node.name))
elif isinstance(node, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "definition", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
size=node.size,
)
)
elif isinstance(node, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "definition", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
classifier=node.spec.c_classifier,
)
)
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
def emit_typedef_decoder(environment: Environment, node: _XdrDeclaration) -> None:
"""Emit a decoder function for one XDR typedef"""
if isinstance(node, _XdrBasic):
template = get_jinja2_template(environment, "decoder", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
)
)
elif isinstance(node, _XdrString):
template = get_jinja2_template(environment, "decoder", node.template)
print(
template.render(
name=node.name,
maxsize=node.maxsize,
)
)
elif isinstance(node, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "decoder", node.template)
print(
template.render(
name=node.name,
size=node.size,
)
)
elif isinstance(node, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "decoder", node.template)
print(
template.render(
name=node.name,
maxsize=node.maxsize,
)
)
elif isinstance(node, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "decoder", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
size=node.size,
classifier=node.spec.c_classifier,
)
)
elif isinstance(node, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "decoder", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
maxsize=node.maxsize,
)
)
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
def emit_typedef_encoder(environment: Environment, node: _XdrDeclaration) -> None:
"""Emit an encoder function for one XDR typedef"""
if isinstance(node, _XdrBasic):
template = get_jinja2_template(environment, "encoder", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
)
)
elif isinstance(node, _XdrString):
template = get_jinja2_template(environment, "encoder", node.template)
print(
template.render(
name=node.name,
maxsize=node.maxsize,
)
)
elif isinstance(node, _XdrFixedLengthOpaque):
template = get_jinja2_template(environment, "encoder", node.template)
print(
template.render(
name=node.name,
size=node.size,
)
)
elif isinstance(node, _XdrVariableLengthOpaque):
template = get_jinja2_template(environment, "encoder", node.template)
print(
template.render(
name=node.name,
maxsize=node.maxsize,
)
)
elif isinstance(node, _XdrFixedLengthArray):
template = get_jinja2_template(environment, "encoder", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
size=node.size,
)
)
elif isinstance(node, _XdrVariableLengthArray):
template = get_jinja2_template(environment, "encoder", node.template)
print(
template.render(
name=node.name,
type=node.spec.type_name,
maxsize=node.maxsize,
)
)
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
def emit_typedef_maxsize(environment: Environment, node: _XdrDeclaration) -> None:
"""Emit a maxsize macro for an XDR typedef"""
macro_name = get_header_name().upper() + "_" + node.name + "_sz"
template = get_jinja2_template(environment, "maxsize", node.template)
print(
template.render(
macro=macro_name,
width=" + ".join(node.symbolic_width()),
)
)
class XdrTypedefGenerator(SourceGenerator):
"""Generate source code for XDR typedefs"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "typedef")
self.peer = peer
def emit_declaration(self, node: _XdrTypedef) -> None:
"""Emit one declaration pair for an XDR enum type"""
emit_typedef_declaration(self.environment, node.declaration)
def emit_definition(self, node: _XdrTypedef) -> None:
"""Emit one definition for an XDR typedef"""
emit_type_definition(self.environment, node.declaration)
def emit_decoder(self, node: _XdrTypedef) -> None:
"""Emit one decoder function for an XDR typedef"""
emit_typedef_decoder(self.environment, node.declaration)
def emit_encoder(self, node: _XdrTypedef) -> None:
"""Emit one encoder function for an XDR typedef"""
emit_typedef_encoder(self.environment, node.declaration)
def emit_maxsize(self, node: _XdrTypedef) -> None:
"""Emit one maxsize macro for an XDR typedef"""
emit_typedef_maxsize(self.environment, node.declaration)
@@ -0,0 +1,366 @@
#!/usr/bin/env python3
# ex: set filetype=python:
"""Generate code to handle XDR unions"""
from jinja2 import Environment
from generators import SourceGenerator
from generators import create_jinja2_environment, get_jinja2_template
from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid, _XdrString, get_header_name
from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis, big_endian
def emit_union_declaration(environment: Environment, node: _XdrUnion) -> None:
"""Emit one declaration pair for an XDR union type"""
if node.name in public_apis:
template = get_jinja2_template(environment, "declaration", "close")
print(template.render(name=node.name))
def emit_union_switch_spec_definition(
environment: Environment, node: _XdrDeclaration
) -> None:
"""Emit a definition for an XDR union's discriminant"""
assert isinstance(node, _XdrBasic)
template = get_jinja2_template(environment, "definition", "switch_spec")
print(
template.render(
name=node.name,
type=node.spec.type_name,
classifier=node.spec.c_classifier,
)
)
def emit_union_case_spec_definition(
environment: Environment, node: _XdrDeclaration
) -> None:
"""Emit a definition for an XDR union's case arm"""
if isinstance(node.arm, _XdrVoid):
return
if isinstance(node.arm, _XdrString):
type_name = "char *"
classifier = ""
else:
type_name = node.arm.spec.type_name
classifier = node.arm.spec.c_classifier
assert isinstance(node.arm, (_XdrBasic, _XdrString))
template = get_jinja2_template(environment, "definition", "case_spec")
print(
template.render(
name=node.arm.name,
type=type_name,
classifier=classifier,
)
)
def emit_union_definition(environment: Environment, node: _XdrUnion) -> None:
"""Emit one XDR union definition"""
template = get_jinja2_template(environment, "definition", "open")
print(template.render(name=node.name))
emit_union_switch_spec_definition(environment, node.discriminant)
for case in node.cases:
emit_union_case_spec_definition(environment, case)
if node.default is not None:
emit_union_case_spec_definition(environment, node.default)
template = get_jinja2_template(environment, "definition", "close")
print(template.render(name=node.name))
def emit_union_switch_spec_decoder(
environment: Environment, node: _XdrDeclaration
) -> None:
"""Emit a decoder for an XDR union's discriminant"""
assert isinstance(node, _XdrBasic)
template = get_jinja2_template(environment, "decoder", "switch_spec")
print(template.render(name=node.name, type=node.spec.type_name))
def emit_union_arm_decoder(
environment: Environment, node: _XdrCaseSpec
) -> None:
"""Emit decoder for an XDR union's arm (data only, no case/break)"""
if isinstance(node.arm, _XdrVoid):
return
if isinstance(node.arm, _XdrString):
type_name = "char *"
classifier = ""
else:
type_name = node.arm.spec.type_name
classifier = node.arm.spec.c_classifier
assert isinstance(node.arm, (_XdrBasic, _XdrString))
template = get_jinja2_template(environment, "decoder", node.arm.template)
print(
template.render(
name=node.arm.name,
type=type_name,
classifier=classifier,
)
)
def emit_union_case_spec_decoder(
environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool
) -> None:
"""Emit decoder functions for an XDR union's case arm"""
if isinstance(node.arm, _XdrVoid):
return
if isinstance(node.arm, _XdrString):
type_name = "char *"
classifier = ""
else:
type_name = node.arm.spec.type_name
classifier = node.arm.spec.c_classifier
if big_endian_discriminant:
template = get_jinja2_template(environment, "decoder", "case_spec_be")
else:
template = get_jinja2_template(environment, "decoder", "case_spec")
for case in node.values:
print(template.render(case=case))
assert isinstance(node.arm, (_XdrBasic, _XdrString))
template = get_jinja2_template(environment, "decoder", node.arm.template)
print(
template.render(
name=node.arm.name,
type=type_name,
classifier=classifier,
)
)
template = get_jinja2_template(environment, "decoder", "break")
print(template.render())
def emit_union_default_spec_decoder(environment: Environment, node: _XdrUnion) -> None:
"""Emit a decoder function for an XDR union's default arm"""
default_case = node.default
# Avoid a gcc warning about a default case with boolean discriminant
if default_case is None and node.discriminant.spec.type_name == "bool":
return
template = get_jinja2_template(environment, "decoder", "default_spec")
print(template.render())
if default_case is None or isinstance(default_case.arm, _XdrVoid):
template = get_jinja2_template(environment, "decoder", "break")
print(template.render())
return
assert isinstance(default_case.arm, _XdrBasic)
template = get_jinja2_template(environment, "decoder", default_case.arm.template)
print(
template.render(
name=default_case.arm.name,
type=default_case.arm.spec.type_name,
classifier=default_case.arm.spec.c_classifier,
)
)
def emit_union_decoder(environment: Environment, node: _XdrUnion) -> None:
"""Emit one XDR union decoder"""
template = get_jinja2_template(environment, "decoder", "open")
print(template.render(name=node.name))
# For boolean discriminants, use if statement instead of switch
if node.discriminant.spec.type_name == "bool":
template = get_jinja2_template(environment, "decoder", "bool_spec")
print(template.render(name=node.discriminant.name, type=node.discriminant.spec.type_name))
# Find and emit the TRUE case
for case in node.cases:
if case.values and case.values[0] == "TRUE":
emit_union_arm_decoder(environment, case)
break
template = get_jinja2_template(environment, "decoder", "close")
print(template.render())
else:
emit_union_switch_spec_decoder(environment, node.discriminant)
for case in node.cases:
emit_union_case_spec_decoder(
environment,
case,
node.discriminant.spec.type_name in big_endian,
)
emit_union_default_spec_decoder(environment, node)
template = get_jinja2_template(environment, "decoder", "close")
print(template.render())
def emit_union_switch_spec_encoder(
environment: Environment, node: _XdrDeclaration
) -> None:
"""Emit an encoder for an XDR union's discriminant"""
assert isinstance(node, _XdrBasic)
template = get_jinja2_template(environment, "encoder", "switch_spec")
print(template.render(name=node.name, type=node.spec.type_name))
def emit_union_arm_encoder(
environment: Environment, node: _XdrCaseSpec
) -> None:
"""Emit encoder for an XDR union's arm (data only, no case/break)"""
if isinstance(node.arm, _XdrVoid):
return
if isinstance(node.arm, _XdrString):
type_name = "char *"
else:
type_name = node.arm.spec.type_name
assert isinstance(node.arm, (_XdrBasic, _XdrString))
template = get_jinja2_template(environment, "encoder", node.arm.template)
print(
template.render(
name=node.arm.name,
type=type_name,
)
)
def emit_union_case_spec_encoder(
environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool
) -> None:
"""Emit encoder functions for an XDR union's case arm"""
if isinstance(node.arm, _XdrVoid):
return
if isinstance(node.arm, _XdrString):
type_name = "char *"
else:
type_name = node.arm.spec.type_name
if big_endian_discriminant:
template = get_jinja2_template(environment, "encoder", "case_spec_be")
else:
template = get_jinja2_template(environment, "encoder", "case_spec")
for case in node.values:
print(template.render(case=case))
template = get_jinja2_template(environment, "encoder", node.arm.template)
print(
template.render(
name=node.arm.name,
type=type_name,
)
)
template = get_jinja2_template(environment, "encoder", "break")
print(template.render())
def emit_union_default_spec_encoder(environment: Environment, node: _XdrUnion) -> None:
"""Emit an encoder function for an XDR union's default arm"""
default_case = node.default
# Avoid a gcc warning about a default case with boolean discriminant
if default_case is None and node.discriminant.spec.type_name == "bool":
return
template = get_jinja2_template(environment, "encoder", "default_spec")
print(template.render())
if default_case is None or isinstance(default_case.arm, _XdrVoid):
template = get_jinja2_template(environment, "encoder", "break")
print(template.render())
return
template = get_jinja2_template(environment, "encoder", default_case.arm.template)
print(
template.render(
name=default_case.arm.name,
type=default_case.arm.spec.type_name,
)
)
def emit_union_encoder(environment, node: _XdrUnion) -> None:
"""Emit one XDR union encoder"""
template = get_jinja2_template(environment, "encoder", "open")
print(template.render(name=node.name))
# For boolean discriminants, use if statement instead of switch
if node.discriminant.spec.type_name == "bool":
template = get_jinja2_template(environment, "encoder", "bool_spec")
print(template.render(name=node.discriminant.name, type=node.discriminant.spec.type_name))
# Find and emit the TRUE case
for case in node.cases:
if case.values and case.values[0] == "TRUE":
emit_union_arm_encoder(environment, case)
break
template = get_jinja2_template(environment, "encoder", "close")
print(template.render())
else:
emit_union_switch_spec_encoder(environment, node.discriminant)
for case in node.cases:
emit_union_case_spec_encoder(
environment,
case,
node.discriminant.spec.type_name in big_endian,
)
emit_union_default_spec_encoder(environment, node)
template = get_jinja2_template(environment, "encoder", "close")
print(template.render())
def emit_union_maxsize(environment: Environment, node: _XdrUnion) -> None:
"""Emit one maxsize macro for an XDR union type"""
macro_name = get_header_name().upper() + "_" + node.name + "_sz"
template = get_jinja2_template(environment, "maxsize", "union")
print(
template.render(
macro=macro_name,
width=" + ".join(node.symbolic_width()),
)
)
class XdrUnionGenerator(SourceGenerator):
"""Generate source code for XDR unions"""
def __init__(self, language: str, peer: str):
"""Initialize an instance of this class"""
self.environment = create_jinja2_environment(language, "union")
self.peer = peer
def emit_declaration(self, node: _XdrUnion) -> None:
"""Emit one declaration pair for an XDR union"""
emit_union_declaration(self.environment, node)
def emit_definition(self, node: _XdrUnion) -> None:
"""Emit one definition for an XDR union"""
emit_union_definition(self.environment, node)
def emit_decoder(self, node: _XdrUnion) -> None:
"""Emit one decoder function for an XDR union"""
emit_union_decoder(self.environment, node)
def emit_encoder(self, node: _XdrUnion) -> None:
"""Emit one encoder function for an XDR union"""
emit_union_encoder(self.environment, node)
def emit_maxsize(self, node: _XdrUnion) -> None:
"""Emit one maxsize macro for an XDR union"""
emit_union_maxsize(self.environment, node)