Repository navigation
A rec pass that never settles is stopped with a message (4.2.47) - #803
Merged
Merged
Conversation
This was referenced Oct 26, 2026
ddehilster
force-pushed
the
fix/rec-limit
branch
from
October 26, 2026 20:00
c2a1250 to
9065750
Compare
A rec pass repeats a region while any rule matches. A rule that keeps matching without changing what it matched loops forever: parse-en-us hung on "much I have been to blame." (fixed in parse-en-us VisualText#10), with nothing on the console. RecinfLoop (2005) only counts a match that rebuilds a node over the same span, and skips one that regroups or excises, so it never saw this one; the basic RecmatchNodes has no check at all. All four rec match loops now count matches per region. Past the limit the region is stopped, the rest of the pass goes on, and one line goes to stderr and err.log, once per input for each pass and rule: [Error in rec pass 75 (pos50): rules matched 1120 times in a region of 6 nodes without settling, so the region was stopped there. Last rule to match: line 15004. Input: .../w1.txt. NLP_REC_LIMIT sets the limit; 0 lifts it.] The limit is 1,000 matches plus 20 per node in the region. Measured over all 18 analyzers in the analyzers repo and a 738 KB novel, no region took more than 2.3 matches a node. NLP_REC_LIMIT scales it (the default is 1000) and 0 lifts it. The engine's own rules-file grammar is not limited: it reads a whole pass file as one region (pos50.nlp is ~25,000 matches), so Parse::rulesFile_ marks those parses. CI: tests/rec-limit has a rec pass that takes 3 matches in a 6-node region. At the default it runs silently; at NLP_REC_LIMIT=1 it is stopped at 2 with the message and the next pass still runs. On master that check fails (matches=3, no message). Checked: all Windows fixture steps pass; parse-en-us output on its three inputs is byte-identical to master's (454 files); no limit errors on any of the 18 analyzers or the novel; the unfixed parse-en-us now stops in about a second where it hung. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ddehilster
force-pushed
the
fix/rec-limit
branch
from
October 26, 2026 20:24
9065750 to
f765a54
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A
recpass repeats a region while any rule matches. A rule that keeps matching without changing what it matched loops forever, and nothing appears on the console. parse-en-us hung this way on "much I have been to blame." (fixed in VisualText/parse-en-us#10). I found it when Pride and Prejudice never finished.The engine already has a loop check,
RecinfLoopfrom 2005, but it didn't catch this:RecmatchNodesvariant has no check at all;err.logand abandons the whole pass.Change
All four
recmatch loops now count matches per region. Past the limit, the region is stopped, the rest of the pass goes on, and one line goes to stderr anderr.log, once per input for each pass and rule:Limit: 1,000 matches plus 20 per node in the region. I measured the largest match-to-node ratio in any region across all 18 analyzers in the analyzers repo and the 738 KB novel:
So the per-node allowance is about nine times the worst case seen. The fixed 1,000 covers small regions.
NLP_REC_LIMITscales the limit (default 1000), and0turns it off.data/rfb) isn't limited. It reads a whole pass file as one region: loading the 17,226-linepos50.nlptakes about 25,000 matches. A newParse::rulesFile_flag, set inrfa.cpp, marks those parses.Tests
tests/rec-limit: arecpass that takes 3 matches in a 6-node region. The new CI step on Windows, Linux and macOS checks that:matches=3);NLP_REC_LIMIT=1it is stopped at 2, with the message, and the next pass still runs.matches=3, no message.pos50) and rule line 15004, where before it hung forever.Version 4.2.47 (rebased onto 4.2.45, zone mode). #802 is 4.2.46; whichever merges second needs its version line rebased. I plan to release both under one tag.
🤖 Generated with Claude Code