Skip to content

Allow some query predicate operators to apply to final capture #1778

@pokey

Description

@pokey

The problem

The following query doesn't work:

(
  (aaa) @bbb.start
  (ccc) @bbb.end
  (#insertion-delimiter! @bbb ", ")
)

because at the point that insertion-delimiter! query predicate operator is run, the @bbb.start and @bbb.end captures haven't yet been merged into @bbb, so it complains that the @bbb capture doesn't exist. Instead, you have to do

(
  (aaa) @bbb.start
  (ccc) @bbb.end
  (#insertion-delimiter! @bbb.start ", ")
)

(or @bbb.end), which is a bit awkward, and annoying if you refactor your pattern to go from @bbb to @bbb.start or vice-versa.

The solution

Instead, we should allow referring to the final node for certain captures.

I don't think we want this for all captures, though, because for example

(
  (aaa
    (ccc) @bbb.end
  ) @bbb.start.startOf
  (#not-parent-type! @bbb.start.startOf ddd)
)

In this case, we want to refer to one side of the @bbb range constructor specifically. Although arguably for this case we could add a new @dummy node

(
  (aaa
    (ccc) @bbb.end
  ) @bbb.start.startOf @dummy
  (#not-parent-type! @dummy ddd)
)

which might make things clearer.

Another problem is that you can't really refer to the capture's parse-tree node if it's the result of constructing a range, because then there are actually two nodes: start and end.

One possible solution to all of the above:

  • You can always refer to the full name @bbb.start.startOf or to the name without .startOf / .endOf. I don't think there's ever ambiguity there. The only potential problem with omitting the .startOf is that I'm not sure we will have updated the range yet, so might be a bit ambiguous what you'd expect the query predicate operator to see 🤔. I guess we could do the same thing I'm proposing in the next bullet, and just throw an error if you access range for now
  • If you refer to @bbb and we only find @bbb.start and/or @bbb.end, then we construct a dummy capture object that throws an exception if the query predicate operator tries to access range or node. That will be fine for insertion-delimiter! and allow-multiple!, which are the only two use cases I've run into. I guess the easiest thing is for the dummy object to mirror your property writes to one of @bbb.start or @bbb.end, as those get merged in the end
    • It would be nice if it were strongly typed instead of raising an exception, but that might be extra credit

Metadata

Metadata

Assignees

No one assigned

    Labels

    code qualityImprovements to code quality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions