From: Chuck Lever <cel@kernel.org>
To: NeilBrown <neilb@ownmail.net>, Jeff Layton <jlayton@kernel.org>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <dai.ngo@oracle.com>, Tom Talpey <tom@talpey.com>
Cc: <linux-nfs@vger.kernel.org>, Chuck Lever <chuck.lever@oracle.com>
Subject: [PATCH 1/3] xdrgen: Extend error reporting to AST transformation phase
Date: Fri, 26 Dec 2025 10:19:33 -0500 [thread overview]
Message-ID: <20251226151935.441045-2-cel@kernel.org> (raw)
In-Reply-To: <20251226151935.441045-1-cel@kernel.org>
From: Chuck Lever <chuck.lever@oracle.com>
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>
---
.../net/sunrpc/xdrgen/subcmds/declarations.py | 8 +++-
.../net/sunrpc/xdrgen/subcmds/definitions.py | 8 +++-
tools/net/sunrpc/xdrgen/subcmds/lint.py | 8 +++-
tools/net/sunrpc/xdrgen/subcmds/source.py | 8 +++-
tools/net/sunrpc/xdrgen/xdr_parse.py | 40 ++++++++++++++++++-
5 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/tools/net/sunrpc/xdrgen/subcmds/declarations.py b/tools/net/sunrpc/xdrgen/subcmds/declarations.py
index 2fd5c255a547..97ffb76a02f1 100644
--- a/tools/net/sunrpc/xdrgen/subcmds/declarations.py
+++ b/tools/net/sunrpc/xdrgen/subcmds/declarations.py
@@ -8,6 +8,7 @@ import logging
from argparse import Namespace
from lark import logger
+from lark.exceptions import VisitError
from generators.constant import XdrConstantGenerator
from generators.enum import XdrEnumGenerator
@@ -24,6 +25,7 @@ from xdr_ast import _XdrConstant, _XdrEnum, _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
+from xdr_parse import handle_transform_error
logger.setLevel(logging.INFO)
@@ -63,7 +65,11 @@ def subcmd(args: Namespace) -> int:
)
except XdrParseError:
return 1
- ast = transform_parse_tree(parse_tree)
+ try:
+ ast = transform_parse_tree(parse_tree)
+ except VisitError as e:
+ handle_transform_error(e, source, args.filename)
+ return 1
gen = XdrHeaderTopGenerator(args.language, args.peer)
gen.emit_declaration(args.filename, ast)
diff --git a/tools/net/sunrpc/xdrgen/subcmds/definitions.py b/tools/net/sunrpc/xdrgen/subcmds/definitions.py
index 8ea5c57cc37a..d6c2dcd6f78f 100644
--- a/tools/net/sunrpc/xdrgen/subcmds/definitions.py
+++ b/tools/net/sunrpc/xdrgen/subcmds/definitions.py
@@ -8,6 +8,7 @@ import logging
from argparse import Namespace
from lark import logger
+from lark.exceptions import VisitError
from generators.constant import XdrConstantGenerator
from generators.enum import XdrEnumGenerator
@@ -24,6 +25,7 @@ from xdr_ast import _RpcProgram, _XdrConstant, _XdrEnum, _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
+from xdr_parse import handle_transform_error
logger.setLevel(logging.INFO)
@@ -82,7 +84,11 @@ def subcmd(args: Namespace) -> int:
)
except XdrParseError:
return 1
- ast = transform_parse_tree(parse_tree)
+ try:
+ ast = transform_parse_tree(parse_tree)
+ except VisitError as e:
+ handle_transform_error(e, source, args.filename)
+ return 1
gen = XdrHeaderTopGenerator(args.language, args.peer)
gen.emit_definition(args.filename, ast)
diff --git a/tools/net/sunrpc/xdrgen/subcmds/lint.py b/tools/net/sunrpc/xdrgen/subcmds/lint.py
index 2c48fa57c4e5..e1da49632e62 100644
--- a/tools/net/sunrpc/xdrgen/subcmds/lint.py
+++ b/tools/net/sunrpc/xdrgen/subcmds/lint.py
@@ -8,8 +8,10 @@ import logging
from argparse import Namespace
from lark import logger
+from lark.exceptions import VisitError
from xdr_parse import xdr_parser, make_error_handler, XdrParseError
+from xdr_parse import handle_transform_error
from xdr_ast import transform_parse_tree
logger.setLevel(logging.DEBUG)
@@ -27,6 +29,10 @@ def subcmd(args: Namespace) -> int:
)
except XdrParseError:
return 1
- transform_parse_tree(parse_tree)
+ try:
+ transform_parse_tree(parse_tree)
+ except VisitError as e:
+ handle_transform_error(e, source, args.filename)
+ return 1
return 0
diff --git a/tools/net/sunrpc/xdrgen/subcmds/source.py b/tools/net/sunrpc/xdrgen/subcmds/source.py
index bc7d38802df3..08c883f547d7 100644
--- a/tools/net/sunrpc/xdrgen/subcmds/source.py
+++ b/tools/net/sunrpc/xdrgen/subcmds/source.py
@@ -8,6 +8,7 @@ import logging
from argparse import Namespace
from lark import logger
+from lark.exceptions import VisitError
from generators.source_top import XdrSourceTopGenerator
from generators.enum import XdrEnumGenerator
@@ -23,6 +24,7 @@ from xdr_ast import _XdrStruct, _XdrTypedef, _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
logger.setLevel(logging.INFO)
@@ -105,7 +107,11 @@ def subcmd(args: Namespace) -> int:
)
except XdrParseError:
return 1
- ast = transform_parse_tree(parse_tree)
+ try:
+ ast = transform_parse_tree(parse_tree)
+ except VisitError as e:
+ handle_transform_error(e, source, args.filename)
+ return 1
match args.peer:
case "server":
generate_server_source(args.filename, ast, args.language)
diff --git a/tools/net/sunrpc/xdrgen/xdr_parse.py b/tools/net/sunrpc/xdrgen/xdr_parse.py
index 426513be066c..38724ad5aea2 100644
--- a/tools/net/sunrpc/xdrgen/xdr_parse.py
+++ b/tools/net/sunrpc/xdrgen/xdr_parse.py
@@ -7,7 +7,7 @@ import sys
from typing import Callable
from lark import Lark
-from lark.exceptions import UnexpectedInput, UnexpectedToken
+from lark.exceptions import UnexpectedInput, UnexpectedToken, VisitError
# Set to True to emit annotation comments in generated source
@@ -107,6 +107,44 @@ def make_error_handler(source: str, filename: str) -> Callable[[UnexpectedInput]
return handle_parse_error
+def handle_transform_error(e: VisitError, source: str, filename: str) -> None:
+ """Report a transform error with context.
+
+ Args:
+ e: The VisitError from Lark's transformer
+ source: The XDR source text being parsed
+ filename: The name of the file being parsed
+ """
+ lines = source.splitlines()
+
+ # Extract position from the tree node if available
+ line_num = 0
+ column = 0
+ if hasattr(e.obj, "meta") and e.obj.meta:
+ line_num = e.obj.meta.line
+ column = e.obj.meta.column
+
+ line_text = lines[line_num - 1] if 0 < line_num <= len(lines) else ""
+
+ # Build the error message
+ msg_parts = [f"{filename}:{line_num}:{column}: semantic error"]
+
+ # The original exception is typically a KeyError for undefined types
+ if isinstance(e.orig_exc, KeyError):
+ msg_parts.append(f"Undefined type '{e.orig_exc.args[0]}'")
+ else:
+ msg_parts.append(str(e.orig_exc))
+
+ # Show the offending line with a caret pointing to the error
+ if line_text:
+ msg_parts.append("")
+ msg_parts.append(f" {line_text}")
+ prefix = line_text[: column - 1].expandtabs()
+ msg_parts.append(f" {' ' * len(prefix)}^")
+
+ sys.stderr.write("\n".join(msg_parts) + "\n")
+
+
def xdr_parser() -> Lark:
"""Return a Lark parser instance configured with the XDR language grammar"""
--
2.52.0
next prev parent reply other threads:[~2025-12-26 15:19 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-26 15:19 [PATCH 0/3] Three xdrgen short subjects Chuck Lever
2025-12-26 15:19 ` Chuck Lever [this message]
2025-12-26 15:19 ` [PATCH 2/3] xdrgen: Emit a max_arg_sz macro Chuck Lever
2025-12-26 15:19 ` [PATCH 3/3] xdrgen: Add enum value validation to generated decoders Chuck Lever
2025-12-26 23:44 ` NeilBrown
2025-12-27 14:17 ` Chuck Lever
2025-12-27 23:02 ` NeilBrown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251226151935.441045-2-cel@kernel.org \
--to=cel@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=dai.ngo@oracle.com \
--cc=jlayton@kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neilb@ownmail.net \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).