Produce end ranges for tokens and AST nodes
This includes a couple of position fixes in `lexer.cc`.
The source for identifiers (vars, params, etc) now refer to the identifier, not the first token of the construct.
Bug: tint:282
Change-Id: I58cb8422a4af1c7dc5f84431fd7f06b823b514c5
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/31444
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/decorated_variable_test.cc b/src/ast/decorated_variable_test.cc
index 3774d1c..c5db5af 100644
--- a/src/ast/decorated_variable_test.cc
+++ b/src/ast/decorated_variable_test.cc
@@ -42,10 +42,12 @@
EXPECT_EQ(dv.type(), &t);
EXPECT_EQ(dv.source().range.begin.line, 0u);
EXPECT_EQ(dv.source().range.begin.column, 0u);
+ EXPECT_EQ(dv.source().range.end.line, 0u);
+ EXPECT_EQ(dv.source().range.end.column, 0u);
}
TEST_F(DecoratedVariableTest, CreationWithSource) {
- Source s{Source::Location{27, 4}};
+ Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}};
type::F32Type t;
auto var = std::make_unique<Variable>(s, "i", StorageClass::kPrivate, &t);
DecoratedVariable dv(std::move(var));
@@ -55,6 +57,8 @@
EXPECT_EQ(dv.type(), &t);
EXPECT_EQ(dv.source().range.begin.line, 27u);
EXPECT_EQ(dv.source().range.begin.column, 4u);
+ EXPECT_EQ(dv.source().range.end.line, 27u);
+ EXPECT_EQ(dv.source().range.end.column, 5u);
}
TEST_F(DecoratedVariableTest, NoDecorations) {
diff --git a/src/ast/discard_statement_test.cc b/src/ast/discard_statement_test.cc
index 4a9e779..9433421 100644
--- a/src/ast/discard_statement_test.cc
+++ b/src/ast/discard_statement_test.cc
@@ -28,12 +28,17 @@
DiscardStatement stmt;
EXPECT_EQ(stmt.source().range.begin.line, 0u);
EXPECT_EQ(stmt.source().range.begin.column, 0u);
+ EXPECT_EQ(stmt.source().range.end.line, 0u);
+ EXPECT_EQ(stmt.source().range.end.column, 0u);
}
TEST_F(DiscardStatementTest, Creation_WithSource) {
- DiscardStatement stmt(Source{Source::Location{20, 2}});
+ DiscardStatement stmt(
+ Source{Source::Range{Source::Location{20, 2}, Source::Location{20, 5}}});
EXPECT_EQ(stmt.source().range.begin.line, 20u);
EXPECT_EQ(stmt.source().range.begin.column, 2u);
+ EXPECT_EQ(stmt.source().range.end.line, 20u);
+ EXPECT_EQ(stmt.source().range.end.column, 5u);
}
TEST_F(DiscardStatementTest, IsDiscard) {
diff --git a/src/ast/fallthrough_statement_test.cc b/src/ast/fallthrough_statement_test.cc
index e1ed7f2..9552627 100644
--- a/src/ast/fallthrough_statement_test.cc
+++ b/src/ast/fallthrough_statement_test.cc
@@ -26,6 +26,8 @@
FallthroughStatement stmt;
EXPECT_EQ(stmt.source().range.begin.line, 0u);
EXPECT_EQ(stmt.source().range.begin.column, 0u);
+ EXPECT_EQ(stmt.source().range.end.line, 0u);
+ EXPECT_EQ(stmt.source().range.end.column, 0u);
}
TEST_F(FallthroughStatementTest, Creation_WithSource) {
diff --git a/src/ast/struct_member_test.cc b/src/ast/struct_member_test.cc
index d20ef7b..f74856a 100644
--- a/src/ast/struct_member_test.cc
+++ b/src/ast/struct_member_test.cc
@@ -39,11 +39,13 @@
EXPECT_TRUE(st.decorations()[0]->IsOffset());
EXPECT_EQ(st.source().range.begin.line, 0u);
EXPECT_EQ(st.source().range.begin.column, 0u);
+ EXPECT_EQ(st.source().range.end.line, 0u);
+ EXPECT_EQ(st.source().range.end.column, 0u);
}
TEST_F(StructMemberTest, CreationWithSource) {
type::I32Type i32;
- Source s{Source::Location{27, 4}};
+ Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}};
StructMember st{s, "a", &i32, {}};
EXPECT_EQ(st.name(), "a");
@@ -51,6 +53,8 @@
EXPECT_EQ(st.decorations().size(), 0u);
EXPECT_EQ(st.source().range.begin.line, 27u);
EXPECT_EQ(st.source().range.begin.column, 4u);
+ EXPECT_EQ(st.source().range.end.line, 27u);
+ EXPECT_EQ(st.source().range.end.column, 8u);
}
TEST_F(StructMemberTest, IsValid) {
diff --git a/src/ast/struct_test.cc b/src/ast/struct_test.cc
index 828f454..55abf23 100644
--- a/src/ast/struct_test.cc
+++ b/src/ast/struct_test.cc
@@ -40,6 +40,8 @@
EXPECT_TRUE(s.decorations().empty());
EXPECT_EQ(s.source().range.begin.line, 0u);
EXPECT_EQ(s.source().range.begin.column, 0u);
+ EXPECT_EQ(s.source().range.end.line, 0u);
+ EXPECT_EQ(s.source().range.end.column, 0u);
}
TEST_F(StructTest, Creation_WithDecorations) {
@@ -58,6 +60,8 @@
EXPECT_EQ(s.decorations()[0], StructDecoration::kBlock);
EXPECT_EQ(s.source().range.begin.line, 0u);
EXPECT_EQ(s.source().range.begin.column, 0u);
+ EXPECT_EQ(s.source().range.end.line, 0u);
+ EXPECT_EQ(s.source().range.end.column, 0u);
}
TEST_F(StructTest, CreationWithSourceAndDecorations) {
@@ -70,13 +74,16 @@
StructDecorationList decos;
decos.push_back(StructDecoration::kBlock);
- Struct s{Source{Source::Location{27, 4}}, std::move(decos),
- std::move(members)};
+ Struct s{
+ Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
+ std::move(decos), std::move(members)};
EXPECT_EQ(s.members().size(), 1u);
ASSERT_EQ(s.decorations().size(), 1u);
EXPECT_EQ(s.decorations()[0], StructDecoration::kBlock);
EXPECT_EQ(s.source().range.begin.line, 27u);
EXPECT_EQ(s.source().range.begin.column, 4u);
+ EXPECT_EQ(s.source().range.end.line, 27u);
+ EXPECT_EQ(s.source().range.end.column, 8u);
}
TEST_F(StructTest, IsValid) {
diff --git a/src/ast/variable_test.cc b/src/ast/variable_test.cc
index ad006e3..3b0f845 100644
--- a/src/ast/variable_test.cc
+++ b/src/ast/variable_test.cc
@@ -34,10 +34,12 @@
EXPECT_EQ(v.type(), &t);
EXPECT_EQ(v.source().range.begin.line, 0u);
EXPECT_EQ(v.source().range.begin.column, 0u);
+ EXPECT_EQ(v.source().range.end.line, 0u);
+ EXPECT_EQ(v.source().range.end.column, 0u);
}
TEST_F(VariableTest, CreationWithSource) {
- Source s{Source::Location{27, 4}};
+ Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}};
type::F32Type t;
Variable v(s, "i", StorageClass::kPrivate, &t);
@@ -46,10 +48,12 @@
EXPECT_EQ(v.type(), &t);
EXPECT_EQ(v.source().range.begin.line, 27u);
EXPECT_EQ(v.source().range.begin.column, 4u);
+ EXPECT_EQ(v.source().range.end.line, 27u);
+ EXPECT_EQ(v.source().range.end.column, 5u);
}
TEST_F(VariableTest, CreationEmpty) {
- Source s{Source::Location{27, 4}};
+ Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}};
Variable v;
v.set_source(s);
v.set_storage_class(StorageClass::kWorkgroup);
@@ -63,6 +67,8 @@
EXPECT_EQ(v.type(), &t);
EXPECT_EQ(v.source().range.begin.line, 27u);
EXPECT_EQ(v.source().range.begin.column, 4u);
+ EXPECT_EQ(v.source().range.end.line, 27u);
+ EXPECT_EQ(v.source().range.end.column, 7u);
}
TEST_F(VariableTest, IsValid) {
diff --git a/src/reader/wgsl/lexer.cc b/src/reader/wgsl/lexer.cc
index 2fa4eb8..eb29668 100644
--- a/src/reader/wgsl/lexer.cc
+++ b/src/reader/wgsl/lexer.cc
@@ -44,7 +44,7 @@
skip_comments();
if (is_eof()) {
- return {Token::Type::kEOF, make_source()};
+ return {Token::Type::kEOF, begin_source()};
}
auto t = try_hex_integer();
@@ -77,10 +77,10 @@
return t;
}
- return {Token::Type::kError, make_source(), "invalid character found"};
+ return {Token::Type::kError, begin_source(), "invalid character found"};
}
-Source Lexer::make_source() const {
+Source Lexer::begin_source() const {
Source src{};
src.file = file_;
src.range.begin = location_;
@@ -88,6 +88,10 @@
return src;
}
+void Lexer::end_source(Source& src) const {
+ src.range.end = location_;
+}
+
bool Lexer::is_eof() const {
return pos_ >= len_;
}
@@ -153,7 +157,7 @@
auto start = pos_;
auto end = pos_;
- auto source = make_source();
+ auto source = begin_source();
if (matches(end, "-")) {
end++;
@@ -195,6 +199,8 @@
pos_ = end;
location_.column += (end - start);
+ end_source(source);
+
auto res = strtod(file_->content.c_str() + start, nullptr);
// This handles if the number is a really small in the exponent
if (res > 0 && res < static_cast<double>(std::numeric_limits<float>::min())) {
@@ -224,6 +230,8 @@
"u32 (" + file_->content.substr(start, end - start) + ") too large"};
}
pos_ += 1;
+ location_.column += 1;
+ end_source(source);
return {source, static_cast<uint32_t>(res)};
}
@@ -237,6 +245,7 @@
Token::Type::kError, source,
"i32 (" + file_->content.substr(start, end - start) + ") too large"};
}
+ end_source(source);
return {source, static_cast<int32_t>(res)};
}
@@ -244,7 +253,7 @@
auto start = pos_;
auto end = pos_;
- auto source = make_source();
+ auto source = begin_source();
if (matches(end, "-")) {
end++;
@@ -268,7 +277,7 @@
auto start = pos_;
auto end = start;
- auto source = make_source();
+ auto source = begin_source();
if (matches(end, "-")) {
end++;
@@ -299,7 +308,7 @@
return {};
}
- auto source = make_source();
+ auto source = begin_source();
auto s = pos_;
while (!is_eof() && is_alphanum(file_->content[pos_])) {
@@ -313,6 +322,8 @@
return t;
}
+ end_source(source);
+
t = check_keyword(source, str);
if (!t.IsUninitialized()) {
return t;
@@ -325,7 +336,7 @@
if (!matches(pos_, R"(")"))
return {};
- auto source = make_source();
+ auto source = begin_source();
pos_++;
auto start = pos_;
@@ -333,15 +344,19 @@
pos_++;
}
auto end = pos_;
- pos_++;
+ if (matches(pos_, R"(")")) {
+ pos_++;
+ }
location_.column += (pos_ - start) + 1;
+ end_source(source);
+
return {Token::Type::kStringLiteral, source,
file_->content.substr(start, end - start)};
}
Token Lexer::try_punctuation() {
- auto source = make_source();
+ auto source = begin_source();
auto type = Token::Type::kUninitialized;
if (matches(pos_, "[[")) {
@@ -474,6 +489,8 @@
location_.column += 1;
}
+ end_source(source);
+
return {type, source};
}
diff --git a/src/reader/wgsl/lexer.h b/src/reader/wgsl/lexer.h
index 1bfaf0a..ef1a839 100644
--- a/src/reader/wgsl/lexer.h
+++ b/src/reader/wgsl/lexer.h
@@ -53,7 +53,8 @@
Token try_punctuation();
Token try_string();
- Source make_source() const;
+ Source begin_source() const;
+ void end_source(Source&) const;
bool is_eof() const;
bool is_alpha(char ch) const;
diff --git a/src/reader/wgsl/lexer_test.cc b/src/reader/wgsl/lexer_test.cc
index 810cf51..e957cb8 100644
--- a/src/reader/wgsl/lexer_test.cc
+++ b/src/reader/wgsl/lexer_test.cc
@@ -40,6 +40,8 @@
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.source().range.begin.line, 2u);
EXPECT_EQ(t.source().range.begin.column, 6u);
+ EXPECT_EQ(t.source().range.end.line, 2u);
+ EXPECT_EQ(t.source().range.end.column, 11u);
EXPECT_EQ(t.to_str(), "ident");
t = l.next();
@@ -57,12 +59,16 @@
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.source().range.begin.line, 2u);
EXPECT_EQ(t.source().range.begin.column, 1u);
+ EXPECT_EQ(t.source().range.end.line, 2u);
+ EXPECT_EQ(t.source().range.end.column, 7u);
EXPECT_EQ(t.to_str(), "ident1");
t = l.next();
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.source().range.begin.line, 4u);
EXPECT_EQ(t.source().range.begin.column, 2u);
+ EXPECT_EQ(t.source().range.end.line, 4u);
+ EXPECT_EQ(t.source().range.end.column, 8u);
EXPECT_EQ(t.to_str(), "ident2");
t = l.next();
@@ -78,18 +84,24 @@
EXPECT_EQ(t.to_str(), "id");
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, 3u);
t = l.next();
EXPECT_TRUE(t.IsStringLiteral());
EXPECT_EQ(t.to_str(), "this is string content");
EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 4u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 28u);
t = l.next();
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "id2");
EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 29u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 32u);
}
TEST_F(LexerTest, StringTest_Unterminated) {
@@ -101,12 +113,16 @@
EXPECT_EQ(t.to_str(), "id");
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, 3u);
t = l.next();
EXPECT_TRUE(t.IsStringLiteral());
EXPECT_EQ(t.to_str(), "this is string content");
EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 4u);
+ EXPECT_EQ(t.source().range.end.line, 1u);
+ EXPECT_EQ(t.source().range.end.column, 27u);
t = l.next();
EXPECT_TRUE(t.IsEof());
@@ -131,6 +147,8 @@
EXPECT_EQ(t.to_f32(), params.result);
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, 1u + strlen(params.input));
t = l.next();
EXPECT_TRUE(t.IsEof());
@@ -182,6 +200,8 @@
EXPECT_TRUE(t.IsIdentifier());
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, 1u + strlen(GetParam()));
EXPECT_EQ(t.to_str(), GetParam());
}
INSTANTIATE_TEST_SUITE_P(
@@ -216,6 +236,8 @@
EXPECT_TRUE(t.IsSintLiteral());
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, 1u + strlen(params.input));
EXPECT_EQ(t.to_i32(), params.result);
}
INSTANTIATE_TEST_SUITE_P(
@@ -263,6 +285,8 @@
EXPECT_TRUE(t.IsUintLiteral());
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, 1u + strlen(params.input));
EXPECT_EQ(t.to_u32(), params.result);
t = l.next();
@@ -306,6 +330,8 @@
EXPECT_EQ(t.to_u32(), params.result);
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, 1u + strlen(params.input));
}
INSTANTIATE_TEST_SUITE_P(LexerTest,
IntegerTest_Unsigned,
@@ -333,6 +359,8 @@
EXPECT_EQ(t.to_i32(), params.result);
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, 1u + strlen(params.input));
}
INSTANTIATE_TEST_SUITE_P(
LexerTest,
@@ -375,6 +403,8 @@
EXPECT_TRUE(t.Is(params.type));
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, 1u + strlen(params.input));
t = l.next();
EXPECT_EQ(t.source().range.begin.column,
@@ -426,6 +456,8 @@
EXPECT_TRUE(t.Is(params.type)) << params.input;
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, 1u + strlen(params.input));
t = l.next();
EXPECT_EQ(t.source().range.begin.column,
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index c445f02..7951a53 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -354,21 +354,18 @@
if (!t.IsConst())
return nullptr;
- auto source = t.source();
next(); // Consume the peek
- std::string name;
- ast::type::Type* type;
- std::tie(name, type) = variable_ident_decl();
+ auto decl = variable_ident_decl();
if (has_error())
return nullptr;
- if (name.empty() || type == nullptr) {
+ if (decl.name.empty() || decl.type == nullptr) {
set_error(peek(), "error parsing constant variable identifier");
return nullptr;
}
- auto var = std::make_unique<ast::Variable>(source, name,
- ast::StorageClass::kNone, type);
+ auto var = std::make_unique<ast::Variable>(
+ decl.source, decl.name, ast::StorageClass::kNone, decl.type);
var->set_is_const(true);
t = next();
@@ -567,7 +564,6 @@
// : VAR variable_storage_decoration? variable_ident_decl
std::unique_ptr<ast::Variable> ParserImpl::variable_decl() {
auto t = peek();
- auto source = t.source();
if (!t.IsVar())
return nullptr;
@@ -577,17 +573,15 @@
if (has_error())
return {};
- std::string name;
- ast::type::Type* type;
- std::tie(name, type) = variable_ident_decl();
+ auto decl = variable_ident_decl();
if (has_error())
return nullptr;
- if (name.empty() || type == nullptr) {
+ if (decl.name.empty() || decl.type == nullptr) {
set_error(peek(), "invalid identifier declaration");
return nullptr;
}
- return std::make_unique<ast::Variable>(source, name, sc, type);
+ return std::make_unique<ast::Variable>(decl.source, decl.name, sc, decl.type);
}
// texture_sampler_types
@@ -1034,12 +1028,13 @@
// variable_ident_decl
// : IDENT COLON type_decl
-std::pair<std::string, ast::type::Type*> ParserImpl::variable_ident_decl() {
+ParserImpl::TypedIdentifier ParserImpl::variable_ident_decl() {
auto t = peek();
if (!t.IsIdentifier())
return {};
auto name = t.to_str();
+ auto source = t.source();
next(); // Consume the peek
t = next();
@@ -1056,7 +1051,7 @@
return {};
}
- return {name, type};
+ return {type, name, source};
}
// variable_storage_decoration
@@ -1620,7 +1615,6 @@
// : struct_member_decoration_decl+ variable_ident_decl SEMICOLON
std::unique_ptr<ast::StructMember> ParserImpl::struct_member() {
auto t = peek();
- auto source = t.source();
ast::StructMemberDecorationList decos;
for (;;) {
@@ -1635,12 +1629,10 @@
if (has_error())
return nullptr;
- std::string name;
- ast::type::Type* type;
- std::tie(name, type) = variable_ident_decl();
+ auto decl = variable_ident_decl();
if (has_error())
return nullptr;
- if (name.empty() || type == nullptr) {
+ if (decl.name.empty() || decl.type == nullptr) {
set_error(peek(), "invalid identifier declaration");
return nullptr;
}
@@ -1651,7 +1643,7 @@
return nullptr;
}
- return std::make_unique<ast::StructMember>(source, name, type,
+ return std::make_unique<ast::StructMember>(decl.source, decl.name, decl.type,
std::move(decos));
}
@@ -1981,21 +1973,18 @@
// | (variable_ident_decl COMMA)* variable_ident_decl
ast::VariableList ParserImpl::param_list() {
auto t = peek();
- auto source = t.source();
ast::VariableList ret;
- std::string name;
- ast::type::Type* type;
- std::tie(name, type) = variable_ident_decl();
+ auto decl = variable_ident_decl();
if (has_error())
return {};
- if (name.empty() || type == nullptr)
+ if (decl.name.empty() || decl.type == nullptr)
return {};
for (;;) {
- auto var = std::make_unique<ast::Variable>(source, name,
- ast::StorageClass::kNone, type);
+ auto var = std::make_unique<ast::Variable>(
+ decl.source, decl.name, ast::StorageClass::kNone, decl.type);
// Formal parameters are treated like a const declaration where the
// initializer value is provided by the call's argument. The key point is
// that it's not updatable after intially set. This is unlike C or GLSL
@@ -2007,13 +1996,12 @@
if (!t.IsComma())
break;
- source = t.source();
next(); // Consume the peek
- std::tie(name, type) = variable_ident_decl();
+ decl = variable_ident_decl();
if (has_error())
return {};
- if (name.empty() || type == nullptr) {
+ if (decl.name.empty() || decl.type == nullptr) {
set_error(t, "found , but no variable declaration");
return {};
}
@@ -2279,16 +2267,13 @@
// | CONST variable_ident_decl EQUAL logical_or_expression
std::unique_ptr<ast::VariableDeclStatement> ParserImpl::variable_stmt() {
auto t = peek();
- auto source = t.source();
if (t.IsConst()) {
next(); // Consume the peek
- std::string name;
- ast::type::Type* type;
- std::tie(name, type) = variable_ident_decl();
+ auto decl = variable_ident_decl();
if (has_error())
return nullptr;
- if (name.empty() || type == nullptr) {
+ if (decl.name.empty() || decl.type == nullptr) {
set_error(peek(), "unable to parse variable declaration");
return nullptr;
}
@@ -2307,12 +2292,13 @@
return nullptr;
}
- auto var = std::make_unique<ast::Variable>(source, name,
- ast::StorageClass::kNone, type);
+ auto var = std::make_unique<ast::Variable>(
+ decl.source, decl.name, ast::StorageClass::kNone, decl.type);
var->set_is_const(true);
var->set_constructor(std::move(constructor));
- return std::make_unique<ast::VariableDeclStatement>(source, std::move(var));
+ return std::make_unique<ast::VariableDeclStatement>(decl.source,
+ std::move(var));
}
auto var = variable_decl();
@@ -2334,7 +2320,8 @@
var->set_constructor(std::move(constructor));
}
- return std::make_unique<ast::VariableDeclStatement>(source, std::move(var));
+ return std::make_unique<ast::VariableDeclStatement>(var->source(),
+ std::move(var));
}
// if_stmt
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 4fb3644..82d04ab 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -76,6 +76,14 @@
/// ParserImpl for WGSL source data
class ParserImpl {
public:
+ /// TypedIdentifier holds a parsed identifier and type. Returned by
+ /// variable_ident_decl().
+ struct TypedIdentifier {
+ ast::type::Type* type = nullptr; /// Parsed type.
+ std::string name; /// Parsed identifier.
+ Source source; /// Source to the identifier.
+ };
+
/// Creates a new parser using the given file
/// @param ctx the non-null context object
/// @param file the input source file to parse
@@ -146,7 +154,7 @@
std::unique_ptr<ast::Variable> variable_decl();
/// Parses a `variable_ident_decl` grammar element
/// @returns the identifier and type parsed or empty otherwise
- std::pair<std::string, ast::type::Type*> variable_ident_decl();
+ TypedIdentifier variable_ident_decl();
/// Parses a `variable_storage_decoration` grammar element
/// @returns the storage class or StorageClass::kNone if none matched
ast::StorageClass variable_storage_decoration();
diff --git a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
index f08d17c..be0535a 100644
--- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -34,6 +34,11 @@
ASSERT_NE(e->type(), nullptr);
EXPECT_TRUE(e->type()->IsF32());
+ EXPECT_EQ(e->source().range.begin.line, 1u);
+ EXPECT_EQ(e->source().range.begin.column, 7u);
+ EXPECT_EQ(e->source().range.end.line, 1u);
+ EXPECT_EQ(e->source().range.end.column, 8u);
+
ASSERT_NE(e->constructor(), nullptr);
EXPECT_TRUE(e->constructor()->IsConstructor());
}
diff --git a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
index 80238ba..d6b74c5 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -33,6 +33,11 @@
EXPECT_TRUE(e->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput);
+ EXPECT_EQ(e->source().range.begin.line, 1u);
+ EXPECT_EQ(e->source().range.begin.column, 10u);
+ EXPECT_EQ(e->source().range.end.line, 1u);
+ EXPECT_EQ(e->source().range.end.column, 11u);
+
ASSERT_EQ(e->constructor(), nullptr);
ASSERT_FALSE(e->IsDecorated());
}
@@ -47,6 +52,11 @@
EXPECT_TRUE(e->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput);
+ EXPECT_EQ(e->source().range.begin.line, 1u);
+ EXPECT_EQ(e->source().range.begin.column, 10u);
+ EXPECT_EQ(e->source().range.end.line, 1u);
+ EXPECT_EQ(e->source().range.end.column, 11u);
+
ASSERT_NE(e->constructor(), nullptr);
ASSERT_TRUE(e->constructor()->IsConstructor());
ASSERT_TRUE(e->constructor()->AsConstructor()->IsScalarConstructor());
@@ -66,6 +76,11 @@
EXPECT_TRUE(e->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput);
+ EXPECT_EQ(e->source().range.begin.line, 1u);
+ EXPECT_EQ(e->source().range.begin.column, 33u);
+ EXPECT_EQ(e->source().range.end.line, 1u);
+ EXPECT_EQ(e->source().range.end.column, 34u);
+
ASSERT_EQ(e->constructor(), nullptr);
ASSERT_TRUE(e->IsDecorated());
@@ -89,6 +104,11 @@
EXPECT_TRUE(e->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput);
+ EXPECT_EQ(e->source().range.begin.line, 1u);
+ EXPECT_EQ(e->source().range.begin.column, 36u);
+ EXPECT_EQ(e->source().range.end.line, 1u);
+ EXPECT_EQ(e->source().range.end.column, 37u);
+
ASSERT_EQ(e->constructor(), nullptr);
ASSERT_TRUE(e->IsDecorated());
diff --git a/src/reader/wgsl/parser_impl_param_list_test.cc b/src/reader/wgsl/parser_impl_param_list_test.cc
index 1d0b12a..4ce27eb 100644
--- a/src/reader/wgsl/parser_impl_param_list_test.cc
+++ b/src/reader/wgsl/parser_impl_param_list_test.cc
@@ -39,6 +39,11 @@
EXPECT_EQ(e[0]->name(), "a");
EXPECT_EQ(e[0]->type(), i32);
EXPECT_TRUE(e[0]->is_const());
+
+ ASSERT_EQ(e[0]->source().range.begin.line, 1u);
+ ASSERT_EQ(e[0]->source().range.begin.column, 1u);
+ ASSERT_EQ(e[0]->source().range.end.line, 1u);
+ ASSERT_EQ(e[0]->source().range.end.column, 2u);
}
TEST_F(ParserImplTest, ParamList_Multiple) {
@@ -55,13 +60,28 @@
EXPECT_EQ(e[0]->type(), i32);
EXPECT_TRUE(e[0]->is_const());
+ ASSERT_EQ(e[0]->source().range.begin.line, 1u);
+ ASSERT_EQ(e[0]->source().range.begin.column, 1u);
+ ASSERT_EQ(e[0]->source().range.end.line, 1u);
+ ASSERT_EQ(e[0]->source().range.end.column, 2u);
+
EXPECT_EQ(e[1]->name(), "b");
EXPECT_EQ(e[1]->type(), f32);
EXPECT_TRUE(e[1]->is_const());
+ ASSERT_EQ(e[1]->source().range.begin.line, 1u);
+ ASSERT_EQ(e[1]->source().range.begin.column, 10u);
+ ASSERT_EQ(e[1]->source().range.end.line, 1u);
+ ASSERT_EQ(e[1]->source().range.end.column, 11u);
+
EXPECT_EQ(e[2]->name(), "c");
EXPECT_EQ(e[2]->type(), vec2);
- EXPECT_TRUE(e[1]->is_const());
+ EXPECT_TRUE(e[2]->is_const());
+
+ ASSERT_EQ(e[2]->source().range.begin.line, 1u);
+ ASSERT_EQ(e[2]->source().range.begin.column, 18u);
+ ASSERT_EQ(e[2]->source().range.end.line, 1u);
+ ASSERT_EQ(e[2]->source().range.end.column, 19u);
}
TEST_F(ParserImplTest, ParamList_Empty) {
diff --git a/src/reader/wgsl/parser_impl_struct_member_test.cc b/src/reader/wgsl/parser_impl_struct_member_test.cc
index 9ee2d9f..d4913c3 100644
--- a/src/reader/wgsl/parser_impl_struct_member_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_test.cc
@@ -35,6 +35,11 @@
EXPECT_EQ(m->name(), "a");
EXPECT_EQ(m->type(), i32);
EXPECT_EQ(m->decorations().size(), 0u);
+
+ ASSERT_EQ(m->source().range.begin.line, 1u);
+ ASSERT_EQ(m->source().range.begin.column, 1u);
+ ASSERT_EQ(m->source().range.end.line, 1u);
+ ASSERT_EQ(m->source().range.end.column, 2u);
}
TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
@@ -50,6 +55,11 @@
EXPECT_EQ(m->decorations().size(), 1u);
EXPECT_TRUE(m->decorations()[0]->IsOffset());
EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u);
+
+ ASSERT_EQ(m->source().range.begin.line, 1u);
+ ASSERT_EQ(m->source().range.begin.column, 15u);
+ ASSERT_EQ(m->source().range.end.line, 1u);
+ ASSERT_EQ(m->source().range.end.column, 16u);
}
TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
@@ -68,6 +78,11 @@
EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u);
EXPECT_TRUE(m->decorations()[1]->IsOffset());
EXPECT_EQ(m->decorations()[1]->AsOffset()->offset(), 4u);
+
+ ASSERT_EQ(m->source().range.begin.line, 2u);
+ ASSERT_EQ(m->source().range.begin.column, 15u);
+ ASSERT_EQ(m->source().range.end.line, 2u);
+ ASSERT_EQ(m->source().range.end.column, 16u);
}
TEST_F(ParserImplTest, StructMember_InvalidDecoration) {
diff --git a/src/reader/wgsl/parser_impl_variable_decl_test.cc b/src/reader/wgsl/parser_impl_variable_decl_test.cc
index 2598376..97d0115 100644
--- a/src/reader/wgsl/parser_impl_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decl_test.cc
@@ -29,9 +29,12 @@
ASSERT_NE(var, nullptr);
ASSERT_EQ(var->name(), "my_var");
ASSERT_NE(var->type(), nullptr);
- ASSERT_EQ(var->source().range.begin.line, 1u);
- ASSERT_EQ(var->source().range.begin.column, 1u);
ASSERT_TRUE(var->type()->IsF32());
+
+ ASSERT_EQ(var->source().range.begin.line, 1u);
+ ASSERT_EQ(var->source().range.begin.column, 5u);
+ ASSERT_EQ(var->source().range.end.line, 1u);
+ ASSERT_EQ(var->source().range.end.column, 11u);
}
TEST_F(ParserImplTest, VariableDecl_MissingVar) {
@@ -60,6 +63,11 @@
EXPECT_EQ(v->name(), "my_var");
EXPECT_TRUE(v->type()->IsF32());
EXPECT_EQ(v->storage_class(), ast::StorageClass::kPrivate);
+
+ EXPECT_EQ(v->source().range.begin.line, 1u);
+ EXPECT_EQ(v->source().range.begin.column, 14u);
+ EXPECT_EQ(v->source().range.end.line, 1u);
+ EXPECT_EQ(v->source().range.end.column, 20u);
}
TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
diff --git a/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc b/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
index 2cf0b6b..dc06863 100644
--- a/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
@@ -23,23 +23,24 @@
TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
auto* p = parser("my_var : f32");
- std::string name;
- ast::type::Type* type;
- std::tie(name, type) = p->variable_ident_decl();
+ auto decl = p->variable_ident_decl();
ASSERT_FALSE(p->has_error());
- ASSERT_EQ(name, "my_var");
- ASSERT_NE(type, nullptr);
- ASSERT_TRUE(type->IsF32());
+ ASSERT_EQ(decl.name, "my_var");
+ ASSERT_NE(decl.type, nullptr);
+ ASSERT_TRUE(decl.type->IsF32());
+
+ ASSERT_EQ(decl.source.range.begin.line, 1u);
+ ASSERT_EQ(decl.source.range.begin.column, 1u);
+ ASSERT_EQ(decl.source.range.end.line, 1u);
+ ASSERT_EQ(decl.source.range.end.column, 7u);
}
TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) {
auto* p = parser(": f32");
- std::string name;
- ast::type::Type* type;
- std::tie(name, type) = p->variable_ident_decl();
+ auto decl = p->variable_ident_decl();
ASSERT_FALSE(p->has_error());
- ASSERT_EQ(name, "");
- ASSERT_EQ(type, nullptr);
+ ASSERT_EQ(decl.name, "");
+ ASSERT_EQ(decl.type, nullptr);
auto t = p->next();
ASSERT_TRUE(t.IsColon());
@@ -61,12 +62,10 @@
TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
auto* p = parser("123 : f32");
- std::string name;
- ast::type::Type* type;
- std::tie(name, type) = p->variable_ident_decl();
+ auto decl = p->variable_ident_decl();
ASSERT_FALSE(p->has_error());
- ASSERT_EQ(name, "");
- ASSERT_EQ(type, nullptr);
+ ASSERT_EQ(decl.name, "");
+ ASSERT_EQ(decl.type, nullptr);
auto t = p->next();
ASSERT_TRUE(t.IsSintLiteral());
diff --git a/src/reader/wgsl/parser_impl_variable_stmt_test.cc b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
index 9e3d278..1330a7a 100644
--- a/src/reader/wgsl/parser_impl_variable_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
@@ -32,6 +32,11 @@
ASSERT_NE(e->variable(), nullptr);
EXPECT_EQ(e->variable()->name(), "a");
+ ASSERT_EQ(e->source().range.begin.line, 1u);
+ ASSERT_EQ(e->source().range.begin.column, 5u);
+ ASSERT_EQ(e->source().range.end.line, 1u);
+ ASSERT_EQ(e->source().range.end.column, 6u);
+
EXPECT_EQ(e->variable()->constructor(), nullptr);
}
@@ -44,6 +49,11 @@
ASSERT_NE(e->variable(), nullptr);
EXPECT_EQ(e->variable()->name(), "a");
+ ASSERT_EQ(e->source().range.begin.line, 1u);
+ ASSERT_EQ(e->source().range.begin.column, 5u);
+ ASSERT_EQ(e->source().range.end.line, 1u);
+ ASSERT_EQ(e->source().range.end.column, 6u);
+
ASSERT_NE(e->variable()->constructor(), nullptr);
EXPECT_TRUE(e->variable()->constructor()->IsConstructor());
}
@@ -70,6 +80,11 @@
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariableDecl());
+
+ ASSERT_EQ(e->source().range.begin.line, 1u);
+ ASSERT_EQ(e->source().range.begin.column, 7u);
+ ASSERT_EQ(e->source().range.end.line, 1u);
+ ASSERT_EQ(e->source().range.end.column, 8u);
}
TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) {
diff --git a/src/reader/wgsl/token_test.cc b/src/reader/wgsl/token_test.cc
index 4911d05..ae56acc 100644
--- a/src/reader/wgsl/token_test.cc
+++ b/src/reader/wgsl/token_test.cc
@@ -67,9 +67,18 @@
}
TEST_F(TokenTest, Source) {
- Token t(Token::Type::kUintLiteral, Source{Source::Location{3, 9}});
+ Source::File file("", "");
+ Source src;
+ src.file = &file;
+ src.range.begin = Source::Location{3, 9};
+ src.range.end = Source::Location{4, 3};
+
+ Token t(Token::Type::kUintLiteral, src);
EXPECT_EQ(t.source().range.begin.line, 3u);
EXPECT_EQ(t.source().range.begin.column, 9u);
+ EXPECT_EQ(t.source().range.end.line, 4u);
+ EXPECT_EQ(t.source().range.end.column, 3u);
+ EXPECT_EQ(t.source().file, &file);
}
} // namespace