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: graphql lexer #2271

Merged
merged 11 commits into from
Apr 5, 2024
Merged

Conversation

vohoanglong0107
Copy link
Contributor

Summary

Implement a Lexer for GraphQL
This PR also include a minimal parser to demonstrate that things work

Test Plan

All the tests for GraphQL lexer and parser pass

@github-actions github-actions bot added the A-Tooling Area: internal tools label Apr 2, 2024
Copy link

netlify bot commented Apr 2, 2024

Deploy Preview for biomejs ready!

Name Link
🔨 Latest commit 23546e5
🔍 Latest deploy log https://app.netlify.com/sites/biomejs/deploys/660f64d87b0d6600083accf6
😎 Deploy Preview https://deploy-preview-2271--biomejs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 99 (🟢 up 5 from production)
Accessibility: 97 (no change from production)
Best Practices: 100 (no change from production)
SEO: 93 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

codspeed-hq bot commented Apr 2, 2024

CodSpeed Performance Report

Merging #2271 will improve performances by 11.8%

Comparing vohoanglong0107:feat-graphql-lexer (23546e5) with main (2bd95dc)

Summary

⚡ 1 improvements
✅ 92 untouched benchmarks

Benchmarks breakdown

Benchmark main vohoanglong0107:feat-graphql-lexer Change
big5-added.json[cached] 2.4 ms 2.1 ms +11.8%

Copy link
Contributor

@arendjr arendjr left a comment

Choose a reason for hiding this comment

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

I still see two todo!(), but other than that, LGTM!

Note that for the Grit lexer, I have also just left an unimplemented!() inside the rewind() method. That probably works here as well.

}
}

fn is_name_start(byte: u8) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if we can use some functions from crates/biome_unicode_table/src/lib.rs here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so, those function support unicode characters while graphql identity only allow ascii

Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

I looked at the code, and overall, it seems fine, although I found a few things we should avoid doing in production. Would you mind addressing them?

}

fn rewind(&mut self, _checkpoint: LexerCheckpoint<Self::Kind>) {
todo!();
Copy link
Member

@ematipico ematipico Apr 3, 2024

Choose a reason for hiding this comment

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

Instead of todo, you should use unimplemented! and provide a brief explanation


/// Lexes an ellipsis.
fn consume_ellipsis(&mut self) -> GraphqlSyntaxKind {
assert_eq!(self.current_byte(), Some(b'.'));
Copy link
Member

Choose a reason for hiding this comment

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

We don't want to ship assertion in production. You should use debug_assert_eq

}

fn consume_digit(&mut self, chr: u8, state: LexNumberState) -> LexNumberState {
assert!(chr.is_ascii_digit());
Copy link
Member

Choose a reason for hiding this comment

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

No assertion in production. You should use debug_assert

}
}

fn consume_digit(&mut self, chr: u8, state: LexNumberState) -> LexNumberState {
Copy link
Member

Choose a reason for hiding this comment

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

What's the difference between a digit and a number? It's worth adding a comment that briefly explains it. Also, LexNumberState should be called LexDigitState, to avoid confusion.

}

fn consume_string(&mut self) -> GraphqlSyntaxKind {
assert_eq!(self.current_byte(), Some(b'"'));
Copy link
Member

Choose a reason for hiding this comment

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

use debug_assert

start: TextSize,
state: LexNumberState,
) -> LexNumberState {
assert!(matches!(chr, b'e' | b'E'));
Copy link
Member

Choose a reason for hiding this comment

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

use debug_assert

let diagnostic = ParseDiagnostic::new(
"Invalid escape sequence",
escape_start..self.text_position() + c.text_len(),
).with_hint(r#"Valid escape sequences are: `\\`, `\/`, `/"`, `\b\`, `\f`, `\n`, `\r`, `\t` or any unicode escape sequence `\uXXXX` where X is hexedecimal number. "#);
Copy link
Member

Choose a reason for hiding this comment

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

Consider using with_alternatives to present a list of things to the user instead.

(state, Some(diagnostic))
}
}
_ => panic!("String uninitialized/terminated"),
Copy link
Member

Choose a reason for hiding this comment

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

We don't want to panic in production. Consider using a safe approach, maybe by emitting a diagnostic and/or using consume_unexpecated_character

}

fn consume_comment(&mut self) -> GraphqlSyntaxKind {
assert_eq!(self.current_byte(), Some(b'#'));
Copy link
Member

Choose a reason for hiding this comment

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

use debug_assert_eq


#[inline]
fn parse_selection_set(p: &mut GraphqlParser) -> ParsedSyntax {
if !p.at(T!['{']) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to propose removing this conditional because doing so would enable parsing of an invalid syntax without losing the set in the absence of {.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean something like this?

fn parse_selection_set(p: &mut GraphqlParser) -> ParsedSyntax {
  if !p.eat(T!['{']) {p.error("Expected `{` here")}

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes,
I believe that we have 'p.expect(T![token])'🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you check it again e86a331

Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

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

Looks good. Just a few nits to address and we can merge it :)

let m = p.start();
p.expect(T!['{']);
SelectionList::new().parse_list(p);
p.bump(T!['}']);
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, it looks good!

Sorry, I forgot to mention that we also need to use expect here. It seems we need to check the at/at_ts token and call bump to ensure that we don't encounter a panic in production.

Suggested change
p.bump(T!['}']);
p.expect(T!['}']);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I understand. I didn't notice bump panic if the token was not found

Copy link
Contributor

@denbezrukov denbezrukov left a comment

Choose a reason for hiding this comment

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

🙏

@ematipico ematipico merged commit 2b19194 into biomejs:main Apr 5, 2024
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Tooling Area: internal tools
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants