diff --git a/pyparsing/core.py b/pyparsing/core.py index a7b51762..ba976372 100644 --- a/pyparsing/core.py +++ b/pyparsing/core.py @@ -4547,7 +4547,8 @@ def parseImpl(self, instring, loc, doActions=True): try: return self.expr._parse(instring, loc, doActions, callPreParse=False) except ParseBaseException as pbe: - pbe.msg = self.errmsg + if not isinstance(self, Forward) or self.customName is not None: + pbe.msg = self.errmsg raise else: raise ParseException(instring, loc, "No expression defined", self) diff --git a/tests/test_unit.py b/tests/test_unit.py index 7c101baf..157e2952 100644 --- a/tests/test_unit.py +++ b/tests/test_unit.py @@ -9897,6 +9897,29 @@ def modify_upper(self, tokens): msg=f"unexpected exception line ({exception_line!r})", ) + + def testForwardReferenceException(self): + token = pp.Forward() + num = pp.Word(pp.nums) + num.setName("num") + text = pp.Word(pp.alphas) + text.setName("text") + fail = pp.Regex(r"\\[A-Za-z]*")("name") + def parse_fail(s, loc, toks): + raise pp.ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}") + fail.set_parse_action(parse_fail) + token <<= num | text | fail + + # If no name is given, do not intercept error messages + with self.assertRaises(pp.ParseFatalException, msg="Unknown symbol: \\fail"): + token.parse_string("\\fail") + + # If name is given, do intercept error messages + token.set_name("token") + with self.assertRaises(pp.ParseFatalException, msg="Expected token, found.*"): + token.parse_string("\\fail") + + def testMiscellaneousExceptionBits(self): pp.ParserElement.verbose_stacktrace = True