diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc index dffed2e0ff..c4eed5f480 100644 --- a/src/reader/wgsl/lexer.cc +++ b/src/reader/wgsl/lexer.cc @@ -135,13 +135,43 @@ void Lexer::skip_whitespace() { } void Lexer::skip_comments() { - if (!matches(pos_, "//")) { + if (matches(pos_, "//")) { + // Line comment: ignore everything until the end of line. + while (!is_eof() && !matches(pos_, "\n")) { + pos_++; + location_.column++; + } return; } - while (!is_eof() && !matches(pos_, "\n")) { - pos_++; - location_.column++; + if (matches(pos_, "/*")) { + // Block comment: ignore everything until the closing '*/' token. + pos_ += 2; + location_.column += 2; + + int depth = 1; + while (!is_eof() && depth > 0) { + if (matches(pos_, "/*")) { + // Start of block comment: increase nesting depth. + pos_ += 2; + location_.column += 2; + depth++; + } else if (matches(pos_, "*/")) { + // End of block comment: decrease nesting depth. + pos_ += 2; + location_.column += 2; + depth--; + } else if (matches(pos_, "\n")) { + // Newline: skip and update source location. + pos_++; + location_.line++; + location_.column = 1; + } else { + // Anything else: skip and update source location. + pos_++; + location_.column++; + } + } } } diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc index 52a6f1bd09..b134bc00af 100644 --- a/src/reader/wgsl/lexer_test.cc +++ b/src/reader/wgsl/lexer_test.cc @@ -48,7 +48,7 @@ TEST_F(LexerTest, Skips_Whitespace) { EXPECT_TRUE(t.IsEof()); } -TEST_F(LexerTest, Skips_Comments) { +TEST_F(LexerTest, Skips_Comments_Line) { Source::FileContent content(R"(//starts with comment ident1 //ends with comment // blank line @@ -75,6 +75,41 @@ ident1 //ends with comment EXPECT_TRUE(t.IsEof()); } +TEST_F(LexerTest, Skips_Comments_Block) { + Source::FileContent content(R"(/* comment +text */ident)"); + Lexer l("test.wgsl", &content); + + auto t = l.next(); + EXPECT_TRUE(t.IsIdentifier()); + EXPECT_EQ(t.source().range.begin.line, 2u); + EXPECT_EQ(t.source().range.begin.column, 8u); + EXPECT_EQ(t.source().range.end.line, 2u); + EXPECT_EQ(t.source().range.end.column, 13u); + EXPECT_EQ(t.to_str(), "ident"); + + t = l.next(); + EXPECT_TRUE(t.IsEof()); +} + +TEST_F(LexerTest, Skips_Comments_Block_Nested) { + Source::FileContent content(R"(/* comment +text // nested line comments are ignored /* more text +/////**/ */*/ident)"); + Lexer l("test.wgsl", &content); + + auto t = l.next(); + EXPECT_TRUE(t.IsIdentifier()); + EXPECT_EQ(t.source().range.begin.line, 3u); + EXPECT_EQ(t.source().range.begin.column, 14u); + EXPECT_EQ(t.source().range.end.line, 3u); + EXPECT_EQ(t.source().range.end.column, 19u); + EXPECT_EQ(t.to_str(), "ident"); + + t = l.next(); + EXPECT_TRUE(t.IsEof()); +} + struct FloatData { const char* input; float result; diff --git a/src/reader/wgsl/parser_impl_test.cc b/src/reader/wgsl/parser_impl_test.cc index a7ba36e9e3..588967e565 100644 --- a/src/reader/wgsl/parser_impl_test.cc +++ b/src/reader/wgsl/parser_impl_test.cc @@ -48,6 +48,26 @@ fn main() -> { // missing return type EXPECT_EQ(p->error(), "2:15: unable to determine function return type"); } +TEST_F(ParserImplTest, Comments) { + auto p = parser(R"( +/** + * Here is my shader. + * + * /* I can nest /**/ comments. */ + * // I can nest line comments too. + **/ +[[stage(fragment)]] // This is the stage +fn main(/* +no +parameters +*/) -> [[location(0)]] vec4 { + return/*block_comments_delimit_tokens*/vec4(.4, .2, .3, 1); +}/* unterminated block comments are OK at EOF...)"); + + ASSERT_TRUE(p->Parse()) << p->error(); + ASSERT_EQ(1u, p->program().AST().Functions().size()); +} + TEST_F(ParserImplTest, GetRegisteredType) { auto p = parser(""); auto* alias = create(Sym("my_alias"), ty.i32());