diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc index 16070a0db6..cf684d3d0b 100644 --- a/src/tint/reader/wgsl/parser_impl.cc +++ b/src/tint/reader/wgsl/parser_impl.cc @@ -2800,6 +2800,19 @@ Maybe ParserImpl::element_count_expression() { return math.value; } +// shift_expression +// : unary_expression shift_expression.post.unary_expression +Maybe ParserImpl::maybe_shift_expression() { + auto lhs = unary_expression(); + if (lhs.errored) { + return Failure::kErrored; + } + if (!lhs.matched) { + return Failure::kNoMatch; + } + return expect_shift_expression_post_unary_expression(lhs.value); +} + // shift_expression.post.unary_expression // : multiplicative_expression.post.unary_expression? // | SHIFT_LEFT unary_expression @@ -2835,6 +2848,66 @@ Expect ParserImpl::expect_shift_expression_post_unary_ex return expect_multiplicative_expression_post_unary_expression(lhs); } +// relational_expression +// : unary_expression relational_expression.post.unary_expression +Maybe ParserImpl::maybe_relational_expression() { + auto lhs = unary_expression(); + if (lhs.errored) { + return Failure::kErrored; + } + if (!lhs.matched) { + return Failure::kNoMatch; + } + return expect_relational_expression_post_unary_expression(lhs.value); +} + +// relational_expression.post.unary_expression +// : shift_expression.post.unary_expression +// | shift_expression.post.unary_expression EQUAL_EQUAL shift_expression +// | shift_expression.post.unary_expression GREATER_THAN shift_expression +// | shift_expression.post.unary_expression GREATER_THAN_EQUAL shift_expression +// | shift_expression.post.unary_expression LESS_THAN shift_expression +// | shift_expression.post.unary_expression LESS_THAN_EQUAL shift_expression +// | shift_expression.post.unary_expression NOT_EQUAL shift_expression +// +// Note, a `shift_expression` element was added to simplify many of the right sides +Expect ParserImpl::expect_relational_expression_post_unary_expression( + const ast::Expression* lhs) { + auto lhs_result = expect_shift_expression_post_unary_expression(lhs); + if (lhs_result.errored) { + return Failure::kErrored; + } + lhs = lhs_result.value; + + auto& t = peek(); + if (match(Token::Type::kEqualEqual) || match(Token::Type::kGreaterThan) || + match(Token::Type::kGreaterThanEqual) || match(Token::Type::kLessThan) || + match(Token::Type::kLessThanEqual) || match(Token::Type::kNotEqual)) { + ast::BinaryOp op = ast::BinaryOp::kNone; + if (t.Is(Token::Type::kLessThan)) { + op = ast::BinaryOp::kLessThan; + } else if (t.Is(Token::Type::kGreaterThan)) { + op = ast::BinaryOp::kGreaterThan; + } else if (t.Is(Token::Type::kLessThanEqual)) { + op = ast::BinaryOp::kLessThanEqual; + } else if (t.Is(Token::Type::kGreaterThanEqual)) { + op = ast::BinaryOp::kGreaterThanEqual; + } + + auto& next = peek(); + auto rhs = maybe_shift_expression(); + if (rhs.errored) { + return Failure::kErrored; + } + if (!rhs.matched) { + return add_error(next, std::string("unable to parse right side of ") + + std::string(t.to_name()) + " expression"); + } + lhs = create(t.source(), op, lhs, rhs.value); + } + return 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 3ac410a759..d6d3cccc54 100644 --- a/src/tint/reader/wgsl/parser_impl.h +++ b/src/tint/reader/wgsl/parser_impl.h @@ -667,11 +667,22 @@ class ParserImpl { /// Parses an `element_count_expression` grammar element /// @returns the parsed expression or nullptr Maybe element_count_expression(); + /// Parses a `unary_expression shift.post.unary_expression` + /// @returns the parsed expression or nullptr + Maybe maybe_shift_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); + /// Parses a `unary_expression relational_expression.post.unary_expression` + /// @returns the parsed expression or nullptr + Maybe maybe_relational_expression(); + /// Parses a `relational_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_relational_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_relational_expression_test.cc b/src/tint/reader/wgsl/parser_impl_relational_expression_test.cc index 7ad161f94b..1c47f879b6 100644 --- a/src/tint/reader/wgsl/parser_impl_relational_expression_test.cc +++ b/src/tint/reader/wgsl/parser_impl_relational_expression_test.cc @@ -17,7 +17,7 @@ namespace tint::reader::wgsl { namespace { -TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) { +TEST_F(ParserImplTest, RelationalExpression_Orig_Parses_LessThan) { auto p = parser("a < true"); auto e = p->relational_expression(); EXPECT_TRUE(e.matched); @@ -42,7 +42,7 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) { ASSERT_TRUE(rel->rhs->As()->value); } -TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) { +TEST_F(ParserImplTest, RelationalExpression_Orig_Parses_GreaterThan) { auto p = parser("a > true"); auto e = p->relational_expression(); EXPECT_TRUE(e.matched); @@ -67,7 +67,7 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) { ASSERT_TRUE(rel->rhs->As()->value); } -TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) { +TEST_F(ParserImplTest, RelationalExpression_Orig_Parses_LessThanEqual) { auto p = parser("a <= true"); auto e = p->relational_expression(); EXPECT_TRUE(e.matched); @@ -92,7 +92,7 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) { ASSERT_TRUE(rel->rhs->As()->value); } -TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) { +TEST_F(ParserImplTest, RelationalExpression_Orig_Parses_GreaterThanEqual) { auto p = parser("a >= true"); auto e = p->relational_expression(); EXPECT_TRUE(e.matched); @@ -117,7 +117,7 @@ TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) { ASSERT_TRUE(rel->rhs->As()->value); } -TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) { +TEST_F(ParserImplTest, RelationalExpression_Orig_InvalidLHS) { auto p = parser("if (a) {} < true"); auto e = p->relational_expression(); EXPECT_FALSE(e.matched); @@ -126,7 +126,7 @@ TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) { EXPECT_EQ(e.value, nullptr); } -TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) { +TEST_F(ParserImplTest, RelationalExpression_Orig_InvalidRHS) { auto p = parser("true < if (a) {}"); auto e = p->relational_expression(); ASSERT_TRUE(p->has_error()); @@ -134,7 +134,7 @@ TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) { EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression"); } -TEST_F(ParserImplTest, RelationalExpression_NoOr_ReturnsLHS) { +TEST_F(ParserImplTest, RelationalExpression_Orig_NoOr_ReturnsLHS) { auto p = parser("a true"); auto e = p->relational_expression(); EXPECT_TRUE(e.matched); @@ -144,5 +144,163 @@ TEST_F(ParserImplTest, RelationalExpression_NoOr_ReturnsLHS) { ASSERT_TRUE(e->Is()); } +TEST_F(ParserImplTest, RelationalExpression_PostUnary_Parses_LessThan) { + auto p = parser("a < true"); + auto lhs = p->unary_expression(); + auto e = p->expect_relational_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, 4u); + + ASSERT_TRUE(e->Is()); + auto* rel = e->As(); + EXPECT_EQ(ast::BinaryOp::kLessThan, rel->op); + + ASSERT_TRUE(rel->lhs->Is()); + auto* ident = rel->lhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a")); + + ASSERT_TRUE(rel->rhs->Is()); + ASSERT_TRUE(rel->rhs->As()->value); +} + +TEST_F(ParserImplTest, RelationalExpression_PostUnary_Parses_GreaterThan) { + auto p = parser("a > true"); + auto lhs = p->unary_expression(); + auto e = p->expect_relational_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, 4u); + + ASSERT_TRUE(e->Is()); + auto* rel = e->As(); + EXPECT_EQ(ast::BinaryOp::kGreaterThan, rel->op); + + ASSERT_TRUE(rel->lhs->Is()); + auto* ident = rel->lhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a")); + + ASSERT_TRUE(rel->rhs->Is()); + ASSERT_TRUE(rel->rhs->As()->value); +} + +TEST_F(ParserImplTest, RelationalExpression_PostUnary_Parses_LessThanEqual) { + auto p = parser("a <= true"); + auto lhs = p->unary_expression(); + auto e = p->expect_relational_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::kLessThanEqual, rel->op); + + ASSERT_TRUE(rel->lhs->Is()); + auto* ident = rel->lhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a")); + + ASSERT_TRUE(rel->rhs->Is()); + ASSERT_TRUE(rel->rhs->As()->value); +} + +TEST_F(ParserImplTest, RelationalExpression_PostUnary_Parses_GreaterThanEqual) { + auto p = parser("a >= true"); + auto lhs = p->unary_expression(); + auto e = p->expect_relational_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::kGreaterThanEqual, rel->op); + + ASSERT_TRUE(rel->lhs->Is()); + auto* ident = rel->lhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a")); + + ASSERT_TRUE(rel->rhs->Is()); + ASSERT_TRUE(rel->rhs->As()->value); +} + +TEST_F(ParserImplTest, RelationalExpression_PostUnary_InvalidRHS) { + auto p = parser("true < if (a) {}"); + auto lhs = p->unary_expression(); + auto e = p->expect_relational_expression_post_unary_expression(lhs.value); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(e.value, nullptr); + EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression"); +} + +TEST_F(ParserImplTest, RelationalExpression_PostUnary_NoMatch_ReturnsLHS) { + auto p = parser("a true"); + auto lhs = p->unary_expression(); + auto e = p->expect_relational_expression_post_unary_expression(lhs.value); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e.value, nullptr); + EXPECT_EQ(lhs.value, e.value); +} + +TEST_F(ParserImplTest, RelationalExpression_Matches) { + auto p = parser("a >= true"); + auto e = p->maybe_relational_expression(); + EXPECT_TRUE(e.matched); + 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::kGreaterThanEqual, rel->op); + + ASSERT_TRUE(rel->lhs->Is()); + auto* ident = rel->lhs->As(); + EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a")); + + ASSERT_TRUE(rel->rhs->Is()); + ASSERT_TRUE(rel->rhs->As()->value); +} + +TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) { + auto p = parser("if (a) {}< 3"); + auto e = p->maybe_relational_expression(); + ASSERT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + ASSERT_FALSE(p->has_error()) << p->error(); + EXPECT_EQ(e.value, nullptr); +} + +TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) { + auto p = parser("true < if (a) {}"); + auto e = p->maybe_relational_expression(); + ASSERT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(e.value, nullptr); + EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression"); +} + } // namespace } // namespace tint::reader::wgsl 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 edf15199d6..76337cd283 100644 --- a/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc +++ b/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc @@ -114,7 +114,7 @@ TEST_F(ParserImplTest, ShiftExpression_Orig_NoOr_ReturnsLHS) { ASSERT_TRUE(e->Is()); } -TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { +TEST_F(ParserImplTest, ShiftExpression_PostUnary_Parses_ShiftLeft) { auto p = parser("a << true"); auto lhs = p->unary_expression(); auto e = p->expect_shift_expression_post_unary_expression(lhs.value); @@ -139,7 +139,7 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) { ASSERT_TRUE(rel->rhs->As()->value); } -TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { +TEST_F(ParserImplTest, ShiftExpression_PostUnary_Parses_ShiftRight) { auto p = parser("a >> true"); auto lhs = p->unary_expression(); auto e = p->expect_shift_expression_post_unary_expression(lhs.value); @@ -164,7 +164,7 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) { ASSERT_TRUE(rel->rhs->As()->value); } -TEST_F(ParserImplTest, ShiftExpression_Parses_Multiplicative) { +TEST_F(ParserImplTest, ShiftExpression_PostUnary_Parses_Multiplicative) { auto p = parser("a * b"); auto lhs = p->unary_expression(); auto e = p->expect_shift_expression_post_unary_expression(lhs.value); @@ -185,7 +185,7 @@ TEST_F(ParserImplTest, ShiftExpression_Parses_Multiplicative) { EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("b")); } -TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceLeft) { +TEST_F(ParserImplTest, ShiftExpression_PostUnary_InvalidSpaceLeft) { auto p = parser("a < < true"); auto lhs = p->unary_expression(); auto e = p->expect_shift_expression_post_unary_expression(lhs.value); @@ -194,7 +194,7 @@ TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceLeft) { EXPECT_FALSE(e.value->Is()); } -TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceRight) { +TEST_F(ParserImplTest, ShiftExpression_PostUnary_InvalidSpaceRight) { auto p = parser("a > > true"); auto lhs = p->unary_expression(); auto e = p->expect_shift_expression_post_unary_expression(lhs.value); @@ -203,7 +203,7 @@ TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceRight) { EXPECT_FALSE(e.value->Is()); } -TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) { +TEST_F(ParserImplTest, ShiftExpression_PostUnary_InvalidRHS) { auto p = parser("a << if (a) {}"); auto lhs = p->unary_expression(); auto e = p->expect_shift_expression_post_unary_expression(lhs.value); @@ -213,7 +213,7 @@ TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) { EXPECT_EQ(p->error(), "1:3: unable to parse right side of << expression"); } -TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) { +TEST_F(ParserImplTest, ShiftExpression_PostUnary_NoOr_ReturnsLHS) { auto p = parser("a true"); auto lhs = p->unary_expression(); auto e = p->expect_shift_expression_post_unary_expression(lhs.value); @@ -223,5 +223,45 @@ TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) { ASSERT_EQ(lhs.value, e.value); } +TEST_F(ParserImplTest, ShiftExpression_Parses) { + auto p = parser("a << true"); + auto e = p->maybe_shift_expression(); + EXPECT_TRUE(e.matched); + 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::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_Invalid_Unary) { + auto p = parser("if >> true"); + auto e = p->maybe_shift_expression(); + EXPECT_FALSE(e.matched); + EXPECT_FALSE(e.errored); + EXPECT_FALSE(p->has_error()) << p->error(); + ASSERT_EQ(e.value, nullptr); +} + +TEST_F(ParserImplTest, ShiftExpression_Inavlid_ShiftExpressionPostUnary) { + auto p = parser("a * if (a) {}"); + auto e = p->maybe_shift_expression(); + EXPECT_FALSE(e.matched); + EXPECT_TRUE(e.errored); + EXPECT_TRUE(p->has_error()); + ASSERT_EQ(e.value, nullptr); + + EXPECT_EQ(p->error(), "1:5: unable to parse right side of * expression"); +} + } // namespace } // namespace tint::reader::wgsl