Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

xdrgen: Extend error reporting to AST transformation phase

Commit 277df18d7df9 ("xdrgen: Improve parse error reporting") added
clean, compiler-style error messages for syntax errors detected during
parsing. However, semantic errors discovered during AST transformation
still produce verbose Python stack traces.

When an XDR specification references an undefined type, the transformer
raises a VisitError wrapping a KeyError. Before this change:

Traceback (most recent call last):
File ".../lark/visitors.py", line 124, in _call_userfunc
return f(children)
...
KeyError: 'fsh4_mode'
...
lark.exceptions.VisitError: Error trying to process rule "basic":
'fsh4_mode'

After this change:

file.x:156:2: semantic error
Undefined type 'fsh4_mode'

fsh4_mode mode;
^

The new handle_transform_error() function extracts position information
from the Lark tree node metadata and formats the error consistently with
parse error messages.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>

+67 -5
+7 -1
tools/net/sunrpc/xdrgen/subcmds/declarations.py
··· 8 8 9 9 from argparse import Namespace 10 10 from lark import logger 11 + from lark.exceptions import VisitError 11 12 12 13 from generators.constant import XdrConstantGenerator 13 14 from generators.enum import XdrEnumGenerator ··· 25 24 from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion 26 25 from xdr_parse import xdr_parser, set_xdr_annotate 27 26 from xdr_parse import make_error_handler, XdrParseError 27 + from xdr_parse import handle_transform_error 28 28 29 29 logger.setLevel(logging.INFO) 30 30 ··· 65 63 ) 66 64 except XdrParseError: 67 65 return 1 68 - ast = transform_parse_tree(parse_tree) 66 + try: 67 + ast = transform_parse_tree(parse_tree) 68 + except VisitError as e: 69 + handle_transform_error(e, source, args.filename) 70 + return 1 69 71 70 72 gen = XdrHeaderTopGenerator(args.language, args.peer) 71 73 gen.emit_declaration(args.filename, ast)
+7 -1
tools/net/sunrpc/xdrgen/subcmds/definitions.py
··· 8 8 9 9 from argparse import Namespace 10 10 from lark import logger 11 + from lark.exceptions import VisitError 11 12 12 13 from generators.constant import XdrConstantGenerator 13 14 from generators.enum import XdrEnumGenerator ··· 25 24 from xdr_ast import _XdrTypedef, _XdrStruct, _XdrUnion 26 25 from xdr_parse import xdr_parser, set_xdr_annotate 27 26 from xdr_parse import make_error_handler, XdrParseError 27 + from xdr_parse import handle_transform_error 28 28 29 29 logger.setLevel(logging.INFO) 30 30 ··· 84 82 ) 85 83 except XdrParseError: 86 84 return 1 87 - ast = transform_parse_tree(parse_tree) 85 + try: 86 + ast = transform_parse_tree(parse_tree) 87 + except VisitError as e: 88 + handle_transform_error(e, source, args.filename) 89 + return 1 88 90 89 91 gen = XdrHeaderTopGenerator(args.language, args.peer) 90 92 gen.emit_definition(args.filename, ast)
+7 -1
tools/net/sunrpc/xdrgen/subcmds/lint.py
··· 8 8 9 9 from argparse import Namespace 10 10 from lark import logger 11 + from lark.exceptions import VisitError 11 12 12 13 from xdr_parse import xdr_parser, make_error_handler, XdrParseError 14 + from xdr_parse import handle_transform_error 13 15 from xdr_ast import transform_parse_tree 14 16 15 17 logger.setLevel(logging.DEBUG) ··· 29 27 ) 30 28 except XdrParseError: 31 29 return 1 32 - transform_parse_tree(parse_tree) 30 + try: 31 + transform_parse_tree(parse_tree) 32 + except VisitError as e: 33 + handle_transform_error(e, source, args.filename) 34 + return 1 33 35 34 36 return 0
+7 -1
tools/net/sunrpc/xdrgen/subcmds/source.py
··· 8 8 9 9 from argparse import Namespace 10 10 from lark import logger 11 + from lark.exceptions import VisitError 11 12 12 13 from generators.source_top import XdrSourceTopGenerator 13 14 from generators.enum import XdrEnumGenerator ··· 24 23 25 24 from xdr_parse import xdr_parser, set_xdr_annotate 26 25 from xdr_parse import make_error_handler, XdrParseError 26 + from xdr_parse import handle_transform_error 27 27 28 28 logger.setLevel(logging.INFO) 29 29 ··· 107 105 ) 108 106 except XdrParseError: 109 107 return 1 110 - ast = transform_parse_tree(parse_tree) 108 + try: 109 + ast = transform_parse_tree(parse_tree) 110 + except VisitError as e: 111 + handle_transform_error(e, source, args.filename) 112 + return 1 111 113 match args.peer: 112 114 case "server": 113 115 generate_server_source(args.filename, ast, args.language)
+39 -1
tools/net/sunrpc/xdrgen/xdr_parse.py
··· 7 7 from typing import Callable 8 8 9 9 from lark import Lark 10 - from lark.exceptions import UnexpectedInput, UnexpectedToken 10 + from lark.exceptions import UnexpectedInput, UnexpectedToken, VisitError 11 11 12 12 13 13 # Set to True to emit annotation comments in generated source ··· 105 105 raise XdrParseError() 106 106 107 107 return handle_parse_error 108 + 109 + 110 + def handle_transform_error(e: VisitError, source: str, filename: str) -> None: 111 + """Report a transform error with context. 112 + 113 + Args: 114 + e: The VisitError from Lark's transformer 115 + source: The XDR source text being parsed 116 + filename: The name of the file being parsed 117 + """ 118 + lines = source.splitlines() 119 + 120 + # Extract position from the tree node if available 121 + line_num = 0 122 + column = 0 123 + if hasattr(e.obj, "meta") and e.obj.meta: 124 + line_num = e.obj.meta.line 125 + column = e.obj.meta.column 126 + 127 + line_text = lines[line_num - 1] if 0 < line_num <= len(lines) else "" 128 + 129 + # Build the error message 130 + msg_parts = [f"{filename}:{line_num}:{column}: semantic error"] 131 + 132 + # The original exception is typically a KeyError for undefined types 133 + if isinstance(e.orig_exc, KeyError): 134 + msg_parts.append(f"Undefined type '{e.orig_exc.args[0]}'") 135 + else: 136 + msg_parts.append(str(e.orig_exc)) 137 + 138 + # Show the offending line with a caret pointing to the error 139 + if line_text: 140 + msg_parts.append("") 141 + msg_parts.append(f" {line_text}") 142 + prefix = line_text[: column - 1].expandtabs() 143 + msg_parts.append(f" {' ' * len(prefix)}^") 144 + 145 + sys.stderr.write("\n".join(msg_parts) + "\n") 108 146 109 147 110 148 def xdr_parser() -> Lark: