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>
This commit is contained in:
Ben Clayton 2020-11-02 15:25:18 +00:00 committed by Commit Bot service account
parent a3bcde2c10
commit 580d6c7f3e
19 changed files with 243 additions and 79 deletions

View File

@ -42,10 +42,12 @@ TEST_F(DecoratedVariableTest, Creation) {
EXPECT_EQ(dv.type(), &t); EXPECT_EQ(dv.type(), &t);
EXPECT_EQ(dv.source().range.begin.line, 0u); EXPECT_EQ(dv.source().range.begin.line, 0u);
EXPECT_EQ(dv.source().range.begin.column, 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) { 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; type::F32Type t;
auto var = std::make_unique<Variable>(s, "i", StorageClass::kPrivate, &t); auto var = std::make_unique<Variable>(s, "i", StorageClass::kPrivate, &t);
DecoratedVariable dv(std::move(var)); DecoratedVariable dv(std::move(var));
@ -55,6 +57,8 @@ TEST_F(DecoratedVariableTest, CreationWithSource) {
EXPECT_EQ(dv.type(), &t); EXPECT_EQ(dv.type(), &t);
EXPECT_EQ(dv.source().range.begin.line, 27u); EXPECT_EQ(dv.source().range.begin.line, 27u);
EXPECT_EQ(dv.source().range.begin.column, 4u); 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) { TEST_F(DecoratedVariableTest, NoDecorations) {

View File

@ -28,12 +28,17 @@ TEST_F(DiscardStatementTest, Creation) {
DiscardStatement stmt; DiscardStatement stmt;
EXPECT_EQ(stmt.source().range.begin.line, 0u); EXPECT_EQ(stmt.source().range.begin.line, 0u);
EXPECT_EQ(stmt.source().range.begin.column, 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) { 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.line, 20u);
EXPECT_EQ(stmt.source().range.begin.column, 2u); 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) { TEST_F(DiscardStatementTest, IsDiscard) {

View File

@ -26,6 +26,8 @@ TEST_F(FallthroughStatementTest, Creation) {
FallthroughStatement stmt; FallthroughStatement stmt;
EXPECT_EQ(stmt.source().range.begin.line, 0u); EXPECT_EQ(stmt.source().range.begin.line, 0u);
EXPECT_EQ(stmt.source().range.begin.column, 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) { TEST_F(FallthroughStatementTest, Creation_WithSource) {

View File

@ -39,11 +39,13 @@ TEST_F(StructMemberTest, Creation) {
EXPECT_TRUE(st.decorations()[0]->IsOffset()); EXPECT_TRUE(st.decorations()[0]->IsOffset());
EXPECT_EQ(st.source().range.begin.line, 0u); EXPECT_EQ(st.source().range.begin.line, 0u);
EXPECT_EQ(st.source().range.begin.column, 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) { TEST_F(StructMemberTest, CreationWithSource) {
type::I32Type i32; 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, {}}; StructMember st{s, "a", &i32, {}};
EXPECT_EQ(st.name(), "a"); EXPECT_EQ(st.name(), "a");
@ -51,6 +53,8 @@ TEST_F(StructMemberTest, CreationWithSource) {
EXPECT_EQ(st.decorations().size(), 0u); EXPECT_EQ(st.decorations().size(), 0u);
EXPECT_EQ(st.source().range.begin.line, 27u); EXPECT_EQ(st.source().range.begin.line, 27u);
EXPECT_EQ(st.source().range.begin.column, 4u); 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) { TEST_F(StructMemberTest, IsValid) {

View File

@ -40,6 +40,8 @@ TEST_F(StructTest, Creation) {
EXPECT_TRUE(s.decorations().empty()); EXPECT_TRUE(s.decorations().empty());
EXPECT_EQ(s.source().range.begin.line, 0u); EXPECT_EQ(s.source().range.begin.line, 0u);
EXPECT_EQ(s.source().range.begin.column, 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) { TEST_F(StructTest, Creation_WithDecorations) {
@ -58,6 +60,8 @@ TEST_F(StructTest, Creation_WithDecorations) {
EXPECT_EQ(s.decorations()[0], StructDecoration::kBlock); EXPECT_EQ(s.decorations()[0], StructDecoration::kBlock);
EXPECT_EQ(s.source().range.begin.line, 0u); EXPECT_EQ(s.source().range.begin.line, 0u);
EXPECT_EQ(s.source().range.begin.column, 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) { TEST_F(StructTest, CreationWithSourceAndDecorations) {
@ -70,13 +74,16 @@ TEST_F(StructTest, CreationWithSourceAndDecorations) {
StructDecorationList decos; StructDecorationList decos;
decos.push_back(StructDecoration::kBlock); decos.push_back(StructDecoration::kBlock);
Struct s{Source{Source::Location{27, 4}}, std::move(decos), Struct s{
std::move(members)}; Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
std::move(decos), std::move(members)};
EXPECT_EQ(s.members().size(), 1u); EXPECT_EQ(s.members().size(), 1u);
ASSERT_EQ(s.decorations().size(), 1u); ASSERT_EQ(s.decorations().size(), 1u);
EXPECT_EQ(s.decorations()[0], StructDecoration::kBlock); EXPECT_EQ(s.decorations()[0], StructDecoration::kBlock);
EXPECT_EQ(s.source().range.begin.line, 27u); EXPECT_EQ(s.source().range.begin.line, 27u);
EXPECT_EQ(s.source().range.begin.column, 4u); 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) { TEST_F(StructTest, IsValid) {

View File

@ -34,10 +34,12 @@ TEST_F(VariableTest, Creation) {
EXPECT_EQ(v.type(), &t); EXPECT_EQ(v.type(), &t);
EXPECT_EQ(v.source().range.begin.line, 0u); EXPECT_EQ(v.source().range.begin.line, 0u);
EXPECT_EQ(v.source().range.begin.column, 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) { 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; type::F32Type t;
Variable v(s, "i", StorageClass::kPrivate, &t); Variable v(s, "i", StorageClass::kPrivate, &t);
@ -46,10 +48,12 @@ TEST_F(VariableTest, CreationWithSource) {
EXPECT_EQ(v.type(), &t); EXPECT_EQ(v.type(), &t);
EXPECT_EQ(v.source().range.begin.line, 27u); EXPECT_EQ(v.source().range.begin.line, 27u);
EXPECT_EQ(v.source().range.begin.column, 4u); 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) { TEST_F(VariableTest, CreationEmpty) {
Source s{Source::Location{27, 4}}; Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}};
Variable v; Variable v;
v.set_source(s); v.set_source(s);
v.set_storage_class(StorageClass::kWorkgroup); v.set_storage_class(StorageClass::kWorkgroup);
@ -63,6 +67,8 @@ TEST_F(VariableTest, CreationEmpty) {
EXPECT_EQ(v.type(), &t); EXPECT_EQ(v.type(), &t);
EXPECT_EQ(v.source().range.begin.line, 27u); EXPECT_EQ(v.source().range.begin.line, 27u);
EXPECT_EQ(v.source().range.begin.column, 4u); 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) { TEST_F(VariableTest, IsValid) {

View File

@ -44,7 +44,7 @@ Token Lexer::next() {
skip_comments(); skip_comments();
if (is_eof()) { if (is_eof()) {
return {Token::Type::kEOF, make_source()}; return {Token::Type::kEOF, begin_source()};
} }
auto t = try_hex_integer(); auto t = try_hex_integer();
@ -77,10 +77,10 @@ Token Lexer::next() {
return t; 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{}; Source src{};
src.file = file_; src.file = file_;
src.range.begin = location_; src.range.begin = location_;
@ -88,6 +88,10 @@ Source Lexer::make_source() const {
return src; return src;
} }
void Lexer::end_source(Source& src) const {
src.range.end = location_;
}
bool Lexer::is_eof() const { bool Lexer::is_eof() const {
return pos_ >= len_; return pos_ >= len_;
} }
@ -153,7 +157,7 @@ Token Lexer::try_float() {
auto start = pos_; auto start = pos_;
auto end = pos_; auto end = pos_;
auto source = make_source(); auto source = begin_source();
if (matches(end, "-")) { if (matches(end, "-")) {
end++; end++;
@ -195,6 +199,8 @@ Token Lexer::try_float() {
pos_ = end; pos_ = end;
location_.column += (end - start); location_.column += (end - start);
end_source(source);
auto res = strtod(file_->content.c_str() + start, nullptr); auto res = strtod(file_->content.c_str() + start, nullptr);
// This handles if the number is a really small in the exponent // This handles if the number is a really small in the exponent
if (res > 0 && res < static_cast<double>(std::numeric_limits<float>::min())) { if (res > 0 && res < static_cast<double>(std::numeric_limits<float>::min())) {
@ -224,6 +230,8 @@ Token Lexer::build_token_from_int_if_possible(Source source,
"u32 (" + file_->content.substr(start, end - start) + ") too large"}; "u32 (" + file_->content.substr(start, end - start) + ") too large"};
} }
pos_ += 1; pos_ += 1;
location_.column += 1;
end_source(source);
return {source, static_cast<uint32_t>(res)}; return {source, static_cast<uint32_t>(res)};
} }
@ -237,6 +245,7 @@ Token Lexer::build_token_from_int_if_possible(Source source,
Token::Type::kError, source, Token::Type::kError, source,
"i32 (" + file_->content.substr(start, end - start) + ") too large"}; "i32 (" + file_->content.substr(start, end - start) + ") too large"};
} }
end_source(source);
return {source, static_cast<int32_t>(res)}; return {source, static_cast<int32_t>(res)};
} }
@ -244,7 +253,7 @@ Token Lexer::try_hex_integer() {
auto start = pos_; auto start = pos_;
auto end = pos_; auto end = pos_;
auto source = make_source(); auto source = begin_source();
if (matches(end, "-")) { if (matches(end, "-")) {
end++; end++;
@ -268,7 +277,7 @@ Token Lexer::try_integer() {
auto start = pos_; auto start = pos_;
auto end = start; auto end = start;
auto source = make_source(); auto source = begin_source();
if (matches(end, "-")) { if (matches(end, "-")) {
end++; end++;
@ -299,7 +308,7 @@ Token Lexer::try_ident() {
return {}; return {};
} }
auto source = make_source(); auto source = begin_source();
auto s = pos_; auto s = pos_;
while (!is_eof() && is_alphanum(file_->content[pos_])) { while (!is_eof() && is_alphanum(file_->content[pos_])) {
@ -313,6 +322,8 @@ Token Lexer::try_ident() {
return t; return t;
} }
end_source(source);
t = check_keyword(source, str); t = check_keyword(source, str);
if (!t.IsUninitialized()) { if (!t.IsUninitialized()) {
return t; return t;
@ -325,7 +336,7 @@ Token Lexer::try_string() {
if (!matches(pos_, R"(")")) if (!matches(pos_, R"(")"))
return {}; return {};
auto source = make_source(); auto source = begin_source();
pos_++; pos_++;
auto start = pos_; auto start = pos_;
@ -333,15 +344,19 @@ Token Lexer::try_string() {
pos_++; pos_++;
} }
auto end = pos_; auto end = pos_;
if (matches(pos_, R"(")")) {
pos_++; pos_++;
}
location_.column += (pos_ - start) + 1; location_.column += (pos_ - start) + 1;
end_source(source);
return {Token::Type::kStringLiteral, source, return {Token::Type::kStringLiteral, source,
file_->content.substr(start, end - start)}; file_->content.substr(start, end - start)};
} }
Token Lexer::try_punctuation() { Token Lexer::try_punctuation() {
auto source = make_source(); auto source = begin_source();
auto type = Token::Type::kUninitialized; auto type = Token::Type::kUninitialized;
if (matches(pos_, "[[")) { if (matches(pos_, "[[")) {
@ -474,6 +489,8 @@ Token Lexer::try_punctuation() {
location_.column += 1; location_.column += 1;
} }
end_source(source);
return {type, source}; return {type, source};
} }

View File

@ -53,7 +53,8 @@ class Lexer {
Token try_punctuation(); Token try_punctuation();
Token try_string(); Token try_string();
Source make_source() const; Source begin_source() const;
void end_source(Source&) const;
bool is_eof() const; bool is_eof() const;
bool is_alpha(char ch) const; bool is_alpha(char ch) const;

View File

@ -40,6 +40,8 @@ TEST_F(LexerTest, Skips_Whitespace) {
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.source().range.begin.line, 2u); EXPECT_EQ(t.source().range.begin.line, 2u);
EXPECT_EQ(t.source().range.begin.column, 6u); 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"); EXPECT_EQ(t.to_str(), "ident");
t = l.next(); t = l.next();
@ -57,12 +59,16 @@ ident1 #ends with comment
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.source().range.begin.line, 2u); EXPECT_EQ(t.source().range.begin.line, 2u);
EXPECT_EQ(t.source().range.begin.column, 1u); 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"); EXPECT_EQ(t.to_str(), "ident1");
t = l.next(); t = l.next();
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.source().range.begin.line, 4u); EXPECT_EQ(t.source().range.begin.line, 4u);
EXPECT_EQ(t.source().range.begin.column, 2u); 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"); EXPECT_EQ(t.to_str(), "ident2");
t = l.next(); t = l.next();
@ -78,18 +84,24 @@ TEST_F(LexerTest, StringTest_Parse) {
EXPECT_EQ(t.to_str(), "id"); EXPECT_EQ(t.to_str(), "id");
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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(); t = l.next();
EXPECT_TRUE(t.IsStringLiteral()); EXPECT_TRUE(t.IsStringLiteral());
EXPECT_EQ(t.to_str(), "this is string content"); EXPECT_EQ(t.to_str(), "this is string content");
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 4u); 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(); t = l.next();
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "id2"); EXPECT_EQ(t.to_str(), "id2");
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 29u); 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) { TEST_F(LexerTest, StringTest_Unterminated) {
@ -101,12 +113,16 @@ TEST_F(LexerTest, StringTest_Unterminated) {
EXPECT_EQ(t.to_str(), "id"); EXPECT_EQ(t.to_str(), "id");
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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(); t = l.next();
EXPECT_TRUE(t.IsStringLiteral()); EXPECT_TRUE(t.IsStringLiteral());
EXPECT_EQ(t.to_str(), "this is string content"); EXPECT_EQ(t.to_str(), "this is string content");
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 4u); 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(); t = l.next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
@ -131,6 +147,8 @@ TEST_P(FloatTest, Parse) {
EXPECT_EQ(t.to_f32(), params.result); EXPECT_EQ(t.to_f32(), params.result);
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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(); t = l.next();
EXPECT_TRUE(t.IsEof()); EXPECT_TRUE(t.IsEof());
@ -182,6 +200,8 @@ TEST_P(IdentifierTest, Parse) {
EXPECT_TRUE(t.IsIdentifier()); EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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()); EXPECT_EQ(t.to_str(), GetParam());
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -216,6 +236,8 @@ TEST_P(IntegerTest_HexSigned, Matches) {
EXPECT_TRUE(t.IsSintLiteral()); EXPECT_TRUE(t.IsSintLiteral());
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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); EXPECT_EQ(t.to_i32(), params.result);
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -263,6 +285,8 @@ TEST_P(IntegerTest_HexUnsigned, Matches) {
EXPECT_TRUE(t.IsUintLiteral()); EXPECT_TRUE(t.IsUintLiteral());
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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); EXPECT_EQ(t.to_u32(), params.result);
t = l.next(); t = l.next();
@ -306,6 +330,8 @@ TEST_P(IntegerTest_Unsigned, Matches) {
EXPECT_EQ(t.to_u32(), params.result); EXPECT_EQ(t.to_u32(), params.result);
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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, INSTANTIATE_TEST_SUITE_P(LexerTest,
IntegerTest_Unsigned, IntegerTest_Unsigned,
@ -333,6 +359,8 @@ TEST_P(IntegerTest_Signed, Matches) {
EXPECT_EQ(t.to_i32(), params.result); EXPECT_EQ(t.to_i32(), params.result);
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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( INSTANTIATE_TEST_SUITE_P(
LexerTest, LexerTest,
@ -375,6 +403,8 @@ TEST_P(PunctuationTest, Parses) {
EXPECT_TRUE(t.Is(params.type)); EXPECT_TRUE(t.Is(params.type));
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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(); t = l.next();
EXPECT_EQ(t.source().range.begin.column, EXPECT_EQ(t.source().range.begin.column,
@ -426,6 +456,8 @@ TEST_P(KeywordTest, Parses) {
EXPECT_TRUE(t.Is(params.type)) << params.input; EXPECT_TRUE(t.Is(params.type)) << params.input;
EXPECT_EQ(t.source().range.begin.line, 1u); EXPECT_EQ(t.source().range.begin.line, 1u);
EXPECT_EQ(t.source().range.begin.column, 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(); t = l.next();
EXPECT_EQ(t.source().range.begin.column, EXPECT_EQ(t.source().range.begin.column,

View File

@ -354,21 +354,18 @@ std::unique_ptr<ast::Variable> ParserImpl::global_constant_decl() {
if (!t.IsConst()) if (!t.IsConst())
return nullptr; return nullptr;
auto source = t.source();
next(); // Consume the peek next(); // Consume the peek
std::string name; auto decl = variable_ident_decl();
ast::type::Type* type;
std::tie(name, type) = variable_ident_decl();
if (has_error()) if (has_error())
return nullptr; return nullptr;
if (name.empty() || type == nullptr) { if (decl.name.empty() || decl.type == nullptr) {
set_error(peek(), "error parsing constant variable identifier"); set_error(peek(), "error parsing constant variable identifier");
return nullptr; return nullptr;
} }
auto var = std::make_unique<ast::Variable>(source, name, auto var = std::make_unique<ast::Variable>(
ast::StorageClass::kNone, type); decl.source, decl.name, ast::StorageClass::kNone, decl.type);
var->set_is_const(true); var->set_is_const(true);
t = next(); t = next();
@ -567,7 +564,6 @@ std::unique_ptr<ast::VariableDecoration> ParserImpl::variable_decoration() {
// : VAR variable_storage_decoration? variable_ident_decl // : VAR variable_storage_decoration? variable_ident_decl
std::unique_ptr<ast::Variable> ParserImpl::variable_decl() { std::unique_ptr<ast::Variable> ParserImpl::variable_decl() {
auto t = peek(); auto t = peek();
auto source = t.source();
if (!t.IsVar()) if (!t.IsVar())
return nullptr; return nullptr;
@ -577,17 +573,15 @@ std::unique_ptr<ast::Variable> ParserImpl::variable_decl() {
if (has_error()) if (has_error())
return {}; return {};
std::string name; auto decl = variable_ident_decl();
ast::type::Type* type;
std::tie(name, type) = variable_ident_decl();
if (has_error()) if (has_error())
return nullptr; return nullptr;
if (name.empty() || type == nullptr) { if (decl.name.empty() || decl.type == nullptr) {
set_error(peek(), "invalid identifier declaration"); set_error(peek(), "invalid identifier declaration");
return nullptr; 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 // texture_sampler_types
@ -1034,12 +1028,13 @@ ast::type::ImageFormat ParserImpl::image_storage_type() {
// variable_ident_decl // variable_ident_decl
// : IDENT COLON type_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(); auto t = peek();
if (!t.IsIdentifier()) if (!t.IsIdentifier())
return {}; return {};
auto name = t.to_str(); auto name = t.to_str();
auto source = t.source();
next(); // Consume the peek next(); // Consume the peek
t = next(); t = next();
@ -1056,7 +1051,7 @@ std::pair<std::string, ast::type::Type*> ParserImpl::variable_ident_decl() {
return {}; return {};
} }
return {name, type}; return {type, name, source};
} }
// variable_storage_decoration // variable_storage_decoration
@ -1620,7 +1615,6 @@ ast::StructMemberList ParserImpl::struct_body_decl() {
// : struct_member_decoration_decl+ variable_ident_decl SEMICOLON // : struct_member_decoration_decl+ variable_ident_decl SEMICOLON
std::unique_ptr<ast::StructMember> ParserImpl::struct_member() { std::unique_ptr<ast::StructMember> ParserImpl::struct_member() {
auto t = peek(); auto t = peek();
auto source = t.source();
ast::StructMemberDecorationList decos; ast::StructMemberDecorationList decos;
for (;;) { for (;;) {
@ -1635,12 +1629,10 @@ std::unique_ptr<ast::StructMember> ParserImpl::struct_member() {
if (has_error()) if (has_error())
return nullptr; return nullptr;
std::string name; auto decl = variable_ident_decl();
ast::type::Type* type;
std::tie(name, type) = variable_ident_decl();
if (has_error()) if (has_error())
return nullptr; return nullptr;
if (name.empty() || type == nullptr) { if (decl.name.empty() || decl.type == nullptr) {
set_error(peek(), "invalid identifier declaration"); set_error(peek(), "invalid identifier declaration");
return nullptr; return nullptr;
} }
@ -1651,7 +1643,7 @@ std::unique_ptr<ast::StructMember> ParserImpl::struct_member() {
return nullptr; 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)); std::move(decos));
} }
@ -1981,21 +1973,18 @@ std::unique_ptr<ast::Function> ParserImpl::function_header() {
// | (variable_ident_decl COMMA)* variable_ident_decl // | (variable_ident_decl COMMA)* variable_ident_decl
ast::VariableList ParserImpl::param_list() { ast::VariableList ParserImpl::param_list() {
auto t = peek(); auto t = peek();
auto source = t.source();
ast::VariableList ret; ast::VariableList ret;
std::string name; auto decl = variable_ident_decl();
ast::type::Type* type;
std::tie(name, type) = variable_ident_decl();
if (has_error()) if (has_error())
return {}; return {};
if (name.empty() || type == nullptr) if (decl.name.empty() || decl.type == nullptr)
return {}; return {};
for (;;) { for (;;) {
auto var = std::make_unique<ast::Variable>(source, name, auto var = std::make_unique<ast::Variable>(
ast::StorageClass::kNone, type); decl.source, decl.name, ast::StorageClass::kNone, decl.type);
// Formal parameters are treated like a const declaration where the // Formal parameters are treated like a const declaration where the
// initializer value is provided by the call's argument. The key point is // 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 // that it's not updatable after intially set. This is unlike C or GLSL
@ -2007,13 +1996,12 @@ ast::VariableList ParserImpl::param_list() {
if (!t.IsComma()) if (!t.IsComma())
break; break;
source = t.source();
next(); // Consume the peek next(); // Consume the peek
std::tie(name, type) = variable_ident_decl(); decl = variable_ident_decl();
if (has_error()) if (has_error())
return {}; return {};
if (name.empty() || type == nullptr) { if (decl.name.empty() || decl.type == nullptr) {
set_error(t, "found , but no variable declaration"); set_error(t, "found , but no variable declaration");
return {}; return {};
} }
@ -2279,16 +2267,13 @@ std::unique_ptr<ast::ReturnStatement> ParserImpl::return_stmt() {
// | CONST variable_ident_decl EQUAL logical_or_expression // | CONST variable_ident_decl EQUAL logical_or_expression
std::unique_ptr<ast::VariableDeclStatement> ParserImpl::variable_stmt() { std::unique_ptr<ast::VariableDeclStatement> ParserImpl::variable_stmt() {
auto t = peek(); auto t = peek();
auto source = t.source();
if (t.IsConst()) { if (t.IsConst()) {
next(); // Consume the peek next(); // Consume the peek
std::string name; auto decl = variable_ident_decl();
ast::type::Type* type;
std::tie(name, type) = variable_ident_decl();
if (has_error()) if (has_error())
return nullptr; return nullptr;
if (name.empty() || type == nullptr) { if (decl.name.empty() || decl.type == nullptr) {
set_error(peek(), "unable to parse variable declaration"); set_error(peek(), "unable to parse variable declaration");
return nullptr; return nullptr;
} }
@ -2307,12 +2292,13 @@ std::unique_ptr<ast::VariableDeclStatement> ParserImpl::variable_stmt() {
return nullptr; return nullptr;
} }
auto var = std::make_unique<ast::Variable>(source, name, auto var = std::make_unique<ast::Variable>(
ast::StorageClass::kNone, type); decl.source, decl.name, ast::StorageClass::kNone, decl.type);
var->set_is_const(true); var->set_is_const(true);
var->set_constructor(std::move(constructor)); 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(); auto var = variable_decl();
@ -2334,7 +2320,8 @@ std::unique_ptr<ast::VariableDeclStatement> ParserImpl::variable_stmt() {
var->set_constructor(std::move(constructor)); 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 // if_stmt

View File

@ -76,6 +76,14 @@ struct ForHeader {
/// ParserImpl for WGSL source data /// ParserImpl for WGSL source data
class ParserImpl { class ParserImpl {
public: 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 /// Creates a new parser using the given file
/// @param ctx the non-null context object /// @param ctx the non-null context object
/// @param file the input source file to parse /// @param file the input source file to parse
@ -146,7 +154,7 @@ class ParserImpl {
std::unique_ptr<ast::Variable> variable_decl(); std::unique_ptr<ast::Variable> variable_decl();
/// Parses a `variable_ident_decl` grammar element /// Parses a `variable_ident_decl` grammar element
/// @returns the identifier and type parsed or empty otherwise /// @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 /// Parses a `variable_storage_decoration` grammar element
/// @returns the storage class or StorageClass::kNone if none matched /// @returns the storage class or StorageClass::kNone if none matched
ast::StorageClass variable_storage_decoration(); ast::StorageClass variable_storage_decoration();

View File

@ -34,6 +34,11 @@ TEST_F(ParserImplTest, GlobalConstantDecl) {
ASSERT_NE(e->type(), nullptr); ASSERT_NE(e->type(), nullptr);
EXPECT_TRUE(e->type()->IsF32()); 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); ASSERT_NE(e->constructor(), nullptr);
EXPECT_TRUE(e->constructor()->IsConstructor()); EXPECT_TRUE(e->constructor()->IsConstructor());
} }

View File

@ -33,6 +33,11 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) {
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); 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_EQ(e->constructor(), nullptr);
ASSERT_FALSE(e->IsDecorated()); ASSERT_FALSE(e->IsDecorated());
} }
@ -47,6 +52,11 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); 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_NE(e->constructor(), nullptr);
ASSERT_TRUE(e->constructor()->IsConstructor()); ASSERT_TRUE(e->constructor()->IsConstructor());
ASSERT_TRUE(e->constructor()->AsConstructor()->IsScalarConstructor()); ASSERT_TRUE(e->constructor()->AsConstructor()->IsScalarConstructor());
@ -66,6 +76,11 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); 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_EQ(e->constructor(), nullptr);
ASSERT_TRUE(e->IsDecorated()); ASSERT_TRUE(e->IsDecorated());
@ -89,6 +104,11 @@ TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration_MulitpleGroups) {
EXPECT_TRUE(e->type()->IsF32()); EXPECT_TRUE(e->type()->IsF32());
EXPECT_EQ(e->storage_class(), ast::StorageClass::kOutput); 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_EQ(e->constructor(), nullptr);
ASSERT_TRUE(e->IsDecorated()); ASSERT_TRUE(e->IsDecorated());

View File

@ -39,6 +39,11 @@ TEST_F(ParserImplTest, ParamList_Single) {
EXPECT_EQ(e[0]->name(), "a"); EXPECT_EQ(e[0]->name(), "a");
EXPECT_EQ(e[0]->type(), i32); EXPECT_EQ(e[0]->type(), i32);
EXPECT_TRUE(e[0]->is_const()); 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) { TEST_F(ParserImplTest, ParamList_Multiple) {
@ -55,13 +60,28 @@ TEST_F(ParserImplTest, ParamList_Multiple) {
EXPECT_EQ(e[0]->type(), i32); EXPECT_EQ(e[0]->type(), i32);
EXPECT_TRUE(e[0]->is_const()); 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]->name(), "b");
EXPECT_EQ(e[1]->type(), f32); EXPECT_EQ(e[1]->type(), f32);
EXPECT_TRUE(e[1]->is_const()); 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]->name(), "c");
EXPECT_EQ(e[2]->type(), vec2); 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) { TEST_F(ParserImplTest, ParamList_Empty) {

View File

@ -35,6 +35,11 @@ TEST_F(ParserImplTest, StructMember_Parses) {
EXPECT_EQ(m->name(), "a"); EXPECT_EQ(m->name(), "a");
EXPECT_EQ(m->type(), i32); EXPECT_EQ(m->type(), i32);
EXPECT_EQ(m->decorations().size(), 0u); 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) { TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
@ -50,6 +55,11 @@ TEST_F(ParserImplTest, StructMember_ParsesWithDecoration) {
EXPECT_EQ(m->decorations().size(), 1u); EXPECT_EQ(m->decorations().size(), 1u);
EXPECT_TRUE(m->decorations()[0]->IsOffset()); EXPECT_TRUE(m->decorations()[0]->IsOffset());
EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u); 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) { TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
@ -68,6 +78,11 @@ TEST_F(ParserImplTest, StructMember_ParsesWithMultipleDecorations) {
EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u); EXPECT_EQ(m->decorations()[0]->AsOffset()->offset(), 2u);
EXPECT_TRUE(m->decorations()[1]->IsOffset()); EXPECT_TRUE(m->decorations()[1]->IsOffset());
EXPECT_EQ(m->decorations()[1]->AsOffset()->offset(), 4u); 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) { TEST_F(ParserImplTest, StructMember_InvalidDecoration) {

View File

@ -29,9 +29,12 @@ TEST_F(ParserImplTest, VariableDecl_Parses) {
ASSERT_NE(var, nullptr); ASSERT_NE(var, nullptr);
ASSERT_EQ(var->name(), "my_var"); ASSERT_EQ(var->name(), "my_var");
ASSERT_NE(var->type(), nullptr); 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_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) { TEST_F(ParserImplTest, VariableDecl_MissingVar) {
@ -60,6 +63,11 @@ TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
EXPECT_EQ(v->name(), "my_var"); EXPECT_EQ(v->name(), "my_var");
EXPECT_TRUE(v->type()->IsF32()); EXPECT_TRUE(v->type()->IsF32());
EXPECT_EQ(v->storage_class(), ast::StorageClass::kPrivate); 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) { TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {

View File

@ -23,23 +23,24 @@ namespace {
TEST_F(ParserImplTest, VariableIdentDecl_Parses) { TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
auto* p = parser("my_var : f32"); auto* p = parser("my_var : f32");
std::string name; auto decl = p->variable_ident_decl();
ast::type::Type* type;
std::tie(name, type) = p->variable_ident_decl();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(name, "my_var"); ASSERT_EQ(decl.name, "my_var");
ASSERT_NE(type, nullptr); ASSERT_NE(decl.type, nullptr);
ASSERT_TRUE(type->IsF32()); 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) { TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) {
auto* p = parser(": f32"); auto* p = parser(": f32");
std::string name; auto decl = p->variable_ident_decl();
ast::type::Type* type;
std::tie(name, type) = p->variable_ident_decl();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(name, ""); ASSERT_EQ(decl.name, "");
ASSERT_EQ(type, nullptr); ASSERT_EQ(decl.type, nullptr);
auto t = p->next(); auto t = p->next();
ASSERT_TRUE(t.IsColon()); ASSERT_TRUE(t.IsColon());
@ -61,12 +62,10 @@ TEST_F(ParserImplTest, VariableIdentDecl_MissingType) {
TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) { TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
auto* p = parser("123 : f32"); auto* p = parser("123 : f32");
std::string name; auto decl = p->variable_ident_decl();
ast::type::Type* type;
std::tie(name, type) = p->variable_ident_decl();
ASSERT_FALSE(p->has_error()); ASSERT_FALSE(p->has_error());
ASSERT_EQ(name, ""); ASSERT_EQ(decl.name, "");
ASSERT_EQ(type, nullptr); ASSERT_EQ(decl.type, nullptr);
auto t = p->next(); auto t = p->next();
ASSERT_TRUE(t.IsSintLiteral()); ASSERT_TRUE(t.IsSintLiteral());

View File

@ -32,6 +32,11 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
ASSERT_NE(e->variable(), nullptr); ASSERT_NE(e->variable(), nullptr);
EXPECT_EQ(e->variable()->name(), "a"); 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); EXPECT_EQ(e->variable()->constructor(), nullptr);
} }
@ -44,6 +49,11 @@ TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
ASSERT_NE(e->variable(), nullptr); ASSERT_NE(e->variable(), nullptr);
EXPECT_EQ(e->variable()->name(), "a"); 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); ASSERT_NE(e->variable()->constructor(), nullptr);
EXPECT_TRUE(e->variable()->constructor()->IsConstructor()); EXPECT_TRUE(e->variable()->constructor()->IsConstructor());
} }
@ -70,6 +80,11 @@ TEST_F(ParserImplTest, VariableStmt_Const) {
ASSERT_FALSE(p->has_error()) << p->error(); ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr); ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsVariableDecl()); 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) { TEST_F(ParserImplTest, VariableStmt_Const_InvalidVarIdent) {

View File

@ -67,9 +67,18 @@ TEST_F(TokenTest, ReturnsMaxU32) {
} }
TEST_F(TokenTest, Source) { 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.line, 3u);
EXPECT_EQ(t.source().range.begin.column, 9u); 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 } // namespace