From 97e0c71eb6a3804e94936835faa5cf5ae91706dc Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Fri, 19 Aug 2022 22:16:21 +0000 Subject: [PATCH] Add new shift expression grammar rule. This CL adds the `shift_expression.post.unary_expression` grammar rule into the WGSL parser. Bug: tint:1633 Change-Id: I833ddb05399afe8c792bd0b1abf3eda7f1d114e7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/99760 Commit-Queue: Dan Sinclair Reviewed-by: Ben Clayton --- src/tint/reader/wgsl/parser_impl.cc | 35 +++++ src/tint/reader/wgsl/parser_impl.h | 5 + .../wgsl/parser_impl_shift_expression_test.cc | 123 +++++++++++++++++- 3 files changed, 156 insertions(+), 7 deletions(-) diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc index 733a2ea8e3..16070a0db6 100644 --- a/src/tint/reader/wgsl/parser_impl.cc +++ b/src/tint/reader/wgsl/parser_impl.cc @@ -2800,6 +2800,41 @@ Maybe ParserImpl::element_count_expression() { return math.value; } +// shift_expression.post.unary_expression +// : multiplicative_expression.post.unary_expression? +// | SHIFT_LEFT unary_expression +// | SHIFT_RIGHT unary_expression +// +// Note, add the `multiplicative_expression.post.unary_expression` is added here to make +// implementation simpler. +Expect ParserImpl::expect_shift_expression_post_unary_expression( + const ast::Expression* lhs) { + auto& t = peek(); + if (match(Token::Type::kShiftLeft) || match(Token::Type::kShiftRight)) { + std::string name; + ast::BinaryOp op = ast::BinaryOp::kNone; + if (t.Is(Token::Type::kShiftLeft)) { + op = ast::BinaryOp::kShiftLeft; + name = "<<"; + } else if (t.Is(Token::Type::kShiftRight)) { + op = ast::BinaryOp::kShiftRight; + name = ">>"; + } + + auto rhs = unary_expression(); + if (rhs.errored) { + return Failure::kErrored; + } + if (!rhs.matched) { + return add_error(t, + std::string("unable to parse right side of ") + name + " expression"); + } + return create(t.source(), op, lhs, rhs.value); + } + + return expect_multiplicative_expression_post_unary_expression(lhs); +} + // singular_expression // : primary_expression postfix_expr Maybe ParserImpl::singular_expression() { diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h index d822450e0a..3ac410a759 100644 --- a/src/tint/reader/wgsl/parser_impl.h +++ b/src/tint/reader/wgsl/parser_impl.h @@ -667,6 +667,11 @@ class ParserImpl { /// Parses an `element_count_expression` grammar element /// @returns the parsed expression or nullptr Maybe element_count_expression(); + /// Parses a `shift_expression.post.unary_expression` grammar element + /// @param lhs the left side of the expression + /// @returns the parsed expression or `lhs` if no match + Expect expect_shift_expression_post_unary_expression( + const ast::Expression* lhs); /// Parse the `additive_operator` grammar element /// @returns the parsed operator if successful Maybe additive_operator(); diff --git a/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc b/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc index 83c1255e9d..edf15199d6 100644 --- a/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc +++ b/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc @@ -17,7 +17,7 @@ namespace tint::reader::wgsl { namespace { -TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { +TEST_F(ParserImplTest, ShiftExpression_Orig_Parses_ShiftLeft) { auto p = parser("a << true"); auto e = p->shift_expression(); EXPECT_TRUE(e.matched); @@ -42,7 +42,7 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { ASSERT_TRUE(rel->rhs->As()->value); } -TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { +TEST_F(ParserImplTest, ShiftExpression_Orig_Parses_ShiftRight) { auto p = parser("a >> true"); auto e = p->shift_expression(); EXPECT_TRUE(e.matched); @@ -67,7 +67,7 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { ASSERT_TRUE(rel->rhs->As()->value); } -TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceLeft) { +TEST_F(ParserImplTest, ShiftExpression_Orig_InvalidSpaceLeft) { auto p = parser("a < < true"); auto e = p->shift_expression(); EXPECT_TRUE(e.matched); @@ -76,7 +76,7 @@ TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceLeft) { EXPECT_FALSE(e.value->Is()); } -TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceRight) { +TEST_F(ParserImplTest, ShiftExpression_Orig_InvalidSpaceRight) { auto p = parser("a > > true"); auto e = p->shift_expression(); EXPECT_TRUE(e.matched); @@ -85,7 +85,7 @@ TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceRight) { EXPECT_FALSE(e.value->Is()); } -TEST_F(ParserImplTest, ShiftExpression_InvalidLHS) { +TEST_F(ParserImplTest, ShiftExpression_Orig_InvalidLHS) { auto p = parser("if (a) {} << true"); auto e = p->shift_expression(); EXPECT_FALSE(e.matched); @@ -94,7 +94,7 @@ TEST_F(ParserImplTest, ShiftExpression_InvalidLHS) { EXPECT_EQ(e.value, nullptr); } -TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) { +TEST_F(ParserImplTest, ShiftExpression_Orig_InvalidRHS) { auto p = parser("true << if (a) {}"); auto e = p->shift_expression(); EXPECT_FALSE(e.matched); @@ -104,7 +104,7 @@ TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) { EXPECT_EQ(p->error(), "1:9: unable to parse right side of << expression"); } -TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) { +TEST_F(ParserImplTest, ShiftExpression_Orig_NoOr_ReturnsLHS) { auto p = parser("a true"); auto e = p->shift_expression(); EXPECT_TRUE(e.matched); @@ -114,5 +114,114 @@ TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) { ASSERT_TRUE(e->Is()); } +TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { + auto p = parser("a << true"); + auto lhs = p->unary_expression(); + auto e = p->expect_shift_expression_post_unary_expression(lhs.value); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + + EXPECT_EQ(e->source.range.begin.line, 1u); + EXPECT_EQ(e->source.range.begin.column, 3u); + EXPECT_EQ(e->source.range.end.line, 1u); + EXPECT_EQ(e->source.range.end.column, 5u); + + ASSERT_TRUE(e->Is()); + auto* rel = e->As(); + EXPECT_EQ(ast::BinaryOp::kShiftLeft, rel->op); + + ASSERT_TRUE(rel->lhs->Is()); + auto* ident = rel->lhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a")); + + ASSERT_TRUE(rel->rhs->Is()); + ASSERT_TRUE(rel->rhs->As()->value); +} + +TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { + auto p = parser("a >> true"); + auto lhs = p->unary_expression(); + auto e = p->expect_shift_expression_post_unary_expression(lhs.value); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + + EXPECT_EQ(e->source.range.begin.line, 1u); + EXPECT_EQ(e->source.range.begin.column, 3u); + EXPECT_EQ(e->source.range.end.line, 1u); + EXPECT_EQ(e->source.range.end.column, 5u); + + ASSERT_TRUE(e->Is()); + auto* rel = e->As(); + EXPECT_EQ(ast::BinaryOp::kShiftRight, rel->op); + + ASSERT_TRUE(rel->lhs->Is()); + auto* ident = rel->lhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a")); + + ASSERT_TRUE(rel->rhs->Is()); + ASSERT_TRUE(rel->rhs->As()->value); +} + +TEST_F(ParserImplTest, ShiftExpression_Parses_Multiplicative) { + auto p = parser("a * b"); + auto lhs = p->unary_expression(); + auto e = p->expect_shift_expression_post_unary_expression(lhs.value); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + + ASSERT_TRUE(e->Is()); + auto* rel = e->As(); + EXPECT_EQ(ast::BinaryOp::kMultiply, rel->op); + + ASSERT_TRUE(rel->lhs->Is()); + auto* ident = rel->lhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a")); + + ASSERT_TRUE(rel->rhs->Is()); + ident = rel->rhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("b")); +} + +TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceLeft) { + auto p = parser("a < < true"); + auto lhs = p->unary_expression(); + auto e = p->expect_shift_expression_post_unary_expression(lhs.value); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + EXPECT_FALSE(e.value->Is()); +} + +TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceRight) { + auto p = parser("a > > true"); + auto lhs = p->unary_expression(); + auto e = p->expect_shift_expression_post_unary_expression(lhs.value); + EXPECT_FALSE(e.errored); + ASSERT_NE(e.value, nullptr); + EXPECT_FALSE(e.value->Is()); +} + +TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) { + auto p = parser("a << if (a) {}"); + auto lhs = p->unary_expression(); + auto e = p->expect_shift_expression_post_unary_expression(lhs.value); + EXPECT_TRUE(e.errored); + EXPECT_TRUE(p->has_error()); + EXPECT_EQ(e.value, nullptr); + EXPECT_EQ(p->error(), "1:3: unable to parse right side of << expression"); +} + +TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) { + auto p = parser("a true"); + auto lhs = p->unary_expression(); + auto e = p->expect_shift_expression_post_unary_expression(lhs.value); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + ASSERT_EQ(lhs.value, e.value); +} + } // namespace } // namespace tint::reader::wgsl