Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(css_parser): introduce grit metavariable #3340

Merged
merged 18 commits into from
Jul 9, 2024
Merged

Conversation

ah-yu
Copy link
Contributor

@ah-yu ah-yu commented Jul 3, 2024

@github-actions github-actions bot added A-Project Area: project A-Parser Area: parser A-Formatter Area: formatter A-Tooling Area: internal tools L-CSS Language: CSS labels Jul 3, 2024
Copy link

codspeed-hq bot commented Jul 3, 2024

CodSpeed Performance Report

Merging #3340 will degrade performances by 20.68%

Comparing ah-yu:feat/metavar (89ee4bb) with main (29280e3)

Summary

❌ 1 regressions
✅ 107 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark main ah-yu:feat/metavar Change
eucjp_4223654609205405644.json[uncached] 965 µs 1,216.6 µs -20.68%

@denbezrukov
Copy link
Contributor

Great start!

I'm wondering if we can solve the problem in general. It seems all we need is to have a node that can be anywhere and not raise an invalid syntax error. We already have a bogus node type that can be anywhere in the tree; however, it produces a tree with errors.

What do you think about having something like a bogus type that doesn't break the syntax tree?

@ah-yu
Copy link
Contributor Author

ah-yu commented Jul 3, 2024

What do you think about having something like a bogus type that doesn't break the syntax tree?

Sounds good! However, I am wondering if it will meet the needs of the plugin side, as they would like to know the exact node type of metavariable. @arendjr

/// Returns the syntax kind for metavariables.
fn metavariable_kind() -> Self::Kind;

@arendjr
Copy link
Contributor

arendjr commented Jul 3, 2024

However, I am wondering if it will meet the needs of the plugin side, as they would like to know the exact node type of metavariable.

We do need to be able to check for the node type indeed. But as long as it’s a distinct kind that should be covered.

I’m just not entirely sure how I should understand this sentence:

It seems all we need is to have a node that can be anywhere and not raise an invalid syntax error

How does that differ from the current metavariable implementation exactly? We can let it appear anywhere we want and it doesn’t raise an error. I guess the subtlety lies in how we make it appear where we want? I would be fine with an alternative approach to using specialized syntax (like the μ character), but I’m not sure I see a better way?

@denbezrukov
Copy link
Contributor

However, I am wondering if it will meet the needs of the plugin side, as they would like to know the exact node type of metavariable.

We do need to be able to check for the node type indeed. But as long as it’s a distinct kind that should be covered.

I’m just not entirely sure how I should understand this sentence:

It seems all we need is to have a node that can be anywhere and not raise an invalid syntax error

How does that differ from the current metavariable implementation exactly? We can let it appear anywhere we want and it doesn’t raise an error. I guess the subtlety lies in how we make it appear where we want? I would be fine with an alternative approach to using specialized syntax (like the μ character), but I’m not sure I see a better way?

I agree, but I have slight concerns that we would have to adjust the grammar in many places to include CssGritMetavariable because we want to have it almost anywhere in the syntax tree.

I'm trying to understand if it's possible to implement something similar to what we have for the bogus node.

@ematipico
Copy link
Member

I'm with @denbezrukov on this one. Considering the approach of the metavariables (grit is one, and we will have more too, and they will be sparse across languages), I believe we should strike for a more generic approach using known nodes, very much like the bogus nodes.

We've done this for other nodes, such as Any*, *List, and *Bogus. *Meta could be just one of them.

@ah-yu
Copy link
Contributor Author

ah-yu commented Jul 4, 2024

If I understand correctly, @denbezrukov and @ematipico are proposing something like the following:

CssMetaValue = CssGritMetavar | AnotherQueryLanguageMetavar
CssMetaSelector = CssGritMetavar | AnotherQueryLanguageMetavar

AnyCssValue = 
    ...
    CssMetaValue

AnyCssSelector = 
    ...
    CssMetaSelector

Is that correct?

@arendjr
Copy link
Contributor

arendjr commented Jul 4, 2024

Yes, I think that’s the gist of it. And now I see what @denbezrukov meant, I agree too. It would be best if we had a more generic way of handling these. Probably the solution indeed is that we should be able to specify in the .ungram where they might occur and then the codegen should pretty much take care of the rest.

@denbezrukov
Copy link
Contributor

We can try to improve it in another PR:)

@@ -1326,6 +1353,7 @@ impl<'src> ReLexer<'src> for CssLexer<'src> {
Some(current) => match context {
CssReLexContext::Regular => self.consume_token(current),
CssReLexContext::UnicodeRange => self.consume_unicode_range_token(current),
CssReLexContext::GritMetavariable => self.re_lex_grit_metavariable(old_position),
Copy link
Member

Choose a reason for hiding this comment

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

Why "re lex" and not "consume"? I don't see any re lexing inside the code

@@ -1315,6 +1317,31 @@ impl<'src> CssLexer<'src> {
_ => false,
}
}

fn re_lex_grit_metavariable(&mut self, current_end: usize) -> CssSyntaxKind {
Copy link
Member

Choose a reason for hiding this comment

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

If we have the same logic inside JavaScript, this function should become part of the lexer trait. Not a blocker

// After parsing the compound selector, it then checks if this compound selector is a part of a complex selector.
parse_compound_selector(p).and_then(|selector| parse_complex_selector(p, selector))
if p.options().is_grit_metavariable_enabled() {
p.re_lex(CssReLexContext::GritMetavariable);
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure we need the re-lexing here, because we aren't doing any backwards operation. Instead, you should use parsing with a different context

Copy link
Contributor

Choose a reason for hiding this comment

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

We could try to move this logic inside the lexer.
By passing a new option to the lexer and, without any additional context, if the next token is μ (Επιτέλους, τα ελληνικά μου ήταν χρήσιμα!) and the option is enabled, we can process it as a meta variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Make sense. Addressed in 0ca8bd9

@ah-yu ah-yu requested a review from ematipico July 9, 2024 02:23
@ah-yu ah-yu requested a review from Sec-ant July 9, 2024 07:19
Copy link
Member

@Sec-ant Sec-ant left a comment

Choose a reason for hiding this comment

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

Just another nitpick, thanks!

crates/biome_css_parser/src/parser.rs Outdated Show resolved Hide resolved
@ah-yu ah-yu merged commit a77c00b into biomejs:main Jul 9, 2024
12 of 13 checks passed
@ah-yu ah-yu deleted the feat/metavar branch July 9, 2024 08:41
@Conaclos Conaclos added the A-Changelog Area: changelog label Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Changelog Area: changelog A-Formatter Area: formatter A-Parser Area: parser A-Project Area: project A-Tooling Area: internal tools L-CSS Language: CSS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants