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