Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
11from lark.exceptions import VisitError
12
13from generators.source_top import XdrSourceTopGenerator
14from generators.enum import XdrEnumGenerator
15from generators.passthru import XdrPassthruGenerator
16from generators.pointer import XdrPointerGenerator
17from generators.program import XdrProgramGenerator
18from generators.typedef import XdrTypedefGenerator
19from generators.struct import XdrStructGenerator
20from generators.union import XdrUnionGenerator
21
22from xdr_ast import transform_parse_tree, _RpcProgram, Specification
23from xdr_ast import _XdrAst, _XdrEnum, _XdrPassthru, _XdrPointer
24from xdr_ast import _XdrStruct, _XdrTypedef, _XdrUnion
25
26from xdr_parse import xdr_parser, set_xdr_annotate, set_xdr_enum_validation
27from xdr_parse import make_error_handler, XdrParseError
28from xdr_parse import handle_transform_error
29
30logger.setLevel(logging.INFO)
31
32
33def emit_source_decoder(node: _XdrAst, language: str, peer: str) -> None:
34 """Emit one XDR decoder function for a source file"""
35 if isinstance(node, _XdrEnum):
36 gen = XdrEnumGenerator(language, peer)
37 elif isinstance(node, _XdrPointer):
38 gen = XdrPointerGenerator(language, peer)
39 elif isinstance(node, _XdrTypedef):
40 gen = XdrTypedefGenerator(language, peer)
41 elif isinstance(node, _XdrStruct):
42 gen = XdrStructGenerator(language, peer)
43 elif isinstance(node, _XdrUnion):
44 gen = XdrUnionGenerator(language, peer)
45 elif isinstance(node, _RpcProgram):
46 gen = XdrProgramGenerator(language, peer)
47 else:
48 return
49 gen.emit_decoder(node)
50
51
52def emit_source_encoder(node: _XdrAst, language: str, peer: str) -> None:
53 """Emit one XDR encoder function for a source file"""
54 if isinstance(node, _XdrEnum):
55 gen = XdrEnumGenerator(language, peer)
56 elif isinstance(node, _XdrPointer):
57 gen = XdrPointerGenerator(language, peer)
58 elif isinstance(node, _XdrTypedef):
59 gen = XdrTypedefGenerator(language, peer)
60 elif isinstance(node, _XdrStruct):
61 gen = XdrStructGenerator(language, peer)
62 elif isinstance(node, _XdrUnion):
63 gen = XdrUnionGenerator(language, peer)
64 elif isinstance(node, _RpcProgram):
65 gen = XdrProgramGenerator(language, peer)
66 else:
67 return
68 gen.emit_encoder(node)
69
70
71def generate_server_source(filename: str, root: Specification, language: str) -> None:
72 """Generate server-side source code"""
73
74 gen = XdrSourceTopGenerator(language, "server")
75 gen.emit_source(filename, root)
76
77 for definition in root.definitions:
78 if isinstance(definition.value, _XdrPassthru):
79 passthru_gen = XdrPassthruGenerator(language, "server")
80 passthru_gen.emit_decoder(definition.value)
81 else:
82 emit_source_decoder(definition.value, language, "server")
83 for definition in root.definitions:
84 if not isinstance(definition.value, _XdrPassthru):
85 emit_source_encoder(definition.value, language, "server")
86
87
88def generate_client_source(filename: str, root: Specification, language: str) -> None:
89 """Generate client-side source code"""
90
91 gen = XdrSourceTopGenerator(language, "client")
92 gen.emit_source(filename, root)
93
94 for definition in root.definitions:
95 if isinstance(definition.value, _XdrPassthru):
96 passthru_gen = XdrPassthruGenerator(language, "client")
97 passthru_gen.emit_decoder(definition.value)
98 else:
99 emit_source_encoder(definition.value, language, "client")
100 for definition in root.definitions:
101 if not isinstance(definition.value, _XdrPassthru):
102 emit_source_decoder(definition.value, language, "client")
103
104 # cel: todo: client needs PROC macros
105
106
107def subcmd(args: Namespace) -> int:
108 """Generate encoder and decoder functions"""
109
110 set_xdr_annotate(args.annotate)
111 set_xdr_enum_validation(not args.no_enum_validation)
112 parser = xdr_parser()
113 with open(args.filename, encoding="utf-8") as f:
114 source = f.read()
115 try:
116 parse_tree = parser.parse(
117 source, on_error=make_error_handler(source, args.filename)
118 )
119 except XdrParseError:
120 return 1
121 try:
122 ast = transform_parse_tree(parse_tree)
123 except VisitError as e:
124 handle_transform_error(e, source, args.filename)
125 return 1
126 match args.peer:
127 case "server":
128 generate_server_source(args.filename, ast, args.language)
129 case "client":
130 generate_client_source(args.filename, ast, args.language)
131 case _:
132 print("Code generation for", args.peer, "is not yet supported")
133
134 return 0