Add core_lhs_expression and lhs_expression to parser.
This CL updates the WGSL parser to have a `core_lhs_expression` and a `lhs_expression` grammar rule. The rules are not used anywhere yet, but are standalone so are added with tests. Bug: tint:1633 Change-Id: I87bdaefeb06be637f72a7e6fa72ce2b6298c7bb7 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/99240 Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
e13160efb6
commit
6c8dc15d64
|
@ -1361,6 +1361,7 @@ if (tint_build_unittests) {
|
|||
"reader/wgsl/parser_impl_const_literal_test.cc",
|
||||
"reader/wgsl/parser_impl_continue_stmt_test.cc",
|
||||
"reader/wgsl/parser_impl_continuing_stmt_test.cc",
|
||||
"reader/wgsl/parser_impl_core_lhs_expression_test.cc",
|
||||
"reader/wgsl/parser_impl_depth_texture_test.cc",
|
||||
"reader/wgsl/parser_impl_enable_directive_test.cc",
|
||||
"reader/wgsl/parser_impl_equality_expression_test.cc",
|
||||
|
@ -1379,6 +1380,7 @@ if (tint_build_unittests) {
|
|||
"reader/wgsl/parser_impl_if_stmt_test.cc",
|
||||
"reader/wgsl/parser_impl_inclusive_or_expression_test.cc",
|
||||
"reader/wgsl/parser_impl_increment_decrement_stmt_test.cc",
|
||||
"reader/wgsl/parser_impl_lhs_expression_test.cc",
|
||||
"reader/wgsl/parser_impl_logical_and_expression_test.cc",
|
||||
"reader/wgsl/parser_impl_logical_or_expression_test.cc",
|
||||
"reader/wgsl/parser_impl_loop_stmt_test.cc",
|
||||
|
|
|
@ -956,6 +956,7 @@ if(TINT_BUILD_TESTS)
|
|||
reader/wgsl/parser_impl_const_literal_test.cc
|
||||
reader/wgsl/parser_impl_continue_stmt_test.cc
|
||||
reader/wgsl/parser_impl_continuing_stmt_test.cc
|
||||
reader/wgsl/parser_impl_core_lhs_expression_test.cc
|
||||
reader/wgsl/parser_impl_depth_texture_test.cc
|
||||
reader/wgsl/parser_impl_enable_directive_test.cc
|
||||
reader/wgsl/parser_impl_external_texture_test.cc
|
||||
|
@ -974,6 +975,7 @@ if(TINT_BUILD_TESTS)
|
|||
reader/wgsl/parser_impl_if_stmt_test.cc
|
||||
reader/wgsl/parser_impl_inclusive_or_expression_test.cc
|
||||
reader/wgsl/parser_impl_increment_decrement_stmt_test.cc
|
||||
reader/wgsl/parser_impl_lhs_expression_test.cc
|
||||
reader/wgsl/parser_impl_logical_and_expression_test.cc
|
||||
reader/wgsl/parser_impl_logical_or_expression_test.cc
|
||||
reader/wgsl/parser_impl_loop_stmt_test.cc
|
||||
|
|
|
@ -1009,7 +1009,6 @@ TEST_P(PunctuationTest, Parses) {
|
|||
INSTANTIATE_TEST_SUITE_P(LexerTest,
|
||||
PunctuationTest,
|
||||
testing::Values(TokenData{"&", Token::Type::kAnd},
|
||||
TokenData{"&&", Token::Type::kAndAnd},
|
||||
TokenData{"->", Token::Type::kArrow},
|
||||
TokenData{"@", Token::Type::kAttr},
|
||||
TokenData{"/", Token::Type::kForwardSlash},
|
||||
|
@ -1087,7 +1086,8 @@ TEST_P(SplittablePunctuationTest, Parses) {
|
|||
}
|
||||
INSTANTIATE_TEST_SUITE_P(LexerTest,
|
||||
SplittablePunctuationTest,
|
||||
testing::Values(TokenData{">=", Token::Type::kGreaterThanEqual},
|
||||
testing::Values(TokenData{"&&", Token::Type::kAndAnd},
|
||||
TokenData{">=", Token::Type::kGreaterThanEqual},
|
||||
TokenData{">>", Token::Type::kShiftRight}));
|
||||
|
||||
using KeywordTest = testing::TestWithParam<TokenData>;
|
||||
|
|
|
@ -2501,8 +2501,9 @@ Maybe<const ast::Expression*> ParserImpl::primary_expression() {
|
|||
|
||||
// postfix_expression
|
||||
// :
|
||||
// | BRACE_LEFT expression BRACE_RIGHT postfix_expr
|
||||
// | PERIOD IDENTIFIER postfix_expr
|
||||
// | BRACE_LEFT expression BRACE_RIGHT postfix_expression?
|
||||
// | PERIOD member_ident postfix_expression?
|
||||
// | PERIOD swizzle_name postfix_expression?
|
||||
Maybe<const ast::Expression*> ParserImpl::postfix_expression(const ast::Expression* prefix) {
|
||||
Source source;
|
||||
|
||||
|
@ -3114,6 +3115,68 @@ Maybe<ast::BinaryOp> ParserImpl::compound_assignment_operator() {
|
|||
return Failure::kNoMatch;
|
||||
}
|
||||
|
||||
// core_lhs_expression
|
||||
// : ident
|
||||
// | PAREN_LEFT lhs_expression PAREN_RIGHT
|
||||
Expect<const ast::Expression*> ParserImpl::core_lhs_expression() {
|
||||
auto& t = peek();
|
||||
if (t.IsIdentifier()) {
|
||||
next();
|
||||
|
||||
return create<ast::IdentifierExpression>(t.source(),
|
||||
builder_.Symbols().Register(t.to_str()));
|
||||
}
|
||||
|
||||
if (peek_is(Token::Type::kParenLeft)) {
|
||||
return expect_paren_block("", [&]() -> Expect<const ast::Expression*> {
|
||||
auto expr = lhs_expression();
|
||||
if (expr.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
return expr.value;
|
||||
});
|
||||
}
|
||||
return add_error(peek(), "missing expression");
|
||||
}
|
||||
|
||||
// lhs_expression
|
||||
// : ( STAR | AND )* core_lhs_expression postfix_expression?
|
||||
Expect<const ast::Expression*> ParserImpl::lhs_expression() {
|
||||
std::vector<const Token*> prefixes;
|
||||
while (peek_is(Token::Type::kStar) || peek_is(Token::Type::kAnd) ||
|
||||
peek_is(Token::Type::kAndAnd)) {
|
||||
auto& t = next();
|
||||
|
||||
// If an '&&' is provided split into '&' and '&'
|
||||
if (t.Is(Token::Type::kAndAnd)) {
|
||||
split_token(Token::Type::kAnd, Token::Type::kAnd);
|
||||
}
|
||||
|
||||
prefixes.push_back(&t);
|
||||
}
|
||||
|
||||
auto core_expr = core_lhs_expression();
|
||||
if (core_expr.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
|
||||
const auto* expr = core_expr.value;
|
||||
for (auto it = prefixes.rbegin(); it != prefixes.rend(); ++it) {
|
||||
auto& t = **it;
|
||||
ast::UnaryOp op = ast::UnaryOp::kAddressOf;
|
||||
if (t.Is(Token::Type::kStar)) {
|
||||
op = ast::UnaryOp::kIndirection;
|
||||
}
|
||||
expr = create<ast::UnaryOpExpression>(t.source(), op, expr);
|
||||
}
|
||||
|
||||
auto e = postfix_expression(expr);
|
||||
if (e.errored) {
|
||||
return Failure::kErrored;
|
||||
}
|
||||
return e.value;
|
||||
}
|
||||
|
||||
// assignment_statement
|
||||
// | lhs_expression ( EQUAL | compound_assignment_operator ) expression
|
||||
// | UNDERSCORE EQUAL expression
|
||||
|
|
|
@ -683,6 +683,12 @@ class ParserImpl {
|
|||
/// Parses a `compound_assignment_operator` grammar element
|
||||
/// @returns the parsed compound assignment operator
|
||||
Maybe<ast::BinaryOp> compound_assignment_operator();
|
||||
/// Parses a `core_lhs_expression` grammar element
|
||||
/// @returns the parsed expression or a non-kMatched failure
|
||||
Expect<const ast::Expression*> core_lhs_expression();
|
||||
/// Parses a `lhs_expression` grammar element
|
||||
/// @returns the parsed expression or a non-kMatched failure
|
||||
Expect<const ast::Expression*> lhs_expression();
|
||||
/// Parses a `assignment_statement` grammar element
|
||||
/// @returns the parsed assignment or nullptr
|
||||
Maybe<const ast::Statement*> assignment_statement();
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2022 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
|
||||
|
||||
namespace tint::reader::wgsl {
|
||||
namespace {
|
||||
|
||||
TEST_F(ParserImplTest, CoreLHS_Ident) {
|
||||
auto p = parser("identifier");
|
||||
auto e = p->core_lhs_expression();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
|
||||
|
||||
auto* ident = e->As<ast::IdentifierExpression>();
|
||||
EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("identifier"));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, CoreLHS_ParenStmt) {
|
||||
auto p = parser("(a)");
|
||||
auto e = p->core_lhs_expression();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
|
||||
|
||||
auto* ident = e->As<ast::IdentifierExpression>();
|
||||
EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, CoreLHS_MissingRightParen) {
|
||||
auto p = parser("(a");
|
||||
auto e = p->core_lhs_expression();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(e.errored);
|
||||
ASSERT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:3: expected ')'");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, CoreLHS_InvalidLHSExpression) {
|
||||
auto p = parser("(if (a() {})");
|
||||
auto e = p->core_lhs_expression();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(e.errored);
|
||||
ASSERT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:2: missing expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, CoreLHS_MissingLHSExpression) {
|
||||
auto p = parser("()");
|
||||
auto e = p->core_lhs_expression();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(e.errored);
|
||||
ASSERT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:2: missing expression");
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, CoreLHS_Invalid) {
|
||||
auto p = parser("1234");
|
||||
auto e = p->core_lhs_expression();
|
||||
ASSERT_TRUE(p->has_error());
|
||||
ASSERT_TRUE(e.errored);
|
||||
ASSERT_EQ(e.value, nullptr);
|
||||
EXPECT_EQ(p->error(), "1:1: missing expression");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::reader::wgsl
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2022 The Tint Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
|
||||
|
||||
namespace tint::reader::wgsl {
|
||||
namespace {
|
||||
|
||||
TEST_F(ParserImplTest, LHSExpression_NoPrefix) {
|
||||
auto p = parser("a");
|
||||
auto e = p->lhs_expression();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LHSExpression_And) {
|
||||
auto p = parser("&a");
|
||||
auto e = p->lhs_expression();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
|
||||
|
||||
auto* u = e->As<ast::UnaryOpExpression>();
|
||||
EXPECT_EQ(u->op, ast::UnaryOp::kAddressOf);
|
||||
EXPECT_TRUE(u->expr->Is<ast::IdentifierExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LHSExpression_Star) {
|
||||
auto p = parser("*a");
|
||||
auto e = p->lhs_expression();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
|
||||
|
||||
auto* u = e->As<ast::UnaryOpExpression>();
|
||||
EXPECT_EQ(u->op, ast::UnaryOp::kIndirection);
|
||||
EXPECT_TRUE(u->expr->Is<ast::IdentifierExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LHSExpression_Multiple) {
|
||||
auto p = parser("*&**&&*a");
|
||||
auto e = p->lhs_expression();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
|
||||
std::vector<ast::UnaryOp> results = {ast::UnaryOp::kIndirection, ast::UnaryOp::kAddressOf,
|
||||
ast::UnaryOp::kIndirection, ast::UnaryOp::kIndirection,
|
||||
ast::UnaryOp::kAddressOf, ast::UnaryOp::kAddressOf,
|
||||
ast::UnaryOp::kIndirection};
|
||||
|
||||
auto* expr = e.value;
|
||||
for (auto op : results) {
|
||||
ASSERT_TRUE(expr->Is<ast::UnaryOpExpression>());
|
||||
|
||||
auto* u = expr->As<ast::UnaryOpExpression>();
|
||||
EXPECT_EQ(u->op, op);
|
||||
|
||||
expr = u->expr;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(expr->Is<ast::IdentifierExpression>());
|
||||
}
|
||||
|
||||
TEST_F(ParserImplTest, LHSExpression_PostfixExpression) {
|
||||
auto p = parser("*a.foo");
|
||||
auto e = p->lhs_expression();
|
||||
ASSERT_FALSE(p->has_error()) << p->error();
|
||||
ASSERT_FALSE(e.errored);
|
||||
ASSERT_NE(e.value, nullptr);
|
||||
ASSERT_TRUE(e->Is<ast::MemberAccessorExpression>());
|
||||
|
||||
auto* access = e->As<ast::MemberAccessorExpression>();
|
||||
ASSERT_TRUE(access->structure->Is<ast::UnaryOpExpression>());
|
||||
|
||||
auto* u = access->structure->As<ast::UnaryOpExpression>();
|
||||
EXPECT_EQ(u->op, ast::UnaryOp::kIndirection);
|
||||
|
||||
ASSERT_TRUE(u->expr->Is<ast::IdentifierExpression>());
|
||||
auto* struct_ident = u->expr->As<ast::IdentifierExpression>();
|
||||
EXPECT_EQ(struct_ident->symbol, p->builder().Symbols().Get("a"));
|
||||
|
||||
ASSERT_TRUE(access->member->Is<ast::IdentifierExpression>());
|
||||
auto* member_ident = access->member->As<ast::IdentifierExpression>();
|
||||
EXPECT_EQ(member_ident->symbol, p->builder().Symbols().Get("foo"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::reader::wgsl
|
|
@ -379,7 +379,8 @@ class Token {
|
|||
|
||||
/// @returns true if the token can be split during parse into component tokens
|
||||
bool IsSplittable() const {
|
||||
return Is(Token::Type::kShiftRight) || Is(Token::Type::kGreaterThanEqual);
|
||||
return Is(Token::Type::kShiftRight) || Is(Token::Type::kGreaterThanEqual) ||
|
||||
Is(Token::Type::kAndAnd);
|
||||
}
|
||||
|
||||
/// @returns the source information for this token
|
||||
|
|
Loading…
Reference in New Issue