fix(parser): harden trailing if-gate splitter against "as if" riders#4933
fix(parser): harden trailing if-gate splitter against "as if" riders#4933nickmopen wants to merge 1 commit into
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
matthewevans
left a comment
There was a problem hiding this comment.
[MED] The new as if regression test drives the production CantPlayLand parser with a rules-bearing middle rider that the parser does not model or reject. Evidence: the test parses "You can't play lands as if it had flash if this creature was cast this turn." through parse_static_line_multi (crates/engine/src/parser/oracle_static/tests.rs:345-348), while the production arm accepts any line containing can't play lands (crates/engine/src/parser/oracle_static/dispatch.rs:2789-2795) and only attaches the trailing gate afterward. That means the test succeeds while silently dropping as if it had flash. Why it matters: this makes the parser look like it supports a rules-bearing rider it does not actually represent, which is coverage-dishonest support. Please either test split_trailing_gate_condition directly as a splitter unit, or use a production static whose middle as if rider is fully modeled; production parsing should not accept and erase an unmodeled rider.
This parser-surface PR also still needs the current <!-- coverage-parse-diff --> sticky before acceptance, so the card-level blast radius can be checked against the claimed scope.
Promote `split_trailing_gate_condition` (and its `split_trailing_as_long_as`
building block) from `oracle_static/dispatch.rs` to `oracle_static/shared.rs`,
and match the LAST trailing ` if ` while skipping `as if` riders instead of
anchoring on the first ` if `.
The old `take_until(" if ")` anchored on the first occurrence, so a line like
"You can't play lands as if it had flash if you control a Swamp" mis-split
inside `as if` — attaching the wrong condition or dropping the real trailing
gate. The splitter now walks each ` if ` boundary (combinator-based) and keeps
the last one whose preceding word is not "as".
Adds regression coverage for an `as if` + trailing `if` line on can't-play-lands
and extends the Rock Jockey dispatch test with card-name-normalized text.
Closes phase-rs#4876
f30a54c to
fdaf7f6
Compare
|
Good catch — fixed. Replaced the production-parser test with a direct splitter-unit test (
The Rock Jockey dispatch test (with card-name-normalized text) still exercises the real production path on a fully-modeled line. Also rebased onto current |
|
Thanks for the update. The previous false-green concern is addressed on this head: the Holding this for current-head parse-diff evidence before approval. This PR changes parser source ( |
Parse changes introduced by this PR · head
|
|
Thanks for the follow-up. I’m keeping this on hold for the current head because the parse-diff block here was supplied by the PR author, and the review loop only treats trusted workflow- or maintainer-generated parse-diff evidence as authoritative for parser-source PRs. The no-change result may be correct, but I need trusted evidence for this head before I can clear the prior review. This is especially important for parser splitter changes where the failure mode is silent parse-scope drift. |
Parse changes introduced by this PR✓ No card-parse changes detected. |
matthewevans
left a comment
There was a problem hiding this comment.
Thanks, the parser shape looks otherwise clean. One remaining repo-policy issue blocks this for me:
[LOW] New test uses an inline import despite the repo-wide no-inline-import rule. Evidence: crates/engine/src/parser/oracle_static/tests.rs:346 introduces use super::shared::split_trailing_gate_condition; inside the test body. Why it matters: project instructions require imports at file scope for readability/static analysis, and this is directly avoidable. Suggested fix: move the import to the test module imports or call super::shared::split_trailing_gate_condition(...) fully qualified.
Closes #4876.
Problem
split_trailing_gate_condition(added in #4841 for Rock Jockey'scan't play lands if …gate) usedtake_until(" if "), which anchors on the firstifin the line. On oracle text containing as if — e.g. a permission rider like "cast as if it had flash if you control a Swamp" — it mis-splits insideas if, attaching the wrong condition or dropping the real trailing gate when the building block is reused on other restriction classes.Fix
split_trailing_gate_conditionand itssplit_trailing_as_long_asbuilding block fromoracle_static/dispatch.rstooracle_static/shared.rs(parity withparse_if_static_condition/extract_cant_untap_condition), so the shared trailing-gate splitter lives with the other condition building blocks.iffallback now walks eachifboundary (combinator-basedtake_until/tagscan) and keeps the last one whose preceding word is not"as"— skippingas ifriders." as long as "is still tried first; an unrecognized condition still leaves the line unsupported rather than enforcing unconditionally.Verified behavior:
… can't play lands if this creature was cast this turnthis creature was cast this turn… can't play lands as if it had flash if you control a swampyou control a swamp… can't play lands as long as ten or more lands are on the battlefieldten or more lands are on the battlefield… can't play landsNonecast this as if it had flash(no real gate)NoneTests
cant_play_lands_gate_skips_as_if_rider— anas if+ trailingifline oncan't play landsmust bind the trailing gate.cargo test -p engine --lib→ 14,572 passed / 0 failed;cargo fmt --all --check,cargo clippy -p engine --all-targets -- -D warnings, andscripts/check-parser-combinators.shall clean.CR 611.3a (conditional statics) + CR 305.1 (land plays).