119 lines · python
1#!/usr/bin/env python32# ex: set filetype=python:3 4"""Translate an XDR specification into executable code that5can be compiled for the Linux kernel."""6 7import logging8 9from argparse import Namespace10from lark import logger11from lark.exceptions import UnexpectedInput12 13from generators.source_top import XdrSourceTopGenerator14from generators.enum import XdrEnumGenerator15from generators.pointer import XdrPointerGenerator16from generators.program import XdrProgramGenerator17from generators.typedef import XdrTypedefGenerator18from generators.struct import XdrStructGenerator19from generators.union import XdrUnionGenerator20 21from xdr_ast import transform_parse_tree, _RpcProgram, Specification22from xdr_ast import _XdrAst, _XdrEnum, _XdrPointer23from xdr_ast import _XdrStruct, _XdrTypedef, _XdrUnion24 25from xdr_parse import xdr_parser, set_xdr_annotate26 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 return46 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 return65 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 # cel: todo: client needs XDR size macros87 88 for definition in root.definitions:89 emit_source_encoder(definition.value, language, "client")90 for definition in root.definitions:91 emit_source_decoder(definition.value, language, "client")92 93 # cel: todo: client needs PROC macros94 95 96def handle_parse_error(e: UnexpectedInput) -> bool:97 """Simple parse error reporting, no recovery attempted"""98 print(e)99 return True100 101 102def subcmd(args: Namespace) -> int:103 """Generate encoder and decoder functions"""104 105 set_xdr_annotate(args.annotate)106 parser = xdr_parser()107 with open(args.filename, encoding="utf-8") as f:108 parse_tree = parser.parse(f.read(), on_error=handle_parse_error)109 ast = transform_parse_tree(parse_tree)110 match args.peer:111 case "server":112 generate_server_source(args.filename, ast, args.language)113 case "client":114 generate_client_source(args.filename, ast, args.language)115 case _:116 print("Code generation for", args.peer, "is not yet supported")117 118 return 0119