Skip to content

Commit d22bf4b

Browse files
committed
support for multi-line comments
1 parent 39107eb commit d22bf4b

File tree

2 files changed

+103
-12
lines changed

2 files changed

+103
-12
lines changed

naga/src/front/wgsl/parse/lexer.rs

+85-12
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ fn consume_any(input: &str, what: impl Fn(char) -> bool) -> (&str, &str) {
4848
/// [§3.1 Parsing]: https://gpuweb.github.io/gpuweb/wgsl/#parsing
4949
fn consume_token(input: &str, generic: bool) -> (Token<'_>, &str) {
5050
let mut chars = input.chars();
51+
let full_chars = input.chars();
5152
let cur = match chars.next() {
5253
Some(c) => c,
5354
None => return (Token::End, ""),
@@ -82,33 +83,36 @@ fn consume_token(input: &str, generic: bool) -> (Token<'_>, &str) {
8283
let og_chars = chars.as_str();
8384
match chars.next() {
8485
Some('/') => {
85-
let og_chars = chars.as_str();
8686
let documentation = if let Some(end_position) = chars.position(is_comment_end) {
87-
&og_chars[..end_position]
87+
&full_chars.as_str()[..end_position + 1]
8888
} else {
89-
og_chars
89+
full_chars.as_str()
9090
};
9191
(Token::Comment(documentation), chars.as_str())
9292
}
9393
Some('*') => {
9494
let mut depth = 1;
9595
let mut prev = None;
96-
96+
let mut nb_characters = 1;
9797
for c in &mut chars {
9898
match (prev, c) {
9999
(Some('*'), '/') => {
100100
prev = None;
101101
depth -= 1;
102+
nb_characters += 1;
102103
if depth == 0 {
103-
return (Token::Trivia, chars.as_str());
104+
let doc = &full_chars.as_str()[..nb_characters + 1];
105+
return (Token::Comment(doc), chars.as_str());
104106
}
105107
}
106108
(Some('/'), '*') => {
107109
prev = None;
108110
depth += 1;
111+
nb_characters += 1;
109112
}
110113
_ => {
111114
prev = Some(c);
115+
nb_characters += 1;
112116
}
113117
}
114118
}
@@ -309,17 +313,25 @@ impl<'a> Lexer<'a> {
309313
///
310314
/// See [`consume_token`] for the meaning of `generic`.
311315
fn next_impl(&mut self, generic: bool) -> TokenSpan<'a> {
316+
self.next_until(
317+
|token| !matches!(token, Token::Trivia | Token::Comment(_)),
318+
generic,
319+
)
320+
}
321+
322+
/// Return the next token from `self` for which `stop_at` returns true.
323+
///
324+
/// See [`consume_token`] for the meaning of `generic`.
325+
pub fn next_until(&mut self, stop_at: fn(Token) -> bool, generic: bool) -> TokenSpan<'a> {
312326
let mut start_byte_offset = self.current_byte_offset();
313327
loop {
314328
let (token, rest) = consume_token(self.input, generic);
315329
self.input = rest;
316-
match token {
317-
Token::Trivia | Token::Comment(_) => start_byte_offset = self.current_byte_offset(),
318-
_ => {
319-
self.last_end_offset = self.current_byte_offset();
320-
return (token, self.span_from(start_byte_offset));
321-
}
330+
if stop_at(token) {
331+
self.last_end_offset = self.current_byte_offset();
332+
return (token, self.span_from(start_byte_offset));
322333
}
334+
start_byte_offset = self.current_byte_offset();
323335
}
324336
}
325337

@@ -477,7 +489,11 @@ impl<'a> Lexer<'a> {
477489
fn sub_test(source: &str, expected_tokens: &[Token]) {
478490
let mut lex = Lexer::new(source);
479491
for &token in expected_tokens {
480-
assert_eq!(lex.next().0, token);
492+
assert_eq!(
493+
lex.next_until(|token| !matches!(token, Token::Trivia), false)
494+
.0,
495+
token
496+
);
481497
}
482498
assert_eq!(lex.next().0, Token::End);
483499
}
@@ -763,3 +779,60 @@ fn test_variable_decl() {
763779
],
764780
);
765781
}
782+
783+
#[test]
784+
fn test_comments() {
785+
sub_test("// Single comment", &[Token::Comment("// Single comment")]);
786+
sub_test(
787+
"/* multi
788+
line
789+
comment */",
790+
&[Token::Comment(
791+
"/* multi
792+
line
793+
comment */",
794+
)],
795+
);
796+
sub_test(
797+
"/* multi
798+
line
799+
comment */
800+
// and another",
801+
&[
802+
Token::Comment(
803+
"/* multi
804+
line
805+
comment */",
806+
),
807+
Token::Comment("// and another"),
808+
],
809+
);
810+
}
811+
812+
#[test]
813+
fn test_comment_nested() {
814+
sub_test(
815+
"/*
816+
a comment with nested one /*
817+
nested comment
818+
*/
819+
*/
820+
const a : i32 = 2;",
821+
&[
822+
Token::Comment(
823+
"/*
824+
a comment with nested one /*
825+
nested comment
826+
*/
827+
*/",
828+
),
829+
Token::Word("const"),
830+
Token::Word("a"),
831+
Token::Separator(':'),
832+
Token::Word("i32"),
833+
Token::Operation('='),
834+
Token::Number(Ok(Number::AbstractInt(2))),
835+
Token::Separator(';'),
836+
],
837+
);
838+
}

naga/src/front/wgsl/tests.rs

+18
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,24 @@ fn parse_comment() {
1414
.unwrap();
1515
}
1616

17+
#[test]
18+
fn parse_types_with_comments() {
19+
parse_str(
20+
"/*
21+
a comment with nested one /*
22+
nested comment
23+
*/
24+
*/
25+
const a : i32 = 2;",
26+
)
27+
.unwrap();
28+
let f = parse_str(
29+
"// test
30+
var t: texture_2d<f32>;",
31+
);
32+
dbg!(f).unwrap();
33+
}
34+
1735
#[test]
1836
fn parse_types() {
1937
parse_str("const a : i32 = 2;").unwrap();

0 commit comments

Comments
 (0)