diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 3c3a1ea680..0a0998fba8 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -110,6 +110,7 @@ const char kBindingDecoration[] = "binding"; const char kBlockDecoration[] = "block"; const char kBuiltinDecoration[] = "builtin"; const char kGroupDecoration[] = "group"; +const char kInterpolateDecoration[] = "interpolate"; const char kLocationDecoration[] = "location"; const char kOverrideDecoration[] = "override"; const char kSizeDecoration[] = "size"; @@ -126,9 +127,9 @@ bool is_decoration(Token t) { auto s = t.to_str(); return s == kAlignDecoration || s == kBindingDecoration || s == kBlockDecoration || s == kBuiltinDecoration || - s == kGroupDecoration || s == kLocationDecoration || - s == kOverrideDecoration || s == kSetDecoration || - s == kSizeDecoration || s == kStageDecoration || + s == kGroupDecoration || s == kInterpolateDecoration || + s == kLocationDecoration || s == kOverrideDecoration || + s == kSetDecoration || s == kSizeDecoration || s == kStageDecoration || s == kStrideDecoration || s == kWorkgroupSizeDecoration; } @@ -2995,6 +2996,41 @@ Maybe ParserImpl::decoration() { }); } + if (s == kInterpolateDecoration) { + return expect_paren_block("interpolate decoration", [&]() -> Result { + ast::InterpolationType type; + ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone; + + auto type_tok = next(); + auto type_str = type_tok.to_str(); + if (type_str == "perspective") { + type = ast::InterpolationType::kPerspective; + } else if (type_str == "linear") { + type = ast::InterpolationType::kLinear; + } else if (type_str == "flat") { + type = ast::InterpolationType::kFlat; + } else { + return add_error(type_tok, "invalid interpolation type"); + } + + if (match(Token::Type::kComma)) { + auto sampling_tok = next(); + auto sampling_str = sampling_tok.to_str(); + if (sampling_str == "center") { + sampling = ast::InterpolationSampling::kCenter; + } else if (sampling_str == "centroid") { + sampling = ast::InterpolationSampling::kCentroid; + } else if (sampling_str == "sample") { + sampling = ast::InterpolationSampling::kSample; + } else { + return add_error(sampling_tok, "invalid interpolation sampling"); + } + } + + return create(t.source(), type, sampling); + }); + } + if (s == kBuiltinDecoration) { return expect_paren_block("builtin decoration", [&]() -> Result { auto builtin = expect_builtin(); diff --git a/src/reader/wgsl/parser_impl_variable_decoration_test.cc b/src/reader/wgsl/parser_impl_variable_decoration_test.cc index 33b1d107b4..5e0696b9f5 100644 --- a/src/reader/wgsl/parser_impl_variable_decoration_test.cc +++ b/src/reader/wgsl/parser_impl_variable_decoration_test.cc @@ -174,6 +174,130 @@ TEST_F(ParserImplTest, Decoration_Builtin_MissingInvalid) { EXPECT_EQ(p->error(), "1:9: expected identifier for builtin"); } +TEST_F(ParserImplTest, Decoration_Interpolate_Flat) { + auto p = parser("interpolate(flat)"); + auto deco = p->decoration(); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto* var_deco = deco.value->As(); + ASSERT_NE(var_deco, nullptr); + ASSERT_FALSE(p->has_error()); + ASSERT_TRUE(var_deco->Is()); + + auto* interp = var_deco->As(); + EXPECT_EQ(interp->type(), ast::InterpolationType::kFlat); + EXPECT_EQ(interp->sampling(), ast::InterpolationSampling::kNone); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_Perspective_Center) { + auto p = parser("interpolate(perspective, center)"); + auto deco = p->decoration(); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto* var_deco = deco.value->As(); + ASSERT_NE(var_deco, nullptr); + ASSERT_FALSE(p->has_error()); + ASSERT_TRUE(var_deco->Is()); + + auto* interp = var_deco->As(); + EXPECT_EQ(interp->type(), ast::InterpolationType::kPerspective); + EXPECT_EQ(interp->sampling(), ast::InterpolationSampling::kCenter); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_Perspective_Centroid) { + auto p = parser("interpolate(perspective, centroid)"); + auto deco = p->decoration(); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto* var_deco = deco.value->As(); + ASSERT_NE(var_deco, nullptr); + ASSERT_FALSE(p->has_error()); + ASSERT_TRUE(var_deco->Is()); + + auto* interp = var_deco->As(); + EXPECT_EQ(interp->type(), ast::InterpolationType::kPerspective); + EXPECT_EQ(interp->sampling(), ast::InterpolationSampling::kCentroid); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_Linear_Sample) { + auto p = parser("interpolate(linear, sample)"); + auto deco = p->decoration(); + EXPECT_TRUE(deco.matched); + EXPECT_FALSE(deco.errored); + ASSERT_NE(deco.value, nullptr); + auto* var_deco = deco.value->As(); + ASSERT_NE(var_deco, nullptr); + ASSERT_FALSE(p->has_error()); + ASSERT_TRUE(var_deco->Is()); + + auto* interp = var_deco->As(); + EXPECT_EQ(interp->type(), ast::InterpolationType::kLinear); + EXPECT_EQ(interp->sampling(), ast::InterpolationSampling::kSample); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_MissingLeftParen) { + auto p = parser("interpolate flat)"); + auto deco = p->decoration(); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:13: expected '(' for interpolate decoration"); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_MissingRightParen) { + auto p = parser("interpolate(flat"); + auto deco = p->decoration(); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:17: expected ')' for interpolate decoration"); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_MissingFirstValue) { + auto p = parser("interpolate()"); + auto deco = p->decoration(); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:13: invalid interpolation type"); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_InvalidFirstValue) { + auto p = parser("interpolate(other_thingy)"); + auto deco = p->decoration(); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:13: invalid interpolation type"); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_MissingSecondValue) { + auto p = parser("interpolate(perspective,)"); + auto deco = p->decoration(); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:25: invalid interpolation sampling"); +} + +TEST_F(ParserImplTest, Decoration_Interpolate_InvalidSecondValue) { + auto p = parser("interpolate(perspective, nope)"); + auto deco = p->decoration(); + EXPECT_FALSE(deco.matched); + EXPECT_TRUE(deco.errored); + EXPECT_EQ(deco.value, nullptr); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:26: invalid interpolation sampling"); +} + TEST_F(ParserImplTest, Decoration_Binding) { auto p = parser("binding(4)"); auto deco = p->decoration();