{"record":{"id":"5ffad02c9f86a0ec","repo":"antlr/antlr4","slug":"precpred-ctx","errorCode":null,"errorMessage":"precpred(_ctx, {})","messagePattern":"precpred\\(_ctx, (.+?)\\)","errorType":"exception","errorClass":"FailedPredicateException","httpStatus":null,"severity":"error","filePath":"runtime/Python3/src/antlr4/ParserInterpreter.py","lineNumber":153,"sourceCode":"            if ruleStartState.isPrecedenceRule:\n                self.enterRecursionRule(ctx, ruleStartState.stateNumber, ruleIndex, transition.precedence)\n            else:\n                self.enterRule(ctx, transition.target.stateNumber, ruleIndex)\n\n        elif tt==Transition.PREDICATE:\n\n            if not self.sempred(self._ctx, transition.ruleIndex, transition.predIndex):\n                raise FailedPredicateException(self)\n\n        elif tt==Transition.ACTION:\n\n            self.action(self._ctx, transition.ruleIndex, transition.actionIndex)\n\n        elif tt==Transition.PRECEDENCE:\n\n            if not self.precpred(self._ctx, transition.precedence):\n                msg = \"precpred(_ctx, \" + str(transition.precedence) + \")\"\n                raise FailedPredicateException(self, msg)\n\n        else:\n            raise UnsupportedOperationException(\"Unrecognized ATN transition type.\")\n\n        self.state = transition.target.stateNumber\n\n    def visitRuleStopState(self, p:ATNState):\n        ruleStartState = self.atn.ruleToStartState[p.ruleIndex]\n        if ruleStartState.isPrecedenceRule:\n            parentContext = self._parentContextStack.pop()\n            self.unrollRecursionContexts(parentContext.a)\n            self.state = parentContext[1]\n        else:\n            self.exitRule()\n\n        ruleTransition = self.atn.states[self.state].transitions[0]\n        self.state = ruleTransition.followState.stateNumber\n","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Python3/src/antlr4/ParserInterpreter.py#L135-L171","documentation":"ParserInterpreter handles PRECEDENCE transitions by calling precpred(ctx, precedence); when the check fails it raises FailedPredicateException with the message 'precpred(_ctx, <n>)'. This is the left-recursion precedence mechanism: in an ambiguous left-recursive expression, the interpreter asked whether a sub-expression may continue at precedence level n and the answer was no.","triggerScenarios":"Interpreting a grammar with left-recursive expression rules where the precedence walk fails — usually because the interpreter's precedence bookkeeping (the _p precedence stack maintained by generated parsers via enterRecursionRule/unrollRecursionContexts) is out of sync; custom overrides of precpred returning false; ATN deserialized with options that alter precedence transitions.","commonSituations":"Grammar prototyping with ParserInterpreter on expression grammars; runtime/tool version mismatch producing an ATN the interpreter walks incorrectly; subclassed interpreters overriding precpred or recursion-context hooks incorrectly.","solutions":["Do not override precpred/enterRecursionRule/unrollRecursionContexts in interpreter subclasses unless replicating generated-parser semantics exactly","Ensure the tool version that produced the serialized ATN matches the runtime version interpreting it","If the input itself is genuinely invalid for the precedence rules, validate/catch FailedPredicateException and report a syntax error instead of letting it propagate","For production parsing of left-recursive grammars, use the generated parser rather than the interpreter"],"exampleFix":"# before\nclass MyInterp(ParserInterpreter):\n    def precpred(self, ctx, precedence):\n        return False  # breaks left-recursion: raises precpred(_ctx, n)\n\n# after\nclass MyInterp(ParserInterpreter):\n    pass  # inherit default: return self.precpred(ctx, precedence) semantics intact","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from antlr4.error.Errors import FailedPredicateException\ntry:\n    tree = interpreter.parse(start_rule)\nexcept FailedPredicateException as ex:\n    if \"precpred\" in (ex.msg or \"\"):\n        # precedence walk failed: verify tool/runtime versions match, then reparse with generated parser\n        raise SyntaxError(\"interpreter precedence failure: \" + str(ex.msg)) from ex\n    raise","preventionTips":["Never override precpred or recursion-context hooks in interpreter subclasses","Keep tool and runtime versions in lockstep, especially for left-recursive grammars","Smoke-test interpreter runs on small expression samples after any ANTLR upgrade"],"tags":["antlr","python","parser-interpreter","left-recursion","precedence"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}