1#!/usr/bin/env python3 2# ex: set filetype=python: 3 4"""Translate an XDR specification into executable code that 5can be compiled for the Linux kernel.""" 6 7import logging 8 9from argparse import Namespace 10from lark import logger 11 12from generators.source_top import XdrSourceTopGenerator 13from generators.enum import XdrEnumGenerator 14from generators.pointer import XdrPointerGenerator 15from generators.program import XdrProgramGenerator 16from generators.typedef import XdrTypedefGenerator 17from generators.struct import XdrStructGenerator 18from generators.union import XdrUnionGenerator 19 20from xdr_ast import transform_parse_tree, _RpcProgram, Specification 21from xdr_ast import _XdrAst, _XdrEnum, _XdrPointer 22from xdr_ast import _XdrStruct, _XdrTypedef, _XdrUnion 23 24from xdr_parse import xdr_parser, set_xdr_annotate 25from xdr_parse import make_error_handler, XdrParseError 26 27logger.setLevel(logging.INFO) 28 29 30def emit_source_decoder(node: _XdrAst, language: str, peer: str) -> None: 31 """Emit one XDR decoder function for a source file""" 32 if isinstance(node, _XdrEnum): 33 gen = XdrEnumGenerator(language, peer) 34 elif isinstance(node, _XdrPointer): 35 gen = XdrPointerGenerator(language, peer) 36 elif isinstance(node, _XdrTypedef): 37 gen = XdrTypedefGenerator(language, peer) 38 elif isinstance(node, _XdrStruct): 39 gen = XdrStructGenerator(language, peer) 40 elif isinstance(node, _XdrUnion): 41 gen = XdrUnionGenerator(language, peer) 42 elif isinstance(node, _RpcProgram): 43 gen = XdrProgramGenerator(language, peer) 44 else: 45 return 46 gen.emit_decoder(node) 47 48 49def emit_source_encoder(node: _XdrAst, language: str, peer: str) -> None: 50 """Emit one XDR encoder function for a source file""" 51 if isinstance(node, _XdrEnum): 52 gen = XdrEnumGenerator(language, peer) 53 elif isinstance(node, _XdrPointer): 54 gen = XdrPointerGenerator(language, peer) 55 elif isinstance(node, _XdrTypedef): 56 gen = XdrTypedefGenerator(language, peer) 57 elif isinstance(node, _XdrStruct): 58 gen = XdrStructGenerator(language, peer) 59 elif isinstance(node, _XdrUnion): 60 gen = XdrUnionGenerator(language, peer) 61 elif isinstance(node, _RpcProgram): 62 gen = XdrProgramGenerator(language, peer) 63 else: 64 return 65 gen.emit_encoder(node) 66 67 68def generate_server_source(filename: str, root: Specification, language: str) -> None: 69 """Generate server-side source code""" 70 71 gen = XdrSourceTopGenerator(language, "server") 72 gen.emit_source(filename, root) 73 74 for definition in root.definitions: 75 emit_source_decoder(definition.value, language, "server") 76 for definition in root.definitions: 77 emit_source_encoder(definition.value, language, "server") 78 79 80def generate_client_source(filename: str, root: Specification, language: str) -> None: 81 """Generate server-side source code""" 82 83 gen = XdrSourceTopGenerator(language, "client") 84 gen.emit_source(filename, root) 85 86 print("") 87 for definition in root.definitions: 88 emit_source_encoder(definition.value, language, "client") 89 for definition in root.definitions: 90 emit_source_decoder(definition.value, language, "client") 91 92 # cel: todo: client needs PROC macros 93 94 95def subcmd(args: Namespace) -> int: 96 """Generate encoder and decoder functions""" 97 98 set_xdr_annotate(args.annotate) 99 parser = xdr_parser() 100 with open(args.filename, encoding="utf-8") as f: 101 source = f.read() 102 try: 103 parse_tree = parser.parse( 104 source, on_error=make_error_handler(source, args.filename) 105 ) 106 except XdrParseError: 107 return 1 108 ast = transform_parse_tree(parse_tree) 109 match args.peer: 110 case "server": 111 generate_server_source(args.filename, ast, args.language) 112 case "client": 113 generate_client_source(args.filename, ast, args.language) 114 case _: 115 print("Code generation for", args.peer, "is not yet supported") 116 117 return 0 118