Terminate line comments with \v, \f, and \r
The WGSL spec says that line comments are terminated by any blankspace other than a space or a horizontal tab. Also rename is_whitespace to is_blankspace and tighten up the definition to only include the characters listed in the WGSL spec. Change-Id: I4fee0175980ab70e9baf107a6e79ab5c2e4f906d Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/83920 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: James Price <jrprice@google.com>
This commit is contained in:
parent
2a761f736a
commit
453d5ae84e
|
@ -28,8 +28,10 @@ namespace reader {
|
||||||
namespace wgsl {
|
namespace wgsl {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool is_whitespace(char c) {
|
bool is_blankspace(char c) {
|
||||||
return std::isspace(static_cast<unsigned char>(c));
|
// See https://www.w3.org/TR/WGSL/#blankspace.
|
||||||
|
return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
|
||||||
|
c == '\r';
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t dec_value(char c) {
|
uint32_t dec_value(char c) {
|
||||||
|
@ -62,7 +64,7 @@ Lexer::Lexer(const Source::File* file)
|
||||||
Lexer::~Lexer() = default;
|
Lexer::~Lexer() = default;
|
||||||
|
|
||||||
Token Lexer::next() {
|
Token Lexer::next() {
|
||||||
if (auto t = skip_whitespace_and_comments(); !t.IsUninitialized()) {
|
if (auto t = skip_blankspace_and_comments(); !t.IsUninitialized()) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,10 +130,10 @@ bool Lexer::matches(size_t pos, std::string_view substr) {
|
||||||
return file_->content.data_view.substr(pos, substr.size()) == substr;
|
return file_->content.data_view.substr(pos, substr.size()) == substr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token Lexer::skip_whitespace_and_comments() {
|
Token Lexer::skip_blankspace_and_comments() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto pos = pos_;
|
auto pos = pos_;
|
||||||
while (!is_eof() && is_whitespace(file_->content.data[pos_])) {
|
while (!is_eof() && is_blankspace(file_->content.data[pos_])) {
|
||||||
if (matches(pos_, "\n")) {
|
if (matches(pos_, "\n")) {
|
||||||
pos_++;
|
pos_++;
|
||||||
location_.line++;
|
location_.line++;
|
||||||
|
@ -148,7 +150,7 @@ Token Lexer::skip_whitespace_and_comments() {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the cursor didn't advance we didn't remove any whitespace
|
// If the cursor didn't advance we didn't remove any blankspace
|
||||||
// so we're done.
|
// so we're done.
|
||||||
if (pos == pos_)
|
if (pos == pos_)
|
||||||
break;
|
break;
|
||||||
|
@ -162,9 +164,10 @@ Token Lexer::skip_whitespace_and_comments() {
|
||||||
|
|
||||||
Token Lexer::skip_comment() {
|
Token Lexer::skip_comment() {
|
||||||
if (matches(pos_, "//")) {
|
if (matches(pos_, "//")) {
|
||||||
// Line comment: ignore everything until the end of line
|
// Line comment: ignore everything until the end of input or a blankspace
|
||||||
// or end of input.
|
// character other than space or horizontal tab.
|
||||||
while (!is_eof() && !matches(pos_, "\n")) {
|
while (!is_eof() && !(is_blankspace(file_->content.data[pos_]) &&
|
||||||
|
!matches(pos_, " ") && !matches(pos_, "\t"))) {
|
||||||
if (is_null()) {
|
if (is_null()) {
|
||||||
return {Token::Type::kError, begin_source(), "null character found"};
|
return {Token::Type::kError, begin_source(), "null character found"};
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,9 @@ class Lexer {
|
||||||
Token next();
|
Token next();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Advances past whitespace and comments, if present
|
/// Advances past blankspace and comments, if present at the current position.
|
||||||
/// at the current position.
|
|
||||||
/// @returns error token, EOF, or uninitialized
|
/// @returns error token, EOF, or uninitialized
|
||||||
Token skip_whitespace_and_comments();
|
Token skip_blankspace_and_comments();
|
||||||
/// Advances past a comment at the current position, if one exists.
|
/// Advances past a comment at the current position, if one exists.
|
||||||
/// Returns an error if there was an unterminated block comment,
|
/// Returns an error if there was an unterminated block comment,
|
||||||
/// or a null character was present.
|
/// or a null character was present.
|
||||||
|
|
|
@ -32,7 +32,7 @@ TEST_F(LexerTest, Empty) {
|
||||||
EXPECT_TRUE(t.IsEof());
|
EXPECT_TRUE(t.IsEof());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LexerTest, Skips_Whitespace) {
|
TEST_F(LexerTest, Skips_Blankspace) {
|
||||||
Source::File file("", "\t\r\n\t ident\t\n\t \r ");
|
Source::File file("", "\t\r\n\t ident\t\n\t \r ");
|
||||||
Lexer l(&file);
|
Lexer l(&file);
|
||||||
|
|
||||||
|
@ -75,6 +75,43 @@ ident1 //ends with comment
|
||||||
EXPECT_TRUE(t.IsEof());
|
EXPECT_TRUE(t.IsEof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using LineCommentTerminatorTest = testing::TestWithParam<char>;
|
||||||
|
TEST_P(LineCommentTerminatorTest, Terminators) {
|
||||||
|
// Test that line comments are ended by blankspace characters other than space
|
||||||
|
// and horizontal tab.
|
||||||
|
char c = GetParam();
|
||||||
|
std::string src = "let// This is a comment";
|
||||||
|
src += c;
|
||||||
|
src += "ident";
|
||||||
|
Source::File file("", src);
|
||||||
|
Lexer l(&file);
|
||||||
|
|
||||||
|
auto t = l.next();
|
||||||
|
EXPECT_TRUE(t.Is(Token::Type::kLet));
|
||||||
|
EXPECT_EQ(t.source().range.begin.line, 1u);
|
||||||
|
EXPECT_EQ(t.source().range.begin.column, 1u);
|
||||||
|
EXPECT_EQ(t.source().range.end.line, 1u);
|
||||||
|
EXPECT_EQ(t.source().range.end.column, 4u);
|
||||||
|
|
||||||
|
if (c != ' ' && c != '\t') {
|
||||||
|
size_t line = c == '\n' ? 2u : 1u;
|
||||||
|
size_t col = c == '\n' ? 1u : 25u;
|
||||||
|
t = l.next();
|
||||||
|
EXPECT_TRUE(t.IsIdentifier());
|
||||||
|
EXPECT_EQ(t.source().range.begin.line, line);
|
||||||
|
EXPECT_EQ(t.source().range.begin.column, col);
|
||||||
|
EXPECT_EQ(t.source().range.end.line, line);
|
||||||
|
EXPECT_EQ(t.source().range.end.column, col + 5);
|
||||||
|
EXPECT_EQ(t.to_str(), "ident");
|
||||||
|
}
|
||||||
|
|
||||||
|
t = l.next();
|
||||||
|
EXPECT_TRUE(t.IsEof());
|
||||||
|
}
|
||||||
|
INSTANTIATE_TEST_SUITE_P(LexerTest,
|
||||||
|
LineCommentTerminatorTest,
|
||||||
|
testing::Values(' ', '\t', '\n', '\v', '\f', '\r'));
|
||||||
|
|
||||||
TEST_F(LexerTest, Skips_Comments_Block) {
|
TEST_F(LexerTest, Skips_Comments_Block) {
|
||||||
Source::File file("", R"(/* comment
|
Source::File file("", R"(/* comment
|
||||||
text */ident)");
|
text */ident)");
|
||||||
|
@ -128,7 +165,7 @@ abcd)");
|
||||||
EXPECT_EQ(t.source().range.end.column, 4u);
|
EXPECT_EQ(t.source().range.end.column, 4u);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LexerTest, Null_InWhitespace_IsError) {
|
TEST_F(LexerTest, Null_InBlankspace_IsError) {
|
||||||
Source::File file("", std::string{' ', 0, ' '});
|
Source::File file("", std::string{' ', 0, ' '});
|
||||||
Lexer l(&file);
|
Lexer l(&file);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ class TextGenerator {
|
||||||
public:
|
public:
|
||||||
/// Line holds a single line of text
|
/// Line holds a single line of text
|
||||||
struct Line {
|
struct Line {
|
||||||
/// The indentation of the line in whitespaces
|
/// The indentation of the line in blankspace
|
||||||
uint32_t indent = 0;
|
uint32_t indent = 0;
|
||||||
/// The content of the line, without a trailing newline character
|
/// The content of the line, without a trailing newline character
|
||||||
std::string content;
|
std::string content;
|
||||||
|
|
Loading…
Reference in New Issue