mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 04:04:43 +01:00
xdrgen: Implement pass-through lines in specifications
XDR specification files can contain lines prefixed with '%' that pass through unchanged to generated output. Traditional rpcgen removes the '%' and emits the remainder verbatim, allowing direct insertion of C includes, pragma directives, or other language- specific content into the generated code. Until now, xdrgen silently discarded these lines during parsing. This prevented specifications from including necessary headers or preprocessor directives that might be required for the generated code to compile correctly. The grammar now captures pass-through lines instead of ignoring them. A new AST node type represents pass-through content, and the AST transformer strips the leading '%' character. Definition and source generators emit pass-through content in document order, preserving the original placement within the specification. This brings xdrgen closer to feature parity with traditional rpcgen while maintaining the existing document-order processing model. Existing generated xdrgen source code has been regenerated. Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
3daab3112f
commit
6bc85baba4
12 changed files with 116 additions and 20 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Generated by xdrgen. Manual edits will be lost.
|
||||
// XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x
|
||||
// XDR specification modification time: Thu Dec 25 13:44:43 2025
|
||||
// XDR specification modification time: Thu Jan 8 23:11:48 2026
|
||||
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
|
|
@ -178,6 +178,10 @@ xdrgen_decode_fattr4_open_arguments(struct xdr_stream *xdr, fattr4_open_argument
|
|||
return xdrgen_decode_open_arguments4(xdr, ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine what OPEN supports.
|
||||
*/
|
||||
|
||||
bool
|
||||
xdrgen_decode_fattr4_time_deleg_access(struct xdr_stream *xdr, fattr4_time_deleg_access *ptr)
|
||||
{
|
||||
|
|
@ -190,6 +194,11 @@ xdrgen_decode_fattr4_time_deleg_modify(struct xdr_stream *xdr, fattr4_time_deleg
|
|||
return xdrgen_decode_nfstime4(xdr, ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* New RECOMMENDED Attribute for
|
||||
* delegation caching of times
|
||||
*/
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_open_delegation_type4(struct xdr_stream *xdr, open_delegation_type4 *ptr)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x */
|
||||
/* XDR specification modification time: Thu Dec 25 13:44:43 2025 */
|
||||
/* XDR specification modification time: Thu Jan 8 23:11:48 2026 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NFS4_1_DECL_H
|
||||
#define _LINUX_XDRGEN_NFS4_1_DECL_H
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nfs4_1.x */
|
||||
/* XDR specification modification time: Thu Dec 25 13:44:43 2025 */
|
||||
/* XDR specification modification time: Thu Jan 8 23:11:48 2026 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NFS4_1_DEF_H
|
||||
#define _LINUX_XDRGEN_NFS4_1_DEF_H
|
||||
|
|
@ -87,6 +87,10 @@ typedef enum open_args_createmode4 open_args_createmode4;
|
|||
|
||||
typedef struct open_arguments4 fattr4_open_arguments;
|
||||
|
||||
/*
|
||||
* Determine what OPEN supports.
|
||||
*/
|
||||
|
||||
enum { FATTR4_OPEN_ARGUMENTS = 86 };
|
||||
|
||||
enum { OPEN4_RESULT_NO_OPEN_STATEID = 0x00000010 };
|
||||
|
|
@ -95,6 +99,11 @@ typedef struct nfstime4 fattr4_time_deleg_access;
|
|||
|
||||
typedef struct nfstime4 fattr4_time_deleg_modify;
|
||||
|
||||
/*
|
||||
* New RECOMMENDED Attribute for
|
||||
* delegation caching of times
|
||||
*/
|
||||
|
||||
enum { FATTR4_TIME_DELEG_ACCESS = 84 };
|
||||
|
||||
enum { FATTR4_TIME_DELEG_MODIFY = 85 };
|
||||
|
|
|
|||
|
|
@ -250,8 +250,6 @@ Add more pragma directives:
|
|||
Enable something like a #include to dynamically insert the content
|
||||
of other specification files
|
||||
|
||||
Properly support line-by-line pass-through via the "%" decorator
|
||||
|
||||
Build a unit test suite for verifying translation of XDR language
|
||||
into compilable code
|
||||
|
||||
|
|
|
|||
26
tools/net/sunrpc/xdrgen/generators/passthru.py
Normal file
26
tools/net/sunrpc/xdrgen/generators/passthru.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env python3
|
||||
# ex: set filetype=python:
|
||||
|
||||
"""Generate code for XDR pass-through lines"""
|
||||
|
||||
from generators import SourceGenerator, create_jinja2_environment
|
||||
from xdr_ast import _XdrPassthru
|
||||
|
||||
|
||||
class XdrPassthruGenerator(SourceGenerator):
|
||||
"""Generate source code for XDR pass-through content"""
|
||||
|
||||
def __init__(self, language: str, peer: str):
|
||||
"""Initialize an instance of this class"""
|
||||
self.environment = create_jinja2_environment(language, "passthru")
|
||||
self.peer = peer
|
||||
|
||||
def emit_definition(self, node: _XdrPassthru) -> None:
|
||||
"""Emit one pass-through line"""
|
||||
template = self.environment.get_template("definition.j2")
|
||||
print(template.render(content=node.content))
|
||||
|
||||
def emit_decoder(self, node: _XdrPassthru) -> None:
|
||||
"""Emit one pass-through line"""
|
||||
template = self.environment.get_template("source.j2")
|
||||
print(template.render(content=node.content))
|
||||
|
|
@ -78,6 +78,9 @@ definition : constant_def
|
|||
| type_def
|
||||
| program_def
|
||||
| pragma_def
|
||||
| passthru_def
|
||||
|
||||
passthru_def : PASSTHRU
|
||||
|
||||
//
|
||||
// RPC program definitions not specified in RFC 4506
|
||||
|
|
@ -115,8 +118,7 @@ decimal_constant : /[\+-]?(0|[1-9][0-9]*)/
|
|||
hexadecimal_constant : /0x([a-f]|[A-F]|[0-9])+/
|
||||
octal_constant : /0[0-7]+/
|
||||
|
||||
PASSTHRU : "%" | "%" /.+/
|
||||
%ignore PASSTHRU
|
||||
PASSTHRU : /%.*/
|
||||
|
||||
%import common.C_COMMENT
|
||||
%ignore C_COMMENT
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ from argparse import Namespace
|
|||
from lark import logger
|
||||
from lark.exceptions import VisitError
|
||||
|
||||
from generators.constant import XdrConstantGenerator
|
||||
from generators.enum import XdrEnumGenerator
|
||||
from generators.header_bottom import XdrHeaderBottomGenerator
|
||||
from generators.header_top import XdrHeaderTopGenerator
|
||||
|
|
@ -21,8 +20,7 @@ from generators.struct import XdrStructGenerator
|
|||
from generators.union import XdrUnionGenerator
|
||||
|
||||
from xdr_ast import transform_parse_tree, _RpcProgram, Specification
|
||||
from xdr_ast import _XdrConstant, _XdrEnum, _XdrPointer
|
||||
from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion
|
||||
from xdr_ast import _XdrEnum, _XdrPointer, _XdrTypedef, _XdrStruct, _XdrUnion
|
||||
from xdr_parse import xdr_parser, set_xdr_annotate
|
||||
from xdr_parse import make_error_handler, XdrParseError
|
||||
from xdr_parse import handle_transform_error
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from generators.constant import XdrConstantGenerator
|
|||
from generators.enum import XdrEnumGenerator
|
||||
from generators.header_bottom import XdrHeaderBottomGenerator
|
||||
from generators.header_top import XdrHeaderTopGenerator
|
||||
from generators.passthru import XdrPassthruGenerator
|
||||
from generators.pointer import XdrPointerGenerator
|
||||
from generators.program import XdrProgramGenerator
|
||||
from generators.typedef import XdrTypedefGenerator
|
||||
|
|
@ -21,7 +22,7 @@ from generators.struct import XdrStructGenerator
|
|||
from generators.union import XdrUnionGenerator
|
||||
|
||||
from xdr_ast import transform_parse_tree, Specification
|
||||
from xdr_ast import _RpcProgram, _XdrConstant, _XdrEnum, _XdrPointer
|
||||
from xdr_ast import _RpcProgram, _XdrConstant, _XdrEnum, _XdrPassthru, _XdrPointer
|
||||
from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion
|
||||
from xdr_parse import xdr_parser, set_xdr_annotate
|
||||
from xdr_parse import make_error_handler, XdrParseError
|
||||
|
|
@ -47,6 +48,8 @@ def emit_header_definitions(root: Specification, language: str, peer: str) -> No
|
|||
gen = XdrStructGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrUnion):
|
||||
gen = XdrUnionGenerator(language, peer)
|
||||
elif isinstance(definition.value, _XdrPassthru):
|
||||
gen = XdrPassthruGenerator(language, peer)
|
||||
else:
|
||||
continue
|
||||
gen.emit_definition(definition.value)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from lark.exceptions import VisitError
|
|||
|
||||
from generators.source_top import XdrSourceTopGenerator
|
||||
from generators.enum import XdrEnumGenerator
|
||||
from generators.passthru import XdrPassthruGenerator
|
||||
from generators.pointer import XdrPointerGenerator
|
||||
from generators.program import XdrProgramGenerator
|
||||
from generators.typedef import XdrTypedefGenerator
|
||||
|
|
@ -19,7 +20,7 @@ from generators.struct import XdrStructGenerator
|
|||
from generators.union import XdrUnionGenerator
|
||||
|
||||
from xdr_ast import transform_parse_tree, _RpcProgram, Specification
|
||||
from xdr_ast import _XdrAst, _XdrEnum, _XdrPointer
|
||||
from xdr_ast import _XdrAst, _XdrEnum, _XdrPassthru, _XdrPointer
|
||||
from xdr_ast import _XdrStruct, _XdrTypedef, _XdrUnion
|
||||
|
||||
from xdr_parse import xdr_parser, set_xdr_annotate, set_xdr_enum_validation
|
||||
|
|
@ -74,22 +75,31 @@ def generate_server_source(filename: str, root: Specification, language: str) ->
|
|||
gen.emit_source(filename, root)
|
||||
|
||||
for definition in root.definitions:
|
||||
emit_source_decoder(definition.value, language, "server")
|
||||
if isinstance(definition.value, _XdrPassthru):
|
||||
passthru_gen = XdrPassthruGenerator(language, "server")
|
||||
passthru_gen.emit_decoder(definition.value)
|
||||
else:
|
||||
emit_source_decoder(definition.value, language, "server")
|
||||
for definition in root.definitions:
|
||||
emit_source_encoder(definition.value, language, "server")
|
||||
if not isinstance(definition.value, _XdrPassthru):
|
||||
emit_source_encoder(definition.value, language, "server")
|
||||
|
||||
|
||||
def generate_client_source(filename: str, root: Specification, language: str) -> None:
|
||||
"""Generate server-side source code"""
|
||||
"""Generate client-side source code"""
|
||||
|
||||
gen = XdrSourceTopGenerator(language, "client")
|
||||
gen.emit_source(filename, root)
|
||||
|
||||
print("")
|
||||
for definition in root.definitions:
|
||||
emit_source_encoder(definition.value, language, "client")
|
||||
if isinstance(definition.value, _XdrPassthru):
|
||||
passthru_gen = XdrPassthruGenerator(language, "client")
|
||||
passthru_gen.emit_decoder(definition.value)
|
||||
else:
|
||||
emit_source_encoder(definition.value, language, "client")
|
||||
for definition in root.definitions:
|
||||
emit_source_decoder(definition.value, language, "client")
|
||||
if not isinstance(definition.value, _XdrPassthru):
|
||||
emit_source_decoder(definition.value, language, "client")
|
||||
|
||||
# cel: todo: client needs PROC macros
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{{ content }}
|
||||
3
tools/net/sunrpc/xdrgen/templates/C/passthru/source.j2
Normal file
3
tools/net/sunrpc/xdrgen/templates/C/passthru/source.j2
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{# SPDX-License-Identifier: GPL-2.0 #}
|
||||
|
||||
{{ content }}
|
||||
|
|
@ -516,6 +516,13 @@ class _Pragma(_XdrAst):
|
|||
"""Empty class for pragma directives"""
|
||||
|
||||
|
||||
@dataclass
|
||||
class _XdrPassthru(_XdrAst):
|
||||
"""Passthrough line to emit verbatim in output"""
|
||||
|
||||
content: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class Definition(_XdrAst, ast_utils.WithMeta):
|
||||
"""Corresponds to 'definition' in the grammar"""
|
||||
|
|
@ -738,14 +745,42 @@ class ParseToAst(Transformer):
|
|||
raise NotImplementedError("Directive not supported")
|
||||
return _Pragma()
|
||||
|
||||
def passthru_def(self, children):
|
||||
"""Instantiate one _XdrPassthru object"""
|
||||
token = children[0]
|
||||
content = token.value[1:]
|
||||
return _XdrPassthru(content)
|
||||
|
||||
|
||||
transformer = ast_utils.create_transformer(this_module, ParseToAst())
|
||||
|
||||
|
||||
def _merge_consecutive_passthru(definitions: List[Definition]) -> List[Definition]:
|
||||
"""Merge consecutive passthru definitions into single nodes"""
|
||||
result = []
|
||||
i = 0
|
||||
while i < len(definitions):
|
||||
if isinstance(definitions[i].value, _XdrPassthru):
|
||||
lines = [definitions[i].value.content]
|
||||
meta = definitions[i].meta
|
||||
j = i + 1
|
||||
while j < len(definitions) and isinstance(definitions[j].value, _XdrPassthru):
|
||||
lines.append(definitions[j].value.content)
|
||||
j += 1
|
||||
merged = _XdrPassthru("\n".join(lines))
|
||||
result.append(Definition(meta, merged))
|
||||
i = j
|
||||
else:
|
||||
result.append(definitions[i])
|
||||
i += 1
|
||||
return result
|
||||
|
||||
|
||||
def transform_parse_tree(parse_tree):
|
||||
"""Transform productions into an abstract syntax tree"""
|
||||
|
||||
return transformer.transform(parse_tree)
|
||||
ast = transformer.transform(parse_tree)
|
||||
ast.definitions = _merge_consecutive_passthru(ast.definitions)
|
||||
return ast
|
||||
|
||||
|
||||
def get_header_name() -> str:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue