Skip to content

feat(parser): source-anchored combat-relationship subject static (Alms Beast)#5520

Merged
matthewevans merged 1 commit into
phase-rs:mainfrom
nickmopen:feat/combat-relation-subject-static
Jul 10, 2026
Merged

feat(parser): source-anchored combat-relationship subject static (Alms Beast)#5520
matthewevans merged 1 commit into
phase-rs:mainfrom
nickmopen:feat/combat-relation-subject-static

Conversation

@nickmopen

Copy link
Copy Markdown
Contributor

Problem

A self-relative combat-relationship subject failed to parse — Alms Beast: Creatures blocking or blocked by ~ have lifelink. No subject-filter arm recognized the blocking or blocked by <self> qualifier, so the whole static line dropped (static_structure Unimplemented).

The target-relative form (… blocking or blocked by target creature) is already parsed in oracle_target; only the self/source-relative static form was missing.

Fix

Strip the trailing blocking or blocked by ~ / blocking or blocked by this creature qualifier in parse_continuous_subject_filter, parse the base subject recursively, and attach a source-anchored FilterProp::CombatRelation { relation: BlockingOrBlockedBy, subject: Source }.

That FilterProp (and CombatRelationSubject::Source) is already fully evaluated at runtime by game::filter — so this is a grammar-only seam. The self-reference is normalized to ~; this creature is accepted for the literal phrasing. Mirrors the existing merged qualifier-strip pattern in the same function.

Tests

combat_relation_subject_static_binds_source_anchored_filter asserts (typed AST, both ~ and this creature forms) that the line produces a single static whose affected filter is a creature subject carrying FilterProp::CombatRelation { BlockingOrBlockedBy, Source }, with an AddKeyword { Lifelink } grant.

Local: parser::oracle_static passes; cargo fmt, clippy (-D warnings), parser-combinator + engine-authorities gates all clean.

…s Beast)

A self-relative combat-relationship subject — "Creatures blocking or
blocked by ~ have lifelink" (Alms Beast) — failed to parse: no
subject-filter arm recognized the "blocking or blocked by <self>"
qualifier, so the whole static line dropped.

Strip the trailing "blocking or blocked by ~" / "blocking or blocked by
this creature" qualifier in parse_continuous_subject_filter, parse the
base subject recursively, and attach a source-anchored
FilterProp::CombatRelation { BlockingOrBlockedBy, Source }. That prop is
already fully evaluated at runtime by game::filter (and the target-
relative form is already parsed in oracle_target), so this is a grammar-
only seam. The self-reference is normalized to "~"; "this creature" is
accepted for the literal phrasing.
@nickmopen
nickmopen requested a review from matthewevans as a code owner July 10, 2026 18:36

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for parsing combat-relationship qualifiers (specifically "blocking or blocked by ~" and "blocking or blocked by this creature") in static abilities, mapping them to a source-anchored FilterProp::CombatRelation. It also includes corresponding unit tests to verify the new parsing behavior. As there are no review comments provided, I have no further feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@github-actions

Copy link
Copy Markdown

Parse changes introduced by this PR · 1 card(s), 2 signature(s) (baseline: main 1f875c96ecbb)

1 card(s) · static/Continuous · added: Continuous (affects=combat related creature, mods=grant Lifelink)

Examples: Alms Beast

1 card(s) · ability/static_structure · removed: static_structure

Examples: Alms Beast

@matthewevans matthewevans left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — clean, well-scoped grammar work.

Verified:

  • Right seam. This adds the subject: CombatRelationSubject::Source (self-anchored) sibling of the already-parsed target-relative form in oracle_target.rs (which uses subject: ParentTarget) — same FilterProp::CombatRelation, different anchor. It's a grammar-only change.
  • Runtime authority pre-exists. game::filter already evaluates CombatRelationSubject::Source (filter.rs:3302) and CombatRelation::BlockingOrBlockedBy (filter.rs:3318), so the parsed filter is live at runtime — no new engine logic, no inert AST.
  • Combinators + suffix discipline. all_consuming(terminated(take_until(needle), tag(needle))) correctly requires the qualifier to be a true trailing suffix, and the recursion into parse_continuous_subject_filter(base) composes the base subject with the added prop.
  • Discriminating test asserts the typed structure (creature subject + source-anchored BlockingOrBlockedBy prop + lifelink grant) for both the normalized ~ and literal "this creature" phrasings — not a Debug-string dump.

Thanks — nicely mirrors the existing pattern for the static-subject case.

@matthewevans matthewevans added the enhancement New feature or request label Jul 10, 2026
@matthewevans
matthewevans added this pull request to the merge queue Jul 10, 2026
Merged via the queue into phase-rs:main with commit e768ecf Jul 10, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants