summaryrefslogtreecommitdiff
path: root/tools/net/sunrpc/xdrgen/generators
diff options
context:
space:
mode:
Diffstat (limited to 'tools/net/sunrpc/xdrgen/generators')
-rw-r--r--tools/net/sunrpc/xdrgen/generators/__init__.py16
-rw-r--r--tools/net/sunrpc/xdrgen/generators/enum.py9
-rw-r--r--tools/net/sunrpc/xdrgen/generators/passthru.py26
-rw-r--r--tools/net/sunrpc/xdrgen/generators/program.py38
-rw-r--r--tools/net/sunrpc/xdrgen/generators/typedef.py8
-rw-r--r--tools/net/sunrpc/xdrgen/generators/union.py149
6 files changed, 205 insertions, 41 deletions
diff --git a/tools/net/sunrpc/xdrgen/generators/__init__.py b/tools/net/sunrpc/xdrgen/generators/__init__.py
index b98574a36a4a..5c3a4a47ded8 100644
--- a/tools/net/sunrpc/xdrgen/generators/__init__.py
+++ b/tools/net/sunrpc/xdrgen/generators/__init__.py
@@ -2,11 +2,11 @@
"""Define a base code generator class"""
-import sys
+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, get_header_name
+from xdr_ast import public_apis, pass_by_reference, structs, get_header_name
from xdr_parse import get_xdr_annotate
@@ -14,14 +14,18 @@ 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(sys.path[0] + "/templates/C/" + xdr_type + "/"),
+ 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")
@@ -48,15 +52,15 @@ def find_xdr_program_name(root: Specification) -> str:
def header_guard_infix(filename: str) -> str:
"""Extract the header guard infix from the specification filename"""
- basename = filename.split("/")[-1]
- program = basename.replace(".x", "")
- return program.upper()
+ 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",
diff --git a/tools/net/sunrpc/xdrgen/generators/enum.py b/tools/net/sunrpc/xdrgen/generators/enum.py
index e62f715d3996..b4ed3ed6431e 100644
--- a/tools/net/sunrpc/xdrgen/generators/enum.py
+++ b/tools/net/sunrpc/xdrgen/generators/enum.py
@@ -5,6 +5,7 @@
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):
@@ -42,7 +43,13 @@ class XdrEnumGenerator(SourceGenerator):
template = self.environment.get_template("decoder/enum_be.j2")
else:
template = self.environment.get_template("decoder/enum.j2")
- print(template.render(name=node.name))
+ 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"""
diff --git a/tools/net/sunrpc/xdrgen/generators/passthru.py b/tools/net/sunrpc/xdrgen/generators/passthru.py
new file mode 100644
index 000000000000..cb17bd977f1e
--- /dev/null
+++ b/tools/net/sunrpc/xdrgen/generators/passthru.py
@@ -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))
diff --git a/tools/net/sunrpc/xdrgen/generators/program.py b/tools/net/sunrpc/xdrgen/generators/program.py
index ac3cf1694b68..c0cb3f6d3319 100644
--- a/tools/net/sunrpc/xdrgen/generators/program.py
+++ b/tools/net/sunrpc/xdrgen/generators/program.py
@@ -5,8 +5,9 @@
from jinja2 import Environment
-from generators import SourceGenerator, create_jinja2_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(
@@ -127,6 +128,9 @@ class XdrProgramGenerator(SourceGenerator):
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
@@ -166,3 +170,35 @@ class XdrProgramGenerator(SourceGenerator):
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",
+ )
+ )
diff --git a/tools/net/sunrpc/xdrgen/generators/typedef.py b/tools/net/sunrpc/xdrgen/generators/typedef.py
index fab72e9d6915..75e3a40e14e1 100644
--- a/tools/net/sunrpc/xdrgen/generators/typedef.py
+++ b/tools/net/sunrpc/xdrgen/generators/typedef.py
@@ -58,7 +58,7 @@ def emit_typedef_declaration(environment: Environment, node: _XdrDeclaration) ->
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
- raise NotImplementedError("<void> typedef not yet implemented")
+ raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
@@ -104,7 +104,7 @@ def emit_type_definition(environment: Environment, node: _XdrDeclaration) -> Non
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
- raise NotImplementedError("<void> typedef not yet implemented")
+ raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
@@ -165,7 +165,7 @@ def emit_typedef_decoder(environment: Environment, node: _XdrDeclaration) -> Non
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
- raise NotImplementedError("<void> typedef not yet implemented")
+ raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
@@ -225,7 +225,7 @@ def emit_typedef_encoder(environment: Environment, node: _XdrDeclaration) -> Non
elif isinstance(node, _XdrOptionalData):
raise NotImplementedError("<optional_data> typedef not yet implemented")
elif isinstance(node, _XdrVoid):
- raise NotImplementedError("<void> typedef not yet implemented")
+ raise ValueError("invalid void usage in RPC Specification")
else:
raise NotImplementedError("typedef: type not recognized")
diff --git a/tools/net/sunrpc/xdrgen/generators/union.py b/tools/net/sunrpc/xdrgen/generators/union.py
index 2cca00e279cd..d15837dae651 100644
--- a/tools/net/sunrpc/xdrgen/generators/union.py
+++ b/tools/net/sunrpc/xdrgen/generators/union.py
@@ -8,7 +8,7 @@ from jinja2 import Environment
from generators import SourceGenerator
from generators import create_jinja2_environment, get_jinja2_template
-from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid, get_header_name
+from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid, _XdrString, get_header_name
from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis, big_endian
@@ -40,13 +40,20 @@ def emit_union_case_spec_definition(
"""Emit a definition for an XDR union's case arm"""
if isinstance(node.arm, _XdrVoid):
return
- assert isinstance(node.arm, _XdrBasic)
+ 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=node.arm.spec.type_name,
- classifier=node.arm.spec.c_classifier,
+ type=type_name,
+ classifier=classifier,
)
)
@@ -77,6 +84,31 @@ def emit_union_switch_spec_decoder(
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:
@@ -84,6 +116,12 @@ def emit_union_case_spec_decoder(
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")
@@ -92,13 +130,13 @@ def emit_union_case_spec_decoder(
for case in node.values:
print(template.render(case=case))
- assert isinstance(node.arm, _XdrBasic)
+ assert isinstance(node.arm, (_XdrBasic, _XdrString))
template = get_jinja2_template(environment, "decoder", node.arm.template)
print(
template.render(
name=node.arm.name,
- type=node.arm.spec.type_name,
- classifier=node.arm.spec.c_classifier,
+ type=type_name,
+ classifier=classifier,
)
)
@@ -138,19 +176,33 @@ def emit_union_decoder(environment: Environment, node: _XdrUnion) -> None:
template = get_jinja2_template(environment, "decoder", "open")
print(template.render(name=node.name))
- emit_union_switch_spec_decoder(environment, node.discriminant)
+ # 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))
- for case in node.cases:
- emit_union_case_spec_decoder(
- environment,
- case,
- node.discriminant.spec.type_name in big_endian,
- )
+ # 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
- emit_union_default_spec_decoder(environment, node)
+ template = get_jinja2_template(environment, "decoder", "close")
+ print(template.render())
+ else:
+ emit_union_switch_spec_decoder(environment, node.discriminant)
- template = get_jinja2_template(environment, "decoder", "close")
- print(template.render())
+ 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(
@@ -162,6 +214,28 @@ def emit_union_switch_spec_encoder(
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:
@@ -169,7 +243,10 @@ def emit_union_case_spec_encoder(
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:
@@ -181,7 +258,7 @@ def emit_union_case_spec_encoder(
print(
template.render(
name=node.arm.name,
- type=node.arm.spec.type_name,
+ type=type_name,
)
)
@@ -219,19 +296,33 @@ def emit_union_encoder(environment, node: _XdrUnion) -> None:
template = get_jinja2_template(environment, "encoder", "open")
print(template.render(name=node.name))
- emit_union_switch_spec_encoder(environment, node.discriminant)
+ # 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))
- for case in node.cases:
- emit_union_case_spec_encoder(
- environment,
- case,
- node.discriminant.spec.type_name in big_endian,
- )
+ # 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
- emit_union_default_spec_encoder(environment, node)
+ template = get_jinja2_template(environment, "encoder", "close")
+ print(template.render())
+ else:
+ emit_union_switch_spec_encoder(environment, node.discriminant)
- template = get_jinja2_template(environment, "encoder", "close")
- print(template.render())
+ 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: