Parse void function call. This CL updates the WGSL parser to handle a void function call. Fixes: tint:45 Change-Id: If5b2a4b9e62f0b10e0f2e2e10c0ca2586c5268e8 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/25322 Reviewed-by: Ryan Harrison <rharrison@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn index f6f1a9b..662c682 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -838,6 +838,7 @@ "src/reader/wgsl/parser_impl_assignment_stmt_test.cc", "src/reader/wgsl/parser_impl_body_stmt_test.cc", "src/reader/wgsl/parser_impl_break_stmt_test.cc", + "src/reader/wgsl/parser_impl_call_stmt_test.cc", "src/reader/wgsl/parser_impl_case_body_test.cc", "src/reader/wgsl/parser_impl_const_expr_test.cc", "src/reader/wgsl/parser_impl_const_literal_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 06b02eb..d91d563 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt
@@ -385,6 +385,7 @@ reader/wgsl/parser_impl_assignment_stmt_test.cc reader/wgsl/parser_impl_body_stmt_test.cc reader/wgsl/parser_impl_break_stmt_test.cc + reader/wgsl/parser_impl_call_stmt_test.cc reader/wgsl/parser_impl_case_body_test.cc reader/wgsl/parser_impl_const_expr_test.cc reader/wgsl/parser_impl_const_literal_test.cc
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 63e426b..c3e7318 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc
@@ -1422,6 +1422,7 @@ // | if_stmt // | switch_stmt // | loop_stmt +// | func_call_stmt SEMICOLON // | variable_stmt SEMICOLON // | break_stmt SEMICOLON // | continue_stmt SEMICOLON @@ -1464,6 +1465,18 @@ if (loop != nullptr) return loop; + auto func = func_call_stmt(); + if (has_error()) + return nullptr; + if (func != nullptr) { + t = next(); + if (!t.IsSemicolon()) { + set_error(t, "missing ;"); + return nullptr; + } + return func; + } + auto var = variable_stmt(); if (has_error()) return nullptr; @@ -1908,6 +1921,41 @@ std::move(continuing)); } +// func_call_stmt +// : IDENT PAREN_LEFT argument_expression_list* PAREN_RIGHT +std::unique_ptr<ast::CallStatement> ParserImpl::func_call_stmt() { + auto t = peek(); + auto t2 = peek(1); + if (!t.IsIdentifier() || !t2.IsParenLeft()) + return nullptr; + + auto source = t.source(); + + next(); // Consume the peek + next(); // Consume the 2nd peek + + auto name = t.to_str(); + + t = peek(); + ast::ExpressionList params; + if (!t.IsParenRight() && !t.IsEof()) { + params = argument_expression_list(); + if (has_error()) + return nullptr; + } + + t = next(); + if (!t.IsParenRight()) { + set_error(t, "missing ) for call statement"); + return nullptr; + } + + return std::make_unique<ast::CallStatement>( + std::make_unique<ast::CallExpression>( + source, std::make_unique<ast::IdentifierExpression>(name), + std::move(params))); +} + // break_stmt // : BREAK std::unique_ptr<ast::BreakStatement> ParserImpl::break_stmt() {
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index 38f8cbf..af76bbb 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h
@@ -23,6 +23,7 @@ #include "src/ast/assignment_statement.h" #include "src/ast/builtin.h" +#include "src/ast/call_statement.h" #include "src/ast/case_statement.h" #include "src/ast/constructor_expression.h" #include "src/ast/else_statement.h" @@ -219,6 +220,9 @@ /// Parses a `case_body` grammar element /// @returns the parsed statements ast::StatementList case_body(); + /// Parses a `func_call_stmt` grammar element + /// @returns the parsed function call or nullptr + std::unique_ptr<ast::CallStatement> func_call_stmt(); /// Parses a `loop_stmt` grammar element /// @returns the parsed loop or nullptr std::unique_ptr<ast::LoopStatement> loop_stmt();
diff --git a/src/reader/wgsl/parser_impl_call_stmt_test.cc b/src/reader/wgsl/parser_impl_call_stmt_test.cc new file mode 100644 index 0000000..1b49049 --- /dev/null +++ b/src/reader/wgsl/parser_impl_call_stmt_test.cc
@@ -0,0 +1,86 @@ +// Copyright 2020 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 "gtest/gtest.h" +#include "src/ast/call_expression.h" +#include "src/ast/call_statement.h" +#include "src/ast/identifier_expression.h" +#include "src/reader/wgsl/parser_impl.h" +#include "src/reader/wgsl/parser_impl_test_helper.h" + +namespace tint { +namespace reader { +namespace wgsl { +namespace { + +TEST_F(ParserImplTest, Statement_Call) { + auto* p = parser("a();"); + auto e = p->statement(); + ASSERT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e, nullptr); + + ASSERT_TRUE(e->IsCall()); + auto* c = e->AsCall()->expr(); + + ASSERT_TRUE(c->func()->IsIdentifier()); + auto* func = c->func()->AsIdentifier(); + EXPECT_EQ(func->name(), "a"); + + EXPECT_EQ(c->params().size(), 0u); +} + +TEST_F(ParserImplTest, Statement_Call_WithParams) { + auto* p = parser("a(1, b, 2 + 3 / b);"); + auto e = p->statement(); + ASSERT_FALSE(p->has_error()) << p->error(); + ASSERT_NE(e, nullptr); + + ASSERT_TRUE(e->IsCall()); + auto* c = e->AsCall()->expr(); + + ASSERT_TRUE(c->func()->IsIdentifier()); + auto* func = c->func()->AsIdentifier(); + EXPECT_EQ(func->name(), "a"); + + EXPECT_EQ(c->params().size(), 3u); + EXPECT_TRUE(c->params()[0]->IsConstructor()); + EXPECT_TRUE(c->params()[1]->IsIdentifier()); + EXPECT_TRUE(c->params()[2]->IsBinary()); +} + +TEST_F(ParserImplTest, Statement_Call_Missing_RightParen) { + auto* p = parser("a("); + auto e = p->statement(); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:3: missing ) for call statement"); +} + +TEST_F(ParserImplTest, Statement_Call_Missing_Semi) { + auto* p = parser("a()"); + auto e = p->statement(); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:4: missing ;"); +} + +TEST_F(ParserImplTest, Statement_Call_Bad_ArgList) { + auto* p = parser("a(b c);"); + auto e = p->statement(); + ASSERT_TRUE(p->has_error()); + EXPECT_EQ(p->error(), "1:5: missing ) for call statement"); +} + +} // namespace +} // namespace wgsl +} // namespace reader +} // namespace tint
diff --git a/test/simple.wgsl b/test/simple.wgsl index e60ec1d..92d42ad 100644 --- a/test/simple.wgsl +++ b/test/simple.wgsl
@@ -14,9 +14,14 @@ [[location 0]] var<out> gl_FragColor : vec4<f32>; +fn bar() -> void { + +} + fn main() -> void { var a : vec2<f32> = vec2<f32>(); gl_FragColor = vec4<f32>(0.4, 0.4, 0.8, 1.0); + bar(); return; } entry_point fragment = main;