xref: /linux/tools/net/sunrpc/xdrgen/generators/__init__.py (revision b0319c4642638bad4b36974055b1c0894b2c7aa9)
1# SPDX-License-Identifier: GPL-2.0
2
3"""Define a base code generator class"""
4
5from pathlib import Path
6from jinja2 import Environment, FileSystemLoader, Template
7
8from xdr_ast import _XdrAst, Specification, _RpcProgram, _XdrTypeSpecifier
9from xdr_ast import public_apis, pass_by_reference, get_header_name
10from xdr_parse import get_xdr_annotate
11
12
13def create_jinja2_environment(language: str, xdr_type: str) -> Environment:
14    """Open a set of templates based on output language"""
15    match language:
16        case "C":
17            templates_dir = (
18                Path(__file__).parent.parent / "templates" / language / xdr_type
19            )
20            environment = Environment(
21                loader=FileSystemLoader(templates_dir),
22                trim_blocks=True,
23                lstrip_blocks=True,
24            )
25            environment.globals["annotate"] = get_xdr_annotate()
26            environment.globals["public_apis"] = public_apis
27            environment.globals["pass_by_reference"] = pass_by_reference
28            return environment
29        case _:
30            raise NotImplementedError("Language not supported")
31
32
33def get_jinja2_template(
34    environment: Environment, template_type: str, template_name: str
35) -> Template:
36    """Retrieve a Jinja2 template for emitting source code"""
37    return environment.get_template(template_type + "/" + template_name + ".j2")
38
39
40def find_xdr_program_name(root: Specification) -> str:
41    """Retrieve the RPC program name from an abstract syntax tree"""
42    raw_name = get_header_name()
43    if raw_name != "none":
44        return raw_name.lower()
45    for definition in root.definitions:
46        if isinstance(definition.value, _RpcProgram):
47            raw_name = definition.value.name
48            return raw_name.lower().removesuffix("_program").removesuffix("_prog")
49    return "noprog"
50
51
52def header_guard_infix(filename: str) -> str:
53    """Extract the header guard infix from the specification filename"""
54    return Path(filename).stem.upper()
55
56
57def kernel_c_type(spec: _XdrTypeSpecifier) -> str:
58    """Return name of C type"""
59    builtin_native_c_type = {
60        "bool": "bool",
61        "int": "s32",
62        "unsigned_int": "u32",
63        "long": "s32",
64        "unsigned_long": "u32",
65        "hyper": "s64",
66        "unsigned_hyper": "u64",
67    }
68    if spec.type_name in builtin_native_c_type:
69        return builtin_native_c_type[spec.type_name]
70    return spec.type_name
71
72
73class Boilerplate:
74    """Base class to generate boilerplate for source files"""
75
76    def __init__(self, language: str, peer: str):
77        """Initialize an instance of this class"""
78        raise NotImplementedError("No language support defined")
79
80    def emit_declaration(self, filename: str, root: Specification) -> None:
81        """Emit declaration header boilerplate"""
82        raise NotImplementedError("Header boilerplate generation not supported")
83
84    def emit_definition(self, filename: str, root: Specification) -> None:
85        """Emit definition header boilerplate"""
86        raise NotImplementedError("Header boilerplate generation not supported")
87
88    def emit_source(self, filename: str, root: Specification) -> None:
89        """Emit generic source code for this XDR type"""
90        raise NotImplementedError("Source boilerplate generation not supported")
91
92
93class SourceGenerator:
94    """Base class to generate header and source code for XDR types"""
95
96    def __init__(self, language: str, peer: str):
97        """Initialize an instance of this class"""
98        raise NotImplementedError("No language support defined")
99
100    def emit_declaration(self, node: _XdrAst) -> None:
101        """Emit one function declaration for this XDR type"""
102        raise NotImplementedError("Declaration generation not supported")
103
104    def emit_decoder(self, node: _XdrAst) -> None:
105        """Emit one decoder function for this XDR type"""
106        raise NotImplementedError("Decoder generation not supported")
107
108    def emit_definition(self, node: _XdrAst) -> None:
109        """Emit one definition for this XDR type"""
110        raise NotImplementedError("Definition generation not supported")
111
112    def emit_encoder(self, node: _XdrAst) -> None:
113        """Emit one encoder function for this XDR type"""
114        raise NotImplementedError("Encoder generation not supported")
115
116    def emit_maxsize(self, node: _XdrAst) -> None:
117        """Emit one maxsize macro for this XDR type"""
118        raise NotImplementedError("Maxsize macro generation not supported")
119