Visitar URL original
yeast: Add AST for rewrite rules by tausbn · Pull Request #22786 · github/codeql · GitHub
Skip to content

yeast: Add AST for rewrite rules - #22786

Draft
tausbn wants to merge 3 commits into
mainfrom
tausbn/yeast-add-ast-for-rewrite-rules
Draft

tausbn wants to merge 3 commits into
mainfrom
tausbn/yeast-add-ast-for-rewrite-rules

Conversation

@tausbn

@tausbn tausbn commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Currently we turn rewrite rules into Rust code directly inside the macros that parse the rules themselves. This makes it somewhat difficult to keep track of what's going on, and difficult to easily extend the syntax.

This PR splits code generation into two parts. First we parse the surface syntax into a (hopefully) sensible and intuitive AST representation. This representation is then lowered into Rust source code in a separate pass.

This also means we can now test each component separately, but in order to keep the PR somewhat small, I decided not to change the tests at this time. The existing end-to-end (observing the behaviour of the compiled rules) continue to work without issue.

The first commit takes care of the tree templates -- the output part of rules, whereas the second handles the patterns we match the input CST against (the "input" to a rule).

Worth noting is the fact that templates get lowered into raw Rust code for constructing the appropriate tree (which is not entirely trivial, due to the postfix ? operator for discarding entire subtrees if they contain interpolated Nones), whereas queries/patterns are interpreted at runtime. (Compiling these into static Rust code is not entirely straightforward due to things like backtracking, and in practice query interpretation is fast enough).

This does mean there's a bit of awkwardness where patterns are concerned -- we parse them into an AST when handling the rule! macro, and then map this to an essentially equivalent Query AST for interpretation. I considered consolidating these two into a single structure, and it may be worth pursuing later, but it made it a lot harder to see what's going on in this PR, so I ultimately decided no to do it at this point.

tausbn added 2 commits October 7, 2026 11:41
Adds a structured representation of tree templates, with a lowering
operation for turning them into Rust code. Thus, instead of generating
the code directly inside the rule parser, we now create the internal
AST, and then lower it into Rust code. This makes the boundary between
parsing and code generation cleaner and easier to test.
Extends the previous work. We now explicitly split apart parsing of
rules from lowering them into Rust code.

There is some redundancy here -- a Pattern is basically the same as the
Query that we eventually execute, but cleaning that up would introduce a
lot of churn, so I've tried to leave it as-is for now.
@tausbn tausbn added the no-change-note-required This PR does not need a change note label Oct 8, 2026
@tausbn
tausbn requested a balanced review from Copilot October 8, 2026 12:55

Copilot AI 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.

🟡 Changes recommended

Captured groups containing nested repetitions can panic during macro expansion.

1 open finding
What changed in this PR

Separates Yeast rewrite-rule parsing from code generation through an intermediate AST, making the syntax easier to extend.

Changes:

  • Adds AST types and dedicated rule and template parsers.
  • Moves Rust code generation into a separate lowering pass.
  • Adds parser unit tests and enables full Rust syntax parsing.
File Description
shared/​yeast-macros/​src/​template_parse.rs Parses output templates into AST nodes.
shared/​yeast-macros/​src/​rule_parse.rs Parses patterns, guards, captures, and replacements.
shared/​yeast-macros/​src/​parse.rs Delegates macro entry points to parsing and lowering.
shared/​yeast-macros/​src/​lower.rs Generates Rust code from the AST.
shared/​yeast-macros/​src/​lib.rs Registers modules and updates query documentation.
shared/​yeast-macros/​src/​ast.rs Defines the intermediate AST.
shared/​yeast-macros/​Cargo.toml Enables Syn’s full feature.

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment thread shared/yeast-macros/src/rule_parse.rs
This is a weird pattern (that we don't use) that had weird semantics
previously.

A minimal example would be something like

```
((item)* (separator))* @Items
```

Here, it's not really clear what @Items should be capturing. The current
implementation (post-AST rewrite) simply panics at compile-time, with a
message that may or may not be helpful. As the Copilot review correctly
points out, this is a regression compared to the previous behaviour
(which dealt with the issue by just throwing away the `(item)*` bit).
This compiled, but I don't think the old behaviour is particularly
sensible either.

For that reason, we now explicitly warn that capturing a group
containing a nested repetition is an error.

At present, we never employ the above pattern in our code. If this
changes, then we'll likely want to provide a sensible semantics for this
case rather than just panicking.

Copilot AI 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.

🔵 Needs a closer look

The macro-wide refactor has unresolved capture-binding regressions and requires human validation of syntax and expansion compatibility.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced


Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.

Comment on lines +247 to +251
Pattern::Sequence(patterns) => Pattern::Sequence(
patterns
.into_iter()
.map(|pattern| Pattern::Capture {
capture: capture.clone(),

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-change-note-required This PR does not need a change note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants