Make attribute grammar generic.

This Cl updates the parser to use a generic attribute grammar.

Bug: tint:1845
Change-Id: Icd600a2d87f03972f60d89b27fe0eef7be7667d5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/121100
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair 2023-02-23 18:34:08 +00:00 committed by Dawn LUCI CQ
parent 20a82acf6a
commit 869bcabf88
10 changed files with 174 additions and 226 deletions

View File

@ -2984,85 +2984,12 @@ Expect<const ast::Attribute*> ParserImpl::expect_attribute() {
}
// attribute
// : ATTR 'align' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'binding' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'builtin' PAREN_LEFT builtin_value_name COMMA? PAREN_RIGHT
// | ATTR 'const'
// | ATTR 'diagnostic' diagnostic_control
// | ATTR 'group' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'id' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'interpolate' PAREN_LEFT interpolation_type_name COMMA? PAREN_RIGHT
// | ATTR 'interpolate' PAREN_LEFT interpolation_type_name COMMA
// interpolation_sample_name COMMA? PAREN_RIGHT
// | ATTR 'invariant'
// | ATTR 'location' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'must_use'
// | ATTR 'size' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'workgroup_size' PAREN_LEFT expression COMMA? PAREN_RIGHT
// | ATTR 'workgroup_size' PAREN_LEFT expression COMMA expression COMMA? PAREN_RIGHT
// | ATTR 'workgroup_size' PAREN_LEFT expression COMMA expression COMMA
// expression COMMA? PAREN_RIGHT
// | ATTR 'vertex'
// | ATTR 'fragment'
// | ATTR 'compute'
// : ATTR identifier ( PAREN_LEFT expression ( COMMA expression )? COMMA? PAREN_RIGHT )?
Maybe<const ast::Attribute*> ParserImpl::attribute() {
using Result = Maybe<const ast::Attribute*>;
// Note, the ATTR is matched by the called `attribute_list` in this case, so it is not matched
// here and this has to be an attribute.
auto& t = next();
if (!t.IsIdentifier() && !(t.Is(Token::Type::kDiagnostic))) {
return Failure::kNoMatch;
}
if (t == "align") {
const char* use = "align attribute";
return expect_paren_block(use, [&]() -> Result {
auto expr = expression();
if (expr.errored) {
return Failure::kErrored;
}
if (!expr.matched) {
return add_error(peek(), "expected align expression");
}
match(Token::Type::kComma);
return create<ast::StructMemberAlignAttribute>(t.source(), expr.value);
});
}
if (t == "binding") {
const char* use = "binding attribute";
return expect_paren_block(use, [&]() -> Result {
auto expr = expression();
if (expr.errored) {
return Failure::kErrored;
}
if (!expr.matched) {
return add_error(peek(), "expected binding expression");
}
match(Token::Type::kComma);
return create<ast::BindingAttribute>(t.source(), expr.value);
});
}
if (t == "builtin") {
return expect_paren_block("builtin attribute", [&]() -> Result {
auto builtin = expect_expression("builtin name");
if (builtin.errored) {
return Failure::kErrored;
}
match(Token::Type::kComma);
return create<ast::BuiltinAttribute>(t.source(), builtin.value);
});
}
if (t == "compute") {
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kCompute);
}
// Note, `const` is not valid in a WGSL source file, it's internal only
if (t.Is(Token::Type::kDiagnostic)) {
auto control = expect_diagnostic_control();
if (control.errored) {
@ -3071,152 +2998,173 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
return create<ast::DiagnosticAttribute>(t.source(), std::move(control.value));
}
if (!t.IsIdentifier()) {
return Failure::kNoMatch;
}
utils::Vector<const ast::Expression*, 2> exprs;
auto parse = [&](uint32_t min, uint32_t max) -> Maybe<bool> {
// Handle no parameter items which should have no parens
if (min == 0) {
auto& p = peek();
if (p.Is(Token::Type::kParenLeft)) {
return add_error(p.source(), t.to_str() + " attribute doesn't take parenthesis");
}
return true;
}
auto res = expect_paren_block(t.to_str() + " attribute", [&]() -> Expect<bool> {
while (continue_parsing()) {
if (peek().Is(Token::Type::kParenRight)) {
break;
}
auto expr = expect_expression(t.to_str());
if (expr.errored) {
return Failure::kErrored;
}
exprs.Push(expr.value);
if (!match(Token::Type::kComma)) {
break;
}
}
return true;
});
if (res.errored) {
return Failure::kErrored;
}
if (exprs.IsEmpty() || exprs.Length() < min) {
return add_error(t.source(),
t.to_str() + " expects" + (min != max ? " at least " : " ") +
std::to_string(min) + " argument" + (min > 1 ? "s" : ""));
}
if (exprs.Length() > max) {
return add_error(t.source(),
t.to_str() + " expects" + (min != max ? " at most " : " ") +
std::to_string(max) + " argument" + (max > 1 ? "s" : "") +
", got " + std::to_string(exprs.Length()));
}
return true;
};
if (t == "align") {
auto res = parse(1, 1);
if (res.errored) {
return Failure::kErrored;
}
return create<ast::StructMemberAlignAttribute>(t.source(), exprs[0]);
}
if (t == "binding") {
auto res = parse(1, 1);
if (res.errored) {
return Failure::kErrored;
}
return create<ast::BindingAttribute>(t.source(), exprs[0]);
}
if (t == "builtin") {
auto res = parse(1, 1);
if (res.errored) {
return Failure::kErrored;
}
return create<ast::BuiltinAttribute>(t.source(), exprs[0]);
}
if (t == "compute") {
auto res = parse(0, 0);
if (res.errored) {
return Failure::kErrored;
}
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kCompute);
}
// Note, `const` is not valid in a WGSL source file, it's internal only
if (t == "fragment") {
auto res = parse(0, 0);
if (res.errored) {
return Failure::kErrored;
}
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kFragment);
}
if (t == "group") {
const char* use = "group attribute";
return expect_paren_block(use, [&]() -> Result {
auto expr = expression();
if (expr.errored) {
auto res = parse(1, 1);
if (res.errored) {
return Failure::kErrored;
}
if (!expr.matched) {
return add_error(peek(), "expected group expression");
}
match(Token::Type::kComma);
return create<ast::GroupAttribute>(t.source(), expr.value);
});
return create<ast::GroupAttribute>(t.source(), exprs[0]);
}
if (t == "id") {
const char* use = "id attribute";
return expect_paren_block(use, [&]() -> Result {
auto expr = expression();
if (expr.errored) {
auto res = parse(1, 1);
if (res.errored) {
return Failure::kErrored;
}
if (!expr.matched) {
return add_error(peek(), "expected id expression");
}
match(Token::Type::kComma);
return create<ast::IdAttribute>(t.source(), expr.value);
});
return create<ast::IdAttribute>(t.source(), exprs[0]);
}
if (t == "interpolate") {
return expect_paren_block("interpolate attribute", [&]() -> Result {
auto type = expect_expression("interpolation type");
if (type.errored) {
auto res = parse(1, 2);
if (res.errored) {
return Failure::kErrored;
}
const ast::Expression* sampling = nullptr;
if (match(Token::Type::kComma)) {
if (!peek_is(Token::Type::kParenRight)) {
auto sample = expect_expression("interpolation sampling");
if (sample.errored) {
return Failure::kErrored;
}
sampling = sample.value;
match(Token::Type::kComma);
}
}
return create<ast::InterpolateAttribute>(t.source(), type.value, sampling);
});
return create<ast::InterpolateAttribute>(t.source(), exprs[0],
exprs.Length() == 2 ? exprs[1] : nullptr);
}
if (t == "invariant") {
auto res = parse(0, 0);
if (res.errored) {
return Failure::kErrored;
}
return create<ast::InvariantAttribute>(t.source());
}
if (t == "location") {
const char* use = "location attribute";
return expect_paren_block(use, [&]() -> Result {
auto expr = expression();
if (expr.errored) {
auto res = parse(1, 1);
if (res.errored) {
return Failure::kErrored;
}
if (!expr.matched) {
return add_error(peek(), "expected location expression");
}
match(Token::Type::kComma);
return builder_.Location(t.source(), expr.value);
});
return builder_.Location(t.source(), exprs[0]);
}
if (t == "must_use") {
auto res = parse(0, 0);
if (res.errored) {
return Failure::kErrored;
}
return create<ast::MustUseAttribute>(t.source());
}
if (t == "size") {
const char* use = "size attribute";
return expect_paren_block(use, [&]() -> Result {
auto expr = expression();
if (expr.errored) {
auto res = parse(1, 1);
if (res.errored) {
return Failure::kErrored;
}
if (!expr.matched) {
return add_error(peek(), "expected size expression");
}
match(Token::Type::kComma);
return builder_.MemberSize(t.source(), expr.value);
});
return builder_.MemberSize(t.source(), exprs[0]);
}
if (t == "vertex") {
auto res = parse(0, 0);
if (res.errored) {
return Failure::kErrored;
}
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kVertex);
}
if (t == "workgroup_size") {
return expect_paren_block("workgroup_size attribute", [&]() -> Result {
const ast::Expression* x = nullptr;
const ast::Expression* y = nullptr;
const ast::Expression* z = nullptr;
auto expr = expression();
if (expr.errored) {
auto res = parse(1, 3);
if (res.errored) {
return Failure::kErrored;
} else if (!expr.matched) {
return add_error(peek(), "expected workgroup_size x parameter");
}
x = std::move(expr.value);
if (match(Token::Type::kComma)) {
if (!peek_is(Token::Type::kParenRight)) {
expr = expression();
if (expr.errored) {
return Failure::kErrored;
} else if (!expr.matched) {
return add_error(peek(), "expected workgroup_size y parameter");
}
y = std::move(expr.value);
if (match(Token::Type::kComma)) {
if (!peek_is(Token::Type::kParenRight)) {
expr = expression();
if (expr.errored) {
return Failure::kErrored;
} else if (!expr.matched) {
return add_error(peek(), "expected workgroup_size z parameter");
}
z = std::move(expr.value);
match(Token::Type::kComma);
}
}
}
}
return create<ast::WorkgroupAttribute>(t.source(), x, y, z);
});
return create<ast::WorkgroupAttribute>(t.source(), exprs[0],
exprs.Length() > 1 ? exprs[1] : nullptr,
exprs.Length() > 2 ? exprs[2] : nullptr);
}
return Failure::kNoMatch;
}

View File

@ -353,15 +353,15 @@ fn f() { const_assert true }
TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeXInvalid) {
EXPECT("@workgroup_size() fn f() {}",
R"(test.wgsl:1:17 error: expected workgroup_size x parameter
R"(test.wgsl:1:2 error: workgroup_size expects at least 1 argument
@workgroup_size() fn f() {}
^
^^^^^^^^^^^^^^
)");
}
TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeYInvalid) {
EXPECT("@workgroup_size(1, fn) fn f() {}",
R"(test.wgsl:1:20 error: expected workgroup_size y parameter
R"(test.wgsl:1:20 error: expected expression for workgroup_size
@workgroup_size(1, fn) fn f() {}
^^
)");
@ -369,7 +369,7 @@ TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeYInvalid) {
TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeZInvalid) {
EXPECT("@workgroup_size(1, 2, fn) fn f() {}",
R"(test.wgsl:1:23 error: expected workgroup_size z parameter
R"(test.wgsl:1:23 error: expected expression for workgroup_size
@workgroup_size(1, 2, fn) fn f() {}
^^
)");
@ -672,7 +672,7 @@ struct S { 1 : i32, };
TEST_F(ParserImplErrorTest, GlobalDeclStructMemberAlignInvaldValue) {
EXPECT("struct S { @align(fn) i : i32, };",
R"(test.wgsl:1:19 error: expected align expression
R"(test.wgsl:1:19 error: expected expression for align
struct S { @align(fn) i : i32, };
^^
)");
@ -680,7 +680,7 @@ struct S { @align(fn) i : i32, };
TEST_F(ParserImplErrorTest, GlobalDeclStructMemberSizeInvaldValue) {
EXPECT("struct S { @size(if) i : i32, };",
R"(test.wgsl:1:18 error: expected size expression
R"(test.wgsl:1:18 error: expected expression for size
struct S { @size(if) i : i32, };
^^
)");
@ -761,7 +761,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarAttrLocationMissingRParen) {
TEST_F(ParserImplErrorTest, GlobalDeclVarAttrLocationInvalidValue) {
EXPECT("@location(if) var i : i32;",
R"(test.wgsl:1:11 error: expected location expression
R"(test.wgsl:1:11 error: expected expression for location
@location(if) var i : i32;
^^
)");
@ -785,7 +785,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarAttrIdMissingRParen) {
TEST_F(ParserImplErrorTest, GlobalDeclVarAttrIdInvalidValue) {
EXPECT("@id(if) var i : i32;",
R"(test.wgsl:1:5 error: expected id expression
R"(test.wgsl:1:5 error: expected expression for id
@id(if) var i : i32;
^^
)");
@ -825,7 +825,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingMissingRParen) {
TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingInvalidValue) {
EXPECT("@binding(if) var i : i32;",
R"(test.wgsl:1:10 error: expected binding expression
R"(test.wgsl:1:10 error: expected expression for binding
@binding(if) var i : i32;
^^
)");
@ -849,7 +849,7 @@ TEST_F(ParserImplErrorTest, GlobalDeclVarAttrGroupMissingRParen) {
TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingGroupValue) {
EXPECT("@group(if) var i : i32;",
R"(test.wgsl:1:8 error: expected group expression
R"(test.wgsl:1:8 error: expected expression for group
@group(if) var i : i32;
^^
)");

View File

@ -100,7 +100,7 @@ TEST_F(ParserImplTest, Attribute_Workgroup_1Param_TrailingComma_Double) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:18: expected workgroup_size y parameter");
EXPECT_EQ(p->error(), "1:18: expected expression for workgroup_size");
}
TEST_F(ParserImplTest, Attribute_Workgroup_2Param) {
@ -195,7 +195,7 @@ TEST_F(ParserImplTest, Attribute_Workgroup21Param_TrailingComma_Double) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:20: expected workgroup_size z parameter");
EXPECT_EQ(p->error(), "1:20: expected expression for workgroup_size");
}
TEST_F(ParserImplTest, Attribute_Workgroup_3Param) {
@ -323,7 +323,7 @@ TEST_F(ParserImplTest, Attribute_Workgroup_TooManyValues) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:25: expected ')' for workgroup_size attribute");
EXPECT_EQ(p->error(), "1:1: workgroup_size expects at most 3 arguments, got 4");
}
TEST_F(ParserImplTest, Attribute_Workgroup_MissingLeftParam) {
@ -353,7 +353,7 @@ TEST_F(ParserImplTest, Attribute_Workgroup_MissingValues) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:16: expected workgroup_size x parameter");
EXPECT_EQ(p->error(), "1:1: workgroup_size expects at least 1 argument");
}
TEST_F(ParserImplTest, Attribute_Workgroup_Missing_X_Value) {
@ -363,7 +363,7 @@ TEST_F(ParserImplTest, Attribute_Workgroup_Missing_X_Value) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:16: expected workgroup_size x parameter");
EXPECT_EQ(p->error(), "1:16: expected expression for workgroup_size");
}
TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Y_Comma) {
@ -383,7 +383,7 @@ TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Y_Value) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:19: expected workgroup_size y parameter");
EXPECT_EQ(p->error(), "1:19: expected expression for workgroup_size");
}
TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Z_Comma) {

View File

@ -138,7 +138,7 @@ TEST_F(ParserImplTest, GlobalVariableDecl_InvalidAttribute) {
EXPECT_NE(e.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: expected binding expression");
EXPECT_EQ(p->error(), "1:2: binding expects 1 argument");
}
TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {

View File

@ -46,7 +46,7 @@ TEST_F(ParserImplTest, AttributeDecl_MissingValue) {
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
EXPECT_TRUE(attrs.value.IsEmpty());
EXPECT_EQ(p->error(), "1:11: expected location expression");
EXPECT_EQ(p->error(), "1:2: location expects 1 argument");
}
TEST_F(ParserImplTest, AttributeDecl_MissingParenRight) {

View File

@ -66,7 +66,7 @@ TEST_F(ParserImplTest, StructBodyDecl_InvalidAlign) {
auto m = p->expect_struct_body_decl();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(m.errored);
EXPECT_EQ(p->error(), "3:10: expected align expression");
EXPECT_EQ(p->error(), "3:10: expected expression for align");
}
TEST_F(ParserImplTest, StructBodyDecl_InvalidSize) {
@ -77,7 +77,7 @@ TEST_F(ParserImplTest, StructBodyDecl_InvalidSize) {
auto m = p->expect_struct_body_decl();
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(m.errored);
EXPECT_EQ(p->error(), "3:9: expected size expression");
EXPECT_EQ(p->error(), "3:9: expected expression for size");
}
TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) {

View File

@ -44,7 +44,7 @@ TEST_F(ParserImplTest, AttributeDecl_InvalidAttribute) {
EXPECT_TRUE(p->has_error()) << p->error();
EXPECT_TRUE(attrs.errored);
EXPECT_FALSE(attrs.matched);
EXPECT_EQ(p->error(), "1:7: expected size expression");
EXPECT_EQ(p->error(), "1:7: expected expression for size");
}
} // namespace

View File

@ -104,7 +104,7 @@ TEST_F(ParserImplTest, Attribute_Size_MissingValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:6: expected size expression");
EXPECT_EQ(p->error(), "1:1: size expects 1 argument");
}
TEST_F(ParserImplTest, Attribute_Size_MissingInvalid) {
@ -114,7 +114,7 @@ TEST_F(ParserImplTest, Attribute_Size_MissingInvalid) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:6: expected size expression");
EXPECT_EQ(p->error(), "1:6: expected expression for size");
}
TEST_F(ParserImplTest, Attribute_Align) {
@ -209,7 +209,7 @@ TEST_F(ParserImplTest, Attribute_Align_MissingValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: expected align expression");
EXPECT_EQ(p->error(), "1:1: align expects 1 argument");
}
TEST_F(ParserImplTest, Attribute_Align_ExpressionInvalid) {

View File

@ -115,7 +115,7 @@ TEST_F(ParserImplTest, StructMember_InvalidAttribute) {
ASSERT_EQ(m.value, nullptr);
ASSERT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: expected size expression");
EXPECT_EQ(p->error(), "1:7: expected expression for size");
}
} // namespace

View File

@ -105,7 +105,7 @@ TEST_F(ParserImplTest, Attribute_Id_MissingValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:4: expected id expression");
EXPECT_EQ(p->error(), "1:1: id expects 1 argument");
}
TEST_F(ParserImplTest, Attribute_Id_MissingInvalid) {
@ -115,7 +115,7 @@ TEST_F(ParserImplTest, Attribute_Id_MissingInvalid) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:4: expected id expression");
EXPECT_EQ(p->error(), "1:4: expected expression for id");
}
TEST_F(ParserImplTest, Attribute_Location) {
@ -204,7 +204,7 @@ TEST_F(ParserImplTest, Attribute_Location_MissingValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: expected location expression");
EXPECT_EQ(p->error(), "1:1: location expects 1 argument");
}
TEST_F(ParserImplTest, Attribute_Location_MissingInvalid) {
@ -214,7 +214,7 @@ TEST_F(ParserImplTest, Attribute_Location_MissingInvalid) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:10: expected location expression");
EXPECT_EQ(p->error(), "1:10: expected expression for location");
}
class BuiltinTest : public ParserImplTestWithParam<builtin::BuiltinValue> {};
@ -293,7 +293,7 @@ TEST_F(ParserImplTest, Attribute_Builtin_MissingValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:9: expected expression for builtin name)");
EXPECT_EQ(p->error(), "1:1: builtin expects 1 argument");
}
TEST_F(ParserImplTest, Attribute_Interpolate_Flat) {
@ -335,7 +335,7 @@ TEST_F(ParserImplTest, Attribute_Interpolate_Single_DoubleTrailingComma) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:18: expected expression for interpolation sampling)");
EXPECT_EQ(p->error(), "1:18: expected expression for interpolate");
}
TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Center) {
@ -429,7 +429,7 @@ TEST_F(ParserImplTest, Attribute_Interpolate_MissingFirstValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), R"(1:13: expected expression for interpolation type)");
EXPECT_EQ(p->error(), "1:1: interpolate expects at least 1 argument");
}
TEST_F(ParserImplTest, Attribute_Binding) {
@ -520,7 +520,7 @@ TEST_F(ParserImplTest, Attribute_Binding_MissingValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected binding expression");
EXPECT_EQ(p->error(), "1:1: binding expects 1 argument");
}
TEST_F(ParserImplTest, Attribute_Binding_MissingInvalid) {
@ -530,7 +530,7 @@ TEST_F(ParserImplTest, Attribute_Binding_MissingInvalid) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:9: expected binding expression");
EXPECT_EQ(p->error(), "1:9: expected expression for binding");
}
TEST_F(ParserImplTest, Attribute_group) {
@ -621,7 +621,7 @@ TEST_F(ParserImplTest, Attribute_Group_MissingValue) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: expected group expression");
EXPECT_EQ(p->error(), "1:1: group expects 1 argument");
}
TEST_F(ParserImplTest, Attribute_Group_MissingInvalid) {
@ -631,7 +631,7 @@ TEST_F(ParserImplTest, Attribute_Group_MissingInvalid) {
EXPECT_TRUE(attr.errored);
EXPECT_EQ(attr.value, nullptr);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(p->error(), "1:7: expected group expression");
EXPECT_EQ(p->error(), "1:7: expected expression for group");
}
} // namespace