Update intrinsics in the grammar.

The intrinsic methods were removed from the WGSL grammar and are treated
as builtin functions. This Cl updates Tint to match.

Bug: tint:41
Change-Id: I3f9ff6c17f1ca57ad159d883fd5a966657caeb4f
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/22301
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
dan sinclair 2020-06-01 13:43:22 +00:00 committed by dan sinclair
parent 1d2ad81eb9
commit 46e959da39
35 changed files with 391 additions and 2408 deletions

View File

@ -230,8 +230,6 @@ source_set("libtint_core_src") {
"src/ast/continue_statement.h",
"src/ast/decorated_variable.cc",
"src/ast/decorated_variable.h",
"src/ast/derivative_modifier.cc",
"src/ast/derivative_modifier.h",
"src/ast/else_statement.cc",
"src/ast/else_statement.h",
"src/ast/entry_point.cc",
@ -322,14 +320,6 @@ source_set("libtint_core_src") {
"src/ast/type_constructor_expression.h",
"src/ast/uint_literal.cc",
"src/ast/uint_literal.h",
"src/ast/unary_derivative.cc",
"src/ast/unary_derivative.h",
"src/ast/unary_derivative_expression.cc",
"src/ast/unary_derivative_expression.h",
"src/ast/unary_method.cc",
"src/ast/unary_method.h",
"src/ast/unary_method_expression.cc",
"src/ast/unary_method_expression.h",
"src/ast/unary_op.cc",
"src/ast/unary_op.h",
"src/ast/unary_op_expression.cc",
@ -623,8 +613,6 @@ source_set("tint_unittests_core_src") {
"src/ast/type/vector_type_test.cc",
"src/ast/type_constructor_expression_test.cc",
"src/ast/uint_literal_test.cc",
"src/ast/unary_derivative_expression_test.cc",
"src/ast/unary_method_expression_test.cc",
"src/ast/unary_op_expression_test.cc",
"src/ast/unless_statement_test.cc",
"src/ast/variable_decl_statement_test.cc",
@ -737,7 +725,6 @@ source_set("tint_unittests_wgsl_reader_src") {
"src/reader/wgsl/parser_impl_const_literal_test.cc",
"src/reader/wgsl/parser_impl_continue_stmt_test.cc",
"src/reader/wgsl/parser_impl_continuing_stmt_test.cc",
"src/reader/wgsl/parser_impl_derivative_modifier_test.cc",
"src/reader/wgsl/parser_impl_else_stmt_test.cc",
"src/reader/wgsl/parser_impl_elseif_stmt_test.cc",
"src/reader/wgsl/parser_impl_entry_point_decl_test.cc",
@ -830,7 +817,6 @@ source_set("tint_unittests_wgsl_writer_src") {
"src/writer/wgsl/generator_impl_switch_test.cc",
"src/writer/wgsl/generator_impl_test.cc",
"src/writer/wgsl/generator_impl_type_test.cc",
"src/writer/wgsl/generator_impl_unary_derivative_test.cc",
"src/writer/wgsl/generator_impl_unary_method_test.cc",
"src/writer/wgsl/generator_impl_unary_op_test.cc",
"src/writer/wgsl/generator_impl_unless_test.cc",

View File

@ -67,8 +67,6 @@ set(TINT_LIB_SRCS
ast/continue_statement.h
ast/decorated_variable.cc
ast/decorated_variable.h
ast/derivative_modifier.cc
ast/derivative_modifier.h
ast/else_statement.cc
ast/else_statement.h
ast/entry_point.cc
@ -159,14 +157,6 @@ set(TINT_LIB_SRCS
ast/type/void_type.h
ast/uint_literal.cc
ast/uint_literal.h
ast/unary_derivative.cc
ast/unary_derivative.h
ast/unary_derivative_expression.cc
ast/unary_derivative_expression.h
ast/unary_method.cc
ast/unary_method.h
ast/unary_method_expression.cc
ast/unary_method_expression.h
ast/unary_op.cc
ast/unary_op.h
ast/unary_op_expression.cc
@ -303,8 +293,6 @@ set(TINT_TEST_SRCS
ast/type/vector_type_test.cc
ast/type_constructor_expression_test.cc
ast/uint_literal_test.cc
ast/unary_derivative_expression_test.cc
ast/unary_method_expression_test.cc
ast/unary_op_expression_test.cc
ast/unless_statement_test.cc
ast/variable_decl_statement_test.cc
@ -368,7 +356,6 @@ if(${TINT_BUILD_WGSL_READER})
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_derivative_modifier_test.cc
reader/wgsl/parser_impl_else_stmt_test.cc
reader/wgsl/parser_impl_elseif_stmt_test.cc
reader/wgsl/parser_impl_entry_point_decl_test.cc
@ -478,8 +465,6 @@ if(${TINT_BUILD_WGSL_WRITER})
writer/wgsl/generator_impl_return_test.cc
writer/wgsl/generator_impl_switch_test.cc
writer/wgsl/generator_impl_type_test.cc
writer/wgsl/generator_impl_unary_derivative_test.cc
writer/wgsl/generator_impl_unary_method_test.cc
writer/wgsl/generator_impl_unary_op_test.cc
writer/wgsl/generator_impl_unless_test.cc
writer/wgsl/generator_impl_variable_decl_statement_test.cc

View File

@ -1,39 +0,0 @@
// 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 "src/ast/derivative_modifier.h"
namespace tint {
namespace ast {
std::ostream& operator<<(std::ostream& out, DerivativeModifier mod) {
switch (mod) {
case DerivativeModifier::kNone: {
out << "none";
break;
}
case DerivativeModifier::kFine: {
out << "fine";
break;
}
case DerivativeModifier::kCoarse: {
out << "coarse";
break;
}
}
return out;
}
} // namespace ast
} // namespace tint

View File

@ -1,31 +0,0 @@
// 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.
#ifndef SRC_AST_DERIVATIVE_MODIFIER_H_
#define SRC_AST_DERIVATIVE_MODIFIER_H_
#include <ostream>
namespace tint {
namespace ast {
/// The derivative modifier
enum class DerivativeModifier { kNone = -1, kFine, kCoarse };
std::ostream& operator<<(std::ostream& out, DerivativeModifier mod);
} // namespace ast
} // namespace tint
#endif // SRC_AST_DERIVATIVE_MODIFIER_H_

View File

@ -25,8 +25,6 @@
#include "src/ast/identifier_expression.h"
#include "src/ast/member_accessor_expression.h"
#include "src/ast/type/alias_type.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
namespace tint {
@ -78,14 +76,6 @@ bool Expression::IsBinary() const {
return false;
}
bool Expression::IsUnaryDerivative() const {
return false;
}
bool Expression::IsUnaryMethod() const {
return false;
}
bool Expression::IsUnaryOp() const {
return false;
}
@ -129,16 +119,6 @@ const MemberAccessorExpression* Expression::AsMemberAccessor() const {
return static_cast<const MemberAccessorExpression*>(this);
}
const UnaryDerivativeExpression* Expression::AsUnaryDerivative() const {
assert(IsUnaryDerivative());
return static_cast<const UnaryDerivativeExpression*>(this);
}
const UnaryMethodExpression* Expression::AsUnaryMethod() const {
assert(IsUnaryMethod());
return static_cast<const UnaryMethodExpression*>(this);
}
const UnaryOpExpression* Expression::AsUnaryOp() const {
assert(IsUnaryOp());
return static_cast<const UnaryOpExpression*>(this);
@ -184,16 +164,6 @@ MemberAccessorExpression* Expression::AsMemberAccessor() {
return static_cast<MemberAccessorExpression*>(this);
}
UnaryDerivativeExpression* Expression::AsUnaryDerivative() {
assert(IsUnaryDerivative());
return static_cast<UnaryDerivativeExpression*>(this);
}
UnaryMethodExpression* Expression::AsUnaryMethod() {
assert(IsUnaryMethod());
return static_cast<UnaryMethodExpression*>(this);
}
UnaryOpExpression* Expression::AsUnaryOp() {
assert(IsUnaryOp());
return static_cast<UnaryOpExpression*>(this);

View File

@ -32,8 +32,6 @@ class CastExpression;
class IdentifierExpression;
class ConstructorExpression;
class MemberAccessorExpression;
class UnaryDerivativeExpression;
class UnaryMethodExpression;
class UnaryOpExpression;
/// Base expression class
@ -63,10 +61,6 @@ class Expression : public Node {
virtual bool IsMemberAccessor() const;
/// @returns true if this is a binary expression
virtual bool IsBinary() const;
/// @returns true if this is a unary derivative expression
virtual bool IsUnaryDerivative() const;
/// @returns true if this is a unary method expression
virtual bool IsUnaryMethod() const;
/// @returns true if this is a unary op expression
virtual bool IsUnaryOp() const;
@ -86,10 +80,6 @@ class Expression : public Node {
const MemberAccessorExpression* AsMemberAccessor() const;
/// @returns the expression as a binary expression
const BinaryExpression* AsBinary() const;
/// @returns the expression as a unary derivative expression
const UnaryDerivativeExpression* AsUnaryDerivative() const;
/// @returns the expression as a unary method expression
const UnaryMethodExpression* AsUnaryMethod() const;
/// @returns the expression as a unary op expression
const UnaryOpExpression* AsUnaryOp() const;
@ -109,10 +99,6 @@ class Expression : public Node {
MemberAccessorExpression* AsMemberAccessor();
/// @returns the expression as a binary expression
BinaryExpression* AsBinary();
/// @returns the expression as a unary derivative expression
UnaryDerivativeExpression* AsUnaryDerivative();
/// @returns the expression as a unary method expression
UnaryMethodExpression* AsUnaryMethod();
/// @returns the expression as a unary op expression
UnaryOpExpression* AsUnaryOp();

View File

@ -1,39 +0,0 @@
// 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 "src/ast/unary_derivative.h"
namespace tint {
namespace ast {
std::ostream& operator<<(std::ostream& out, UnaryDerivative mod) {
switch (mod) {
case UnaryDerivative::kDpdx: {
out << "dpdx";
break;
}
case UnaryDerivative::kDpdy: {
out << "dpdy";
break;
}
case UnaryDerivative::kFwidth: {
out << "fwidth";
break;
}
}
return out;
}
} // namespace ast
} // namespace tint

View File

@ -1,31 +0,0 @@
// 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.
#ifndef SRC_AST_UNARY_DERIVATIVE_H_
#define SRC_AST_UNARY_DERIVATIVE_H_
#include <ostream>
namespace tint {
namespace ast {
/// The unary derivative
enum class UnaryDerivative { kDpdx = 0, kDpdy, kFwidth };
std::ostream& operator<<(std::ostream& out, UnaryDerivative mod);
} // namespace ast
} // namespace tint
#endif // SRC_AST_UNARY_DERIVATIVE_H_

View File

@ -1,64 +0,0 @@
// 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 "src/ast/unary_derivative_expression.h"
namespace tint {
namespace ast {
UnaryDerivativeExpression::UnaryDerivativeExpression() : Expression() {}
UnaryDerivativeExpression::UnaryDerivativeExpression(
UnaryDerivative op,
DerivativeModifier mod,
std::unique_ptr<Expression> param)
: Expression(), op_(op), modifier_(mod), param_(std::move(param)) {}
UnaryDerivativeExpression::UnaryDerivativeExpression(
const Source& source,
UnaryDerivative op,
DerivativeModifier mod,
std::unique_ptr<Expression> param)
: Expression(source), op_(op), modifier_(mod), param_(std::move(param)) {}
UnaryDerivativeExpression::UnaryDerivativeExpression(
UnaryDerivativeExpression&&) = default;
UnaryDerivativeExpression::~UnaryDerivativeExpression() = default;
bool UnaryDerivativeExpression::IsUnaryDerivative() const {
return true;
}
bool UnaryDerivativeExpression::IsValid() const {
if (param_ == nullptr || !param_->IsValid()) {
return false;
}
return true;
}
void UnaryDerivativeExpression::to_str(std::ostream& out, size_t indent) const {
make_indent(out, indent);
out << "UnaryDerivative{" << std::endl;
make_indent(out, indent + 2);
out << op_ << std::endl;
make_indent(out, indent + 2);
out << modifier_ << std::endl;
param_->to_str(out, indent + 2);
make_indent(out, indent);
out << "}" << std::endl;
}
} // namespace ast
} // namespace tint

View File

@ -1,96 +0,0 @@
// 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.
#ifndef SRC_AST_UNARY_DERIVATIVE_EXPRESSION_H_
#define SRC_AST_UNARY_DERIVATIVE_EXPRESSION_H_
#include <memory>
#include <utility>
#include "src/ast/derivative_modifier.h"
#include "src/ast/expression.h"
#include "src/ast/literal.h"
#include "src/ast/unary_derivative.h"
namespace tint {
namespace ast {
/// A unary derivative expression
class UnaryDerivativeExpression : public Expression {
public:
/// Constructor
UnaryDerivativeExpression();
/// Constructor
/// @param op the op
/// @param mod the derivative modifier
/// @param param the param
UnaryDerivativeExpression(UnaryDerivative op,
DerivativeModifier mod,
std::unique_ptr<Expression> param);
/// Constructor
/// @param source the unary derivative expression source
/// @param op the op
/// @param mod the derivative modifier
/// @param param the param
UnaryDerivativeExpression(const Source& source,
UnaryDerivative op,
DerivativeModifier mod,
std::unique_ptr<Expression> param);
/// Move constructor
UnaryDerivativeExpression(UnaryDerivativeExpression&&);
~UnaryDerivativeExpression() override;
/// Sets the op
/// @param op the op
void set_op(UnaryDerivative op) { op_ = op; }
/// @returns the op
UnaryDerivative op() const { return op_; }
/// Sets the derivative modifier
/// @param mod the modifier
void set_modifier(DerivativeModifier mod) { modifier_ = mod; }
/// @returns the derivative modifier
DerivativeModifier modifier() const { return modifier_; }
/// Sets the param
/// @param param the param
void set_param(std::unique_ptr<Expression> param) {
param_ = std::move(param);
}
/// @returns the param
Expression* param() const { return param_.get(); }
/// @returns true if this is an as expression
bool IsUnaryDerivative() const override;
/// @returns true if the node is valid
bool IsValid() const override;
/// Writes a representation of the node to the output stream
/// @param out the stream to write to
/// @param indent number of spaces to indent the node when writing
void to_str(std::ostream& out, size_t indent) const override;
private:
UnaryDerivativeExpression(const UnaryDerivativeExpression&) = delete;
UnaryDerivative op_ = UnaryDerivative::kDpdx;
DerivativeModifier modifier_ = DerivativeModifier::kNone;
std::unique_ptr<Expression> param_;
};
} // namespace ast
} // namespace tint
#endif // SRC_AST_UNARY_DERIVATIVE_EXPRESSION_H_

View File

@ -1,90 +0,0 @@
// 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 "src/ast/unary_derivative_expression.h"
#include <sstream>
#include "gtest/gtest.h"
#include "src/ast/identifier_expression.h"
namespace tint {
namespace ast {
namespace {
using UnaryDerivativeExpressionTest = testing::Test;
TEST_F(UnaryDerivativeExpressionTest, Creation) {
auto ident = std::make_unique<IdentifierExpression>("ident");
auto* ident_ptr = ident.get();
UnaryDerivativeExpression d(UnaryDerivative::kDpdy,
DerivativeModifier::kCoarse, std::move(ident));
EXPECT_EQ(d.param(), ident_ptr);
EXPECT_EQ(d.modifier(), DerivativeModifier::kCoarse);
EXPECT_EQ(d.op(), UnaryDerivative::kDpdy);
}
TEST_F(UnaryDerivativeExpressionTest, Creation_WithSource) {
auto ident = std::make_unique<IdentifierExpression>("ident");
UnaryDerivativeExpression d(Source{20, 2}, UnaryDerivative::kDpdy,
DerivativeModifier::kCoarse, std::move(ident));
auto src = d.source();
EXPECT_EQ(src.line, 20u);
EXPECT_EQ(src.column, 2u);
}
TEST_F(UnaryDerivativeExpressionTest, IsUnaryDerivative) {
UnaryDerivativeExpression d;
EXPECT_TRUE(d.IsUnaryDerivative());
}
TEST_F(UnaryDerivativeExpressionTest, IsValid) {
auto ident = std::make_unique<IdentifierExpression>("ident");
UnaryDerivativeExpression d(UnaryDerivative::kDpdy,
DerivativeModifier::kCoarse, std::move(ident));
EXPECT_TRUE(d.IsValid());
}
TEST_F(UnaryDerivativeExpressionTest, IsValid_NullParam) {
UnaryDerivativeExpression d(UnaryDerivative::kDpdy,
DerivativeModifier::kCoarse, nullptr);
EXPECT_FALSE(d.IsValid());
}
TEST_F(UnaryDerivativeExpressionTest, IsValid_InvalidParam) {
auto ident = std::make_unique<IdentifierExpression>("");
UnaryDerivativeExpression d(UnaryDerivative::kDpdy,
DerivativeModifier::kCoarse, std::move(ident));
EXPECT_FALSE(d.IsValid());
}
TEST_F(UnaryDerivativeExpressionTest, ToStr) {
auto ident = std::make_unique<IdentifierExpression>("ident");
UnaryDerivativeExpression d(UnaryDerivative::kDpdy,
DerivativeModifier::kCoarse, std::move(ident));
std::ostringstream out;
d.to_str(out, 2);
EXPECT_EQ(out.str(), R"( UnaryDerivative{
dpdy
coarse
Identifier{ident}
}
)");
}
} // namespace
} // namespace ast
} // namespace tint

View File

@ -1,59 +0,0 @@
// 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 "src/ast/unary_method.h"
namespace tint {
namespace ast {
std::ostream& operator<<(std::ostream& out, UnaryMethod mod) {
switch (mod) {
case UnaryMethod::kAny: {
out << "any";
break;
}
case UnaryMethod::kAll: {
out << "all";
break;
}
case UnaryMethod::kIsNan: {
out << "is_nan";
break;
}
case UnaryMethod::kIsInf: {
out << "is_inf";
break;
}
case UnaryMethod::kIsFinite: {
out << "is_finite";
break;
}
case UnaryMethod::kIsNormal: {
out << "is_normal";
break;
}
case UnaryMethod::kDot: {
out << "dot";
break;
}
case UnaryMethod::kOuterProduct: {
out << "outer_product";
break;
}
}
return out;
}
} // namespace ast
} // namespace tint

View File

@ -1,40 +0,0 @@
// 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.
#ifndef SRC_AST_UNARY_METHOD_H_
#define SRC_AST_UNARY_METHOD_H_
#include <ostream>
namespace tint {
namespace ast {
/// The unary methods
enum class UnaryMethod {
kAny = 0,
kAll,
kIsNan,
kIsInf,
kIsFinite,
kIsNormal,
kDot,
kOuterProduct
};
std::ostream& operator<<(std::ostream& out, UnaryMethod mod);
} // namespace ast
} // namespace tint
#endif // SRC_AST_UNARY_METHOD_H_

View File

@ -1,65 +0,0 @@
// 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 "src/ast/unary_method_expression.h"
namespace tint {
namespace ast {
UnaryMethodExpression::UnaryMethodExpression() : Expression() {}
UnaryMethodExpression::UnaryMethodExpression(UnaryMethod op,
ExpressionList params)
: Expression(), op_(op), params_(std::move(params)) {}
UnaryMethodExpression::UnaryMethodExpression(const Source& source,
UnaryMethod op,
ExpressionList params)
: Expression(source), op_(op), params_(std::move(params)) {}
UnaryMethodExpression::UnaryMethodExpression(UnaryMethodExpression&&) = default;
UnaryMethodExpression::~UnaryMethodExpression() = default;
bool UnaryMethodExpression::IsUnaryMethod() const {
return true;
}
bool UnaryMethodExpression::IsValid() const {
if (params_.empty()) {
return false;
}
for (const auto& p : params_) {
if (p == nullptr || !p->IsValid()) {
return false;
}
}
return true;
}
void UnaryMethodExpression::to_str(std::ostream& out, size_t indent) const {
make_indent(out, indent);
out << "UnaryMethod{" << std::endl;
make_indent(out, indent + 2);
out << op_ << std::endl;
for (const auto& param : params_) {
param->to_str(out, indent + 2);
}
make_indent(out, indent);
out << "}" << std::endl;
}
} // namespace ast
} // namespace tint

View File

@ -1,80 +0,0 @@
// 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.
#ifndef SRC_AST_UNARY_METHOD_EXPRESSION_H_
#define SRC_AST_UNARY_METHOD_EXPRESSION_H_
#include <utility>
#include "src/ast/expression.h"
#include "src/ast/literal.h"
#include "src/ast/unary_method.h"
namespace tint {
namespace ast {
/// A unary method expression
class UnaryMethodExpression : public Expression {
public:
/// Constructor
UnaryMethodExpression();
/// Constructor
/// @param op the op
/// @param params the params
UnaryMethodExpression(UnaryMethod op, ExpressionList params);
/// Constructor
/// @param source the unary method source
/// @param op the op
/// @param params the params
UnaryMethodExpression(const Source& source,
UnaryMethod op,
ExpressionList params);
/// Move constructor
UnaryMethodExpression(UnaryMethodExpression&&);
~UnaryMethodExpression() override;
/// Sets the op
/// @param op the op
void set_op(UnaryMethod op) { op_ = op; }
/// @returns the op
UnaryMethod op() const { return op_; }
/// Sets the params
/// @param params the parameters
void set_params(ExpressionList params) { params_ = std::move(params); }
/// @returns the params
const ExpressionList& params() const { return params_; }
/// @returns true if this is an as expression
bool IsUnaryMethod() const override;
/// @returns true if the node is valid
bool IsValid() const override;
/// Writes a representation of the node to the output stream
/// @param out the stream to write to
/// @param indent number of spaces to indent the node when writing
void to_str(std::ostream& out, size_t indent) const override;
private:
UnaryMethodExpression(const UnaryMethodExpression&) = delete;
UnaryMethod op_ = UnaryMethod::kAny;
ExpressionList params_;
};
} // namespace ast
} // namespace tint
#endif // SRC_AST_UNARY_METHOD_EXPRESSION_H_

View File

@ -1,103 +0,0 @@
// 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 "src/ast/unary_method_expression.h"
#include <memory>
#include <sstream>
#include "gtest/gtest.h"
#include "src/ast/identifier_expression.h"
namespace tint {
namespace ast {
namespace {
using UnaryMethodExpressionTest = testing::Test;
TEST_F(UnaryMethodExpressionTest, Creation) {
ExpressionList params;
params.push_back(std::make_unique<IdentifierExpression>("ident"));
auto* ident_ptr = params[0].get();
UnaryMethodExpression u(UnaryMethod::kAll, std::move(params));
EXPECT_EQ(u.op(), UnaryMethod::kAll);
ASSERT_EQ(u.params().size(), 1u);
EXPECT_EQ(u.params()[0].get(), ident_ptr);
}
TEST_F(UnaryMethodExpressionTest, Creation_WithSource) {
ExpressionList params;
params.push_back(std::make_unique<IdentifierExpression>("ident"));
UnaryMethodExpression u(Source{20, 2}, UnaryMethod::kAll, std::move(params));
auto src = u.source();
EXPECT_EQ(src.line, 20u);
EXPECT_EQ(src.column, 2u);
}
TEST_F(UnaryMethodExpressionTest, IsUnaryMethod) {
UnaryMethodExpression u;
EXPECT_TRUE(u.IsUnaryMethod());
}
TEST_F(UnaryMethodExpressionTest, IsValid) {
ExpressionList params;
params.push_back(std::make_unique<IdentifierExpression>("ident"));
UnaryMethodExpression u(UnaryMethod::kAll, std::move(params));
EXPECT_TRUE(u.IsValid());
}
TEST_F(UnaryMethodExpressionTest, IsValid_NullParam) {
ExpressionList params;
params.push_back(std::make_unique<IdentifierExpression>("ident"));
params.push_back(nullptr);
UnaryMethodExpression u(UnaryMethod::kAll, std::move(params));
EXPECT_FALSE(u.IsValid());
}
TEST_F(UnaryMethodExpressionTest, IsValid_InvalidParam) {
ExpressionList params;
params.push_back(std::make_unique<IdentifierExpression>(""));
UnaryMethodExpression u(UnaryMethod::kAll, std::move(params));
EXPECT_FALSE(u.IsValid());
}
TEST_F(UnaryMethodExpressionTest, IsValid_EmptyParams) {
UnaryMethodExpression u;
u.set_op(UnaryMethod::kAll);
EXPECT_FALSE(u.IsValid());
}
TEST_F(UnaryMethodExpressionTest, ToStr) {
ExpressionList params;
params.push_back(std::make_unique<IdentifierExpression>("ident"));
UnaryMethodExpression u(UnaryMethod::kAll, std::move(params));
std::ostringstream out;
u.to_str(out, 2);
EXPECT_EQ(out.str(), R"( UnaryMethod{
all
Identifier{ident}
}
)");
}
} // namespace
} // namespace ast
} // namespace tint

View File

@ -468,10 +468,6 @@ Token Lexer::try_punctuation() {
}
Token Lexer::check_keyword(const Source& source, const std::string& str) {
if (str == "all")
return {Token::Type::kAll, source, "all"};
if (str == "any")
return {Token::Type::kAny, source, "any"};
if (str == "array")
return {Token::Type::kArray, source, "array"};
if (str == "as")
@ -498,16 +494,8 @@ Token Lexer::check_keyword(const Source& source, const std::string& str) {
return {Token::Type::kContinue, source, "continue"};
if (str == "continuing")
return {Token::Type::kContinuing, source, "continuing"};
if (str == "coarse")
return {Token::Type::kCoarse, source, "coarse"};
if (str == "default")
return {Token::Type::kDefault, source, "default"};
if (str == "dot")
return {Token::Type::kDot, source, "dot"};
if (str == "dpdx")
return {Token::Type::kDpdx, source, "dpdx"};
if (str == "dpdy")
return {Token::Type::kDpdy, source, "dpdy"};
if (str == "else")
return {Token::Type::kElse, source, "else"};
if (str == "elseif")
@ -520,16 +508,12 @@ Token Lexer::check_keyword(const Source& source, const std::string& str) {
return {Token::Type::kFallthrough, source, "fallthrough"};
if (str == "false")
return {Token::Type::kFalse, source, "false"};
if (str == "fine")
return {Token::Type::kFine, source, "fine"};
if (str == "fn")
return {Token::Type::kFn, source, "fn"};
if (str == "fragment")
return {Token::Type::kFragment, source, "fragment"};
if (str == "function")
return {Token::Type::kFunction, source, "function"};
if (str == "fwidth")
return {Token::Type::kFwidth, source, "fwidth"};
if (str == "i32")
return {Token::Type::kI32, source, "i32"};
if (str == "if")
@ -540,14 +524,6 @@ Token Lexer::check_keyword(const Source& source, const std::string& str) {
return {Token::Type::kImport, source, "import"};
if (str == "in")
return {Token::Type::kIn, source, "in"};
if (str == "is_nan")
return {Token::Type::kIsNan, source, "is_nan"};
if (str == "is_inf")
return {Token::Type::kIsInf, source, "is_inf"};
if (str == "is_finite")
return {Token::Type::kIsFinite, source, "is_finite"};
if (str == "is_normal")
return {Token::Type::kIsNormal, source, "is_normal"};
if (str == "kill")
return {Token::Type::kKill, source, "kill"};
if (str == "location")
@ -576,8 +552,6 @@ Token Lexer::check_keyword(const Source& source, const std::string& str) {
return {Token::Type::kOffset, source, "offset"};
if (str == "out")
return {Token::Type::kOut, source, "out"};
if (str == "outer_product")
return {Token::Type::kOuterProduct, source, "outer_product"};
if (str == "private")
return {Token::Type::kPrivate, source, "private"};
if (str == "ptr")

View File

@ -408,82 +408,69 @@ TEST_P(KeywordTest, Parses) {
INSTANTIATE_TEST_SUITE_P(
LexerTest,
KeywordTest,
testing::Values(
TokenData{"all", Token::Type::kAll},
TokenData{"any", Token::Type::kAny},
TokenData{"array", Token::Type::kArray},
TokenData{"as", Token::Type::kAs},
TokenData{"binding", Token::Type::kBinding},
TokenData{"block", Token::Type::kBlock},
TokenData{"bool", Token::Type::kBool},
TokenData{"break", Token::Type::kBreak},
TokenData{"builtin", Token::Type::kBuiltin},
TokenData{"case", Token::Type::kCase},
TokenData{"cast", Token::Type::kCast},
TokenData{"compute", Token::Type::kCompute},
TokenData{"const", Token::Type::kConst},
TokenData{"continue", Token::Type::kContinue},
TokenData{"continuing", Token::Type::kContinuing},
TokenData{"coarse", Token::Type::kCoarse},
TokenData{"default", Token::Type::kDefault},
TokenData{"dot", Token::Type::kDot},
TokenData{"dpdx", Token::Type::kDpdx},
TokenData{"dpdy", Token::Type::kDpdy},
TokenData{"else", Token::Type::kElse},
TokenData{"elseif", Token::Type::kElseIf},
TokenData{"entry_point", Token::Type::kEntryPoint},
TokenData{"f32", Token::Type::kF32},
TokenData{"fallthrough", Token::Type::kFallthrough},
TokenData{"false", Token::Type::kFalse},
TokenData{"fine", Token::Type::kFine},
TokenData{"fn", Token::Type::kFn},
TokenData{"fragment", Token::Type::kFragment},
TokenData{"function", Token::Type::kFunction},
TokenData{"fwidth", Token::Type::kFwidth},
TokenData{"i32", Token::Type::kI32},
TokenData{"if", Token::Type::kIf},
TokenData{"image", Token::Type::kImage},
TokenData{"import", Token::Type::kImport},
TokenData{"in", Token::Type::kIn},
TokenData{"is_nan", Token::Type::kIsNan},
TokenData{"is_inf", Token::Type::kIsInf},
TokenData{"is_finite", Token::Type::kIsFinite},
TokenData{"is_normal", Token::Type::kIsNormal},
TokenData{"kill", Token::Type::kKill},
TokenData{"location", Token::Type::kLocation},
TokenData{"loop", Token::Type::kLoop},
TokenData{"mat2x2", Token::Type::kMat2x2},
TokenData{"mat2x3", Token::Type::kMat2x3},
TokenData{"mat2x4", Token::Type::kMat2x4},
TokenData{"mat3x2", Token::Type::kMat3x2},
TokenData{"mat3x3", Token::Type::kMat3x3},
TokenData{"mat3x4", Token::Type::kMat3x4},
TokenData{"mat4x2", Token::Type::kMat4x2},
TokenData{"mat4x3", Token::Type::kMat4x3},
TokenData{"mat4x4", Token::Type::kMat4x4},
TokenData{"offset", Token::Type::kOffset},
TokenData{"out", Token::Type::kOut},
TokenData{"outer_product", Token::Type::kOuterProduct},
TokenData{"private", Token::Type::kPrivate},
TokenData{"ptr", Token::Type::kPtr},
TokenData{"return", Token::Type::kReturn},
TokenData{"set", Token::Type::kSet},
TokenData{"storage_buffer", Token::Type::kStorageBuffer},
TokenData{"struct", Token::Type::kStruct},
TokenData{"switch", Token::Type::kSwitch},
TokenData{"true", Token::Type::kTrue},
TokenData{"type", Token::Type::kType},
TokenData{"u32", Token::Type::kU32},
TokenData{"uniform", Token::Type::kUniform},
TokenData{"uniform_constant", Token::Type::kUniformConstant},
TokenData{"unless", Token::Type::kUnless},
TokenData{"var", Token::Type::kVar},
TokenData{"vec2", Token::Type::kVec2},
TokenData{"vec3", Token::Type::kVec3},
TokenData{"vec4", Token::Type::kVec4},
TokenData{"vertex", Token::Type::kVertex},
TokenData{"void", Token::Type::kVoid},
TokenData{"workgroup", Token::Type::kWorkgroup}));
testing::Values(TokenData{"array", Token::Type::kArray},
TokenData{"as", Token::Type::kAs},
TokenData{"binding", Token::Type::kBinding},
TokenData{"block", Token::Type::kBlock},
TokenData{"bool", Token::Type::kBool},
TokenData{"break", Token::Type::kBreak},
TokenData{"builtin", Token::Type::kBuiltin},
TokenData{"case", Token::Type::kCase},
TokenData{"cast", Token::Type::kCast},
TokenData{"compute", Token::Type::kCompute},
TokenData{"const", Token::Type::kConst},
TokenData{"continue", Token::Type::kContinue},
TokenData{"continuing", Token::Type::kContinuing},
TokenData{"default", Token::Type::kDefault},
TokenData{"else", Token::Type::kElse},
TokenData{"elseif", Token::Type::kElseIf},
TokenData{"entry_point", Token::Type::kEntryPoint},
TokenData{"f32", Token::Type::kF32},
TokenData{"fallthrough", Token::Type::kFallthrough},
TokenData{"false", Token::Type::kFalse},
TokenData{"fn", Token::Type::kFn},
TokenData{"fragment", Token::Type::kFragment},
TokenData{"function", Token::Type::kFunction},
TokenData{"i32", Token::Type::kI32},
TokenData{"if", Token::Type::kIf},
TokenData{"image", Token::Type::kImage},
TokenData{"import", Token::Type::kImport},
TokenData{"in", Token::Type::kIn},
TokenData{"kill", Token::Type::kKill},
TokenData{"location", Token::Type::kLocation},
TokenData{"loop", Token::Type::kLoop},
TokenData{"mat2x2", Token::Type::kMat2x2},
TokenData{"mat2x3", Token::Type::kMat2x3},
TokenData{"mat2x4", Token::Type::kMat2x4},
TokenData{"mat3x2", Token::Type::kMat3x2},
TokenData{"mat3x3", Token::Type::kMat3x3},
TokenData{"mat3x4", Token::Type::kMat3x4},
TokenData{"mat4x2", Token::Type::kMat4x2},
TokenData{"mat4x3", Token::Type::kMat4x3},
TokenData{"mat4x4", Token::Type::kMat4x4},
TokenData{"offset", Token::Type::kOffset},
TokenData{"out", Token::Type::kOut},
TokenData{"private", Token::Type::kPrivate},
TokenData{"ptr", Token::Type::kPtr},
TokenData{"return", Token::Type::kReturn},
TokenData{"set", Token::Type::kSet},
TokenData{"storage_buffer", Token::Type::kStorageBuffer},
TokenData{"struct", Token::Type::kStruct},
TokenData{"switch", Token::Type::kSwitch},
TokenData{"true", Token::Type::kTrue},
TokenData{"type", Token::Type::kType},
TokenData{"u32", Token::Type::kU32},
TokenData{"uniform", Token::Type::kUniform},
TokenData{"uniform_constant",
Token::Type::kUniformConstant},
TokenData{"unless", Token::Type::kUnless},
TokenData{"var", Token::Type::kVar},
TokenData{"vec2", Token::Type::kVec2},
TokenData{"vec3", Token::Type::kVec3},
TokenData{"vec4", Token::Type::kVec4},
TokenData{"vertex", Token::Type::kVertex},
TokenData{"void", Token::Type::kVoid},
TokenData{"workgroup", Token::Type::kWorkgroup}));
using KeywordTest_Reserved = testing::TestWithParam<const char*>;
TEST_P(KeywordTest_Reserved, Parses) {

View File

@ -57,10 +57,6 @@
#include "src/ast/type/void_type.h"
#include "src/ast/type_constructor_expression.h"
#include "src/ast/uint_literal.h"
#include "src/ast/unary_derivative.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op.h"
#include "src/ast/unary_op_expression.h"
#include "src/ast/variable_decl_statement.h"
@ -2338,30 +2334,6 @@ std::unique_ptr<ast::Expression> ParserImpl::postfix_expression() {
// : postfix_expression
// | MINUS unary_expression
// | BANG unary_expression
// | ANY PAREN_LEFT IDENT PAREN_RIGHT
// | ALL PAREN_LEFT IDENT PAREN_RIGHT
// | IS_NAN PAREN_LEFT IDENT PAREN_RIGHT
// | IS_INF PAREN_LEFT IDENT PAREN_RIGHT
// | IS_FINITE PAREN_LEFT IDENT PAREN_RIGHT
// | IS_NORMAL PAREN_LEFT IDENT PAREN_RIGHT
// | DOT PAREN_LEFT IDENT COMMA IDENT PAREN_RIGHT
// | OUTER_PRODUCT PAREN_LEFT IDENT COMMA IDENT PAREN_RIGHT
// | DPDX (LESS_THAN derivative_modifier GREATER_THAN)?
// PAREN_LEFT IDENT PAREN_RIGHT
// | DPDY (LESS_THAN derivative_modifier GREATER_THAN)?
// PAREN_LEFT IDENT PAREN_RIGHT
// | FWIDTH (LESS_THAN derivative_modifier GREATER_THAN)?
// PAREN_LEFT IDENT PAREN_RIGHT
// # | unord_greater_than_equal(a, b)
// # | unord_greater_than(a, b)
// # | unord_less_than_equal(a, b)
// # | unord_less_than(a, b)
// # | unord_not_equal(a, b)
// # | unord_equal(a, b)
// # | signed_greater_than_equal(a, b)
// # | signed_greater_than(a, b)
// # | signed_less_than_equal(a, b)
// # | signed_less_than(a, b)
std::unique_ptr<ast::Expression> ParserImpl::unary_expression() {
auto t = peek();
auto source = t.source();
@ -2385,158 +2357,9 @@ std::unique_ptr<ast::Expression> ParserImpl::unary_expression() {
return std::make_unique<ast::UnaryOpExpression>(source, op,
std::move(expr));
}
if (t.IsAny() || t.IsAll() || t.IsIsNan() || t.IsIsInf() || t.IsIsFinite() ||
t.IsIsNormal()) {
next(); // Consume the peek
auto op = ast::UnaryMethod::kAny;
if (t.IsAll())
op = ast::UnaryMethod::kAll;
else if (t.IsIsNan())
op = ast::UnaryMethod::kIsNan;
else if (t.IsIsInf())
op = ast::UnaryMethod::kIsInf;
else if (t.IsIsFinite())
op = ast::UnaryMethod::kIsFinite;
else if (t.IsIsNormal())
op = ast::UnaryMethod::kIsNormal;
t = next();
if (!t.IsParenLeft()) {
set_error(t, "missing ( for method call");
return nullptr;
}
t = next();
if (!t.IsIdentifier()) {
set_error(t, "missing identifier for method call");
return nullptr;
}
ast::ExpressionList ident;
ident.push_back(
std::make_unique<ast::IdentifierExpression>(source, t.to_str()));
t = next();
if (!t.IsParenRight()) {
set_error(t, "missing ) for method call");
return nullptr;
}
return std::make_unique<ast::UnaryMethodExpression>(source, op,
std::move(ident));
}
if (t.IsDot() || t.IsOuterProduct()) {
next(); // Consume the peek
auto op = ast::UnaryMethod::kDot;
if (t.IsOuterProduct())
op = ast::UnaryMethod::kOuterProduct;
t = next();
if (!t.IsParenLeft()) {
set_error(t, "missing ( for method call");
return nullptr;
}
t = next();
if (!t.IsIdentifier()) {
set_error(t, "missing identifier for method call");
return nullptr;
}
ast::ExpressionList ident;
ident.push_back(
std::make_unique<ast::IdentifierExpression>(source, t.to_str()));
t = next();
if (!t.IsComma()) {
set_error(t, "missing , for method call");
return nullptr;
}
t = next();
if (!t.IsIdentifier()) {
set_error(t, "missing identifier for method call");
return nullptr;
}
ident.push_back(
std::make_unique<ast::IdentifierExpression>(source, t.to_str()));
t = next();
if (!t.IsParenRight()) {
set_error(t, "missing ) for method call");
return nullptr;
}
return std::make_unique<ast::UnaryMethodExpression>(source, op,
std::move(ident));
}
if (t.IsDpdx() || t.IsDpdy() || t.IsFwidth()) {
next(); // Consume the peek
auto op = ast::UnaryDerivative::kDpdx;
if (t.IsDpdy())
op = ast::UnaryDerivative::kDpdy;
else if (t.IsFwidth())
op = ast::UnaryDerivative::kFwidth;
t = next();
auto mod = ast::DerivativeModifier::kNone;
if (t.IsLessThan()) {
mod = derivative_modifier();
if (has_error())
return nullptr;
if (mod == ast::DerivativeModifier::kNone) {
set_error(peek(), "unable to parse derivative modifier");
return nullptr;
}
t = next();
if (!t.IsGreaterThan()) {
set_error(t, "missing > for derivative modifier");
return nullptr;
}
t = next();
}
if (!t.IsParenLeft()) {
set_error(t, "missing ( for derivative method");
return nullptr;
}
t = next();
if (!t.IsIdentifier()) {
set_error(t, "missing identifier for derivative method");
return nullptr;
}
auto ident =
std::make_unique<ast::IdentifierExpression>(source, t.to_str());
t = next();
if (!t.IsParenRight()) {
set_error(t, "missing ) for derivative method");
return nullptr;
}
return std::make_unique<ast::UnaryDerivativeExpression>(source, op, mod,
std::move(ident));
}
return postfix_expression();
}
// derivative_modifier
// : FINE
// | COARSE
ast::DerivativeModifier ParserImpl::derivative_modifier() {
auto t = peek();
if (t.IsFine()) {
next(); // Consume the peek
return ast::DerivativeModifier::kFine;
}
if (t.IsCoarse()) {
next(); // Consume the peek
return ast::DerivativeModifier::kCoarse;
}
return ast::DerivativeModifier::kNone;
}
// multiplicative_expr
// :
// | STAR unary_expression multiplicative_expr

View File

@ -24,7 +24,6 @@
#include "src/ast/assignment_statement.h"
#include "src/ast/builtin.h"
#include "src/ast/constructor_expression.h"
#include "src/ast/derivative_modifier.h"
#include "src/ast/else_statement.h"
#include "src/ast/entry_point.h"
#include "src/ast/function.h"
@ -246,9 +245,6 @@ class ParserImpl {
/// Parses a `unary_expression` grammar element
/// @returns the parsed expression or nullptr
std::unique_ptr<ast::Expression> unary_expression();
/// Parses a `derivative_modifier` grammar element
/// @returns the modifier or DerivativeModifier::kNone if none matched
ast::DerivativeModifier derivative_modifier();
/// Parses the recursive part of the `multiplicative_expression`
/// @param lhs the left side of the expression
/// @returns the parsed expression or nullptr

View File

@ -17,8 +17,6 @@
#include "src/ast/identifier_expression.h"
#include "src/ast/int_literal.h"
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"

View File

@ -1,86 +0,0 @@
// 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/derivative_modifier.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
namespace tint {
namespace reader {
namespace wgsl {
namespace {
struct DerivativeModifierData {
const char* input;
ast::DerivativeModifier result;
};
inline std::ostream& operator<<(std::ostream& out,
DerivativeModifierData data) {
out << std::string(data.input);
return out;
}
class DerivativeModifierTest
: public testing::TestWithParam<DerivativeModifierData> {
public:
DerivativeModifierTest() = default;
~DerivativeModifierTest() override = default;
void SetUp() override { ctx_.Reset(); }
void TearDown() override { impl_ = nullptr; }
ParserImpl* parser(const std::string& str) {
impl_ = std::make_unique<ParserImpl>(&ctx_, str);
return impl_.get();
}
private:
std::unique_ptr<ParserImpl> impl_;
Context ctx_;
};
TEST_P(DerivativeModifierTest, Parses) {
auto params = GetParam();
auto* p = parser(params.input);
auto mod = p->derivative_modifier();
ASSERT_FALSE(p->has_error());
EXPECT_EQ(mod, params.result);
auto t = p->next();
EXPECT_TRUE(t.IsEof());
}
INSTANTIATE_TEST_SUITE_P(
ParserImplTest,
DerivativeModifierTest,
testing::Values(
DerivativeModifierData{"fine", ast::DerivativeModifier::kFine},
DerivativeModifierData{"coarse", ast::DerivativeModifier::kCoarse}));
TEST_F(ParserImplTest, DerivativeModifier_NoMatch) {
auto* p = parser("not-a-modifier");
auto stage = p->derivative_modifier();
ASSERT_EQ(stage, ast::DerivativeModifier::kNone);
auto t = p->next();
EXPECT_TRUE(t.IsIdentifier());
EXPECT_EQ(t.to_str(), "not");
}
} // namespace
} // namespace wgsl
} // namespace reader
} // namespace tint

View File

@ -19,8 +19,6 @@
#include "src/ast/int_literal.h"
#include "src/ast/member_accessor_expression.h"
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"

View File

@ -23,8 +23,6 @@
#include "src/ast/type/f32_type.h"
#include "src/ast/type/i32_type.h"
#include "src/ast/type_constructor_expression.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"

View File

@ -17,8 +17,6 @@
#include "src/ast/identifier_expression.h"
#include "src/ast/int_literal.h"
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
@ -99,732 +97,6 @@ TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) {
EXPECT_EQ(p->error(), "1:2: unable to parse right side of ! expression");
}
TEST_F(ParserImplTest, UnaryExpression_Any) {
auto* p = parser("any(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
auto* u = e->AsUnaryMethod();
ASSERT_EQ(u->op(), ast::UnaryMethod::kAny);
ASSERT_EQ(u->params().size(), 1u);
ASSERT_TRUE(u->params()[0]->IsIdentifier());
auto* ident = u->params()[0]->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_Any_MissingParenLeft) {
auto* p = parser("any a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing ( for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Any_MissingParenRight) {
auto* p = parser("any(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing ) for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Any_MissingIdentifier) {
auto* p = parser("any()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Any_InvalidIdentifier) {
auto* p = parser("any(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_All) {
auto* p = parser("all(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
auto* u = e->AsUnaryMethod();
ASSERT_EQ(u->op(), ast::UnaryMethod::kAll);
ASSERT_EQ(u->params().size(), 1u);
ASSERT_TRUE(u->params()[0]->IsIdentifier());
auto* ident = u->params()[0]->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_All_MissingParenLeft) {
auto* p = parser("all a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing ( for method call");
}
TEST_F(ParserImplTest, UnaryExpression_All_MissingParenRight) {
auto* p = parser("all(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing ) for method call");
}
TEST_F(ParserImplTest, UnaryExpression_All_MissingIdentifier) {
auto* p = parser("all()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_All_InvalidIdentifier) {
auto* p = parser("all(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsNan) {
auto* p = parser("is_nan(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
auto* u = e->AsUnaryMethod();
ASSERT_EQ(u->op(), ast::UnaryMethod::kIsNan);
ASSERT_EQ(u->params().size(), 1u);
ASSERT_TRUE(u->params()[0]->IsIdentifier());
auto* ident = u->params()[0]->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingParenLeft) {
auto* p = parser("is_nan a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing ( for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingParenRight) {
auto* p = parser("is_nan(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:9: missing ) for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsNan_MissingIdentifier) {
auto* p = parser("is_nan()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsNan_InvalidIdentifier) {
auto* p = parser("is_nan(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsInf) {
auto* p = parser("is_inf(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
auto* u = e->AsUnaryMethod();
ASSERT_EQ(u->op(), ast::UnaryMethod::kIsInf);
ASSERT_EQ(u->params().size(), 1u);
ASSERT_TRUE(u->params()[0]->IsIdentifier());
auto* ident = u->params()[0]->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingParenLeft) {
auto* p = parser("is_inf a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing ( for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingParenRight) {
auto* p = parser("is_inf(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:9: missing ) for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsInf_MissingIdentifier) {
auto* p = parser("is_inf()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsInf_InvalidIdentifier) {
auto* p = parser("is_inf(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsFinite) {
auto* p = parser("is_finite(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
auto* u = e->AsUnaryMethod();
ASSERT_EQ(u->op(), ast::UnaryMethod::kIsFinite);
ASSERT_EQ(u->params().size(), 1u);
ASSERT_TRUE(u->params()[0]->IsIdentifier());
auto* ident = u->params()[0]->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingParenLeft) {
auto* p = parser("is_finite a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: missing ( for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingParenRight) {
auto* p = parser("is_finite(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:12: missing ) for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsFinite_MissingIdentifier) {
auto* p = parser("is_finite()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsFinite_InvalidIdentifier) {
auto* p = parser("is_finite(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsNormal) {
auto* p = parser("is_normal(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
auto* u = e->AsUnaryMethod();
ASSERT_EQ(u->op(), ast::UnaryMethod::kIsNormal);
ASSERT_EQ(u->params().size(), 1u);
ASSERT_TRUE(u->params()[0]->IsIdentifier());
auto* ident = u->params()[0]->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingParenLeft) {
auto* p = parser("is_normal a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: missing ( for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingParenRight) {
auto* p = parser("is_normal(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:12: missing ) for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsNormal_MissingIdentifier) {
auto* p = parser("is_normal()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_IsNormal_InvalidIdentifier) {
auto* p = parser("is_normal(123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:11: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Dot) {
auto* p = parser("dot(a, b)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
auto* u = e->AsUnaryMethod();
ASSERT_EQ(u->op(), ast::UnaryMethod::kDot);
ASSERT_EQ(u->params().size(), 2u);
ASSERT_TRUE(u->params()[0]->IsIdentifier());
auto* ident = u->params()[0]->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
ASSERT_TRUE(u->params()[1]->IsIdentifier());
ident = u->params()[1]->AsIdentifier();
EXPECT_EQ(ident->name(), "b");
}
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingParenLeft) {
auto* p = parser("dot a, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing ( for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingParenRight) {
auto* p = parser("dot(a, b");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:9: missing ) for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingFirstIdentifier) {
auto* p = parser("dot(, a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingSecondIdentifier) {
auto* p = parser("dot(a, )");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Dot_MissingComma) {
auto* p = parser("dot(a b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:7: missing , for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Dot_InvalidFirstIdentifier) {
auto* p = parser("dot(123, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:5: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Dot_InvalidSecondIdentifier) {
auto* p = parser("dot(a, 123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct) {
auto* p = parser("outer_product(a, b)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryMethod());
auto* u = e->AsUnaryMethod();
ASSERT_EQ(u->op(), ast::UnaryMethod::kOuterProduct);
ASSERT_EQ(u->params().size(), 2u);
ASSERT_TRUE(u->params()[0]->IsIdentifier());
auto* ident = u->params()[0]->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
ASSERT_TRUE(u->params()[1]->IsIdentifier());
ident = u->params()[1]->AsIdentifier();
EXPECT_EQ(ident->name(), "b");
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingParenLeft) {
auto* p = parser("outer_product a, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: missing ( for method call");
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingParenRight) {
auto* p = parser("outer_product(a, b");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:19: missing ) for method call");
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingFirstIdentifier) {
auto* p = parser("outer_product(, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingSecondIdentifier) {
auto* p = parser("outer_product(a, )");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:18: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_MissingComma) {
auto* p = parser("outer_product(a b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:17: missing , for method call");
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_InvalidFirstIdentifier) {
auto* p = parser("outer_product(123, b)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_OuterProduct_InvalidSecondIdentifier) {
auto* p = parser("outer_product(a, 123)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:18: missing identifier for method call");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_NoModifier) {
auto* p = parser("dpdx(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
auto* deriv = e->AsUnaryDerivative();
EXPECT_EQ(deriv->op(), ast::UnaryDerivative::kDpdx);
EXPECT_EQ(deriv->modifier(), ast::DerivativeModifier::kNone);
ASSERT_NE(deriv->param(), nullptr);
ASSERT_TRUE(deriv->param()->IsIdentifier());
auto* ident = deriv->param()->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_WithModifier) {
auto* p = parser("dpdx<coarse>(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
auto* deriv = e->AsUnaryDerivative();
EXPECT_EQ(deriv->op(), ast::UnaryDerivative::kDpdx);
EXPECT_EQ(deriv->modifier(), ast::DerivativeModifier::kCoarse);
ASSERT_NE(deriv->param(), nullptr);
ASSERT_TRUE(deriv->param()->IsIdentifier());
auto* ident = deriv->param()->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingLessThan) {
auto* p = parser("dpdx coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_InvalidModifier) {
auto* p = parser("dpdx<invalid>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: unable to parse derivative modifier");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_EmptyModifer) {
auto* p = parser("dpdx coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingGreaterThan) {
auto* p = parser("dpdx<coarse (a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:13: missing > for derivative modifier");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MisisngLeftParen) {
auto* p = parser("dpdx<coarse>a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:13: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingRightParen) {
auto* p = parser("dpdx<coarse>(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: missing ) for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_MissingIdentifier) {
auto* p = parser("dpdx<coarse>()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:14: missing identifier for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdx_InvalidIdentifeir) {
auto* p = parser("dpdx<coarse>(12345)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:14: missing identifier for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_NoModifier) {
auto* p = parser("dpdy(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
auto* deriv = e->AsUnaryDerivative();
EXPECT_EQ(deriv->op(), ast::UnaryDerivative::kDpdy);
EXPECT_EQ(deriv->modifier(), ast::DerivativeModifier::kNone);
ASSERT_NE(deriv->param(), nullptr);
ASSERT_TRUE(deriv->param()->IsIdentifier());
auto* ident = deriv->param()->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_WithModifier) {
auto* p = parser("dpdy<fine>(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
auto* deriv = e->AsUnaryDerivative();
EXPECT_EQ(deriv->op(), ast::UnaryDerivative::kDpdy);
EXPECT_EQ(deriv->modifier(), ast::DerivativeModifier::kFine);
ASSERT_NE(deriv->param(), nullptr);
ASSERT_TRUE(deriv->param()->IsIdentifier());
auto* ident = deriv->param()->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingLessThan) {
auto* p = parser("dpdy coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_InvalidModifier) {
auto* p = parser("dpdy<invalid>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: unable to parse derivative modifier");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_EmptyModifer) {
auto* p = parser("dpdy coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:6: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingGreaterThan) {
auto* p = parser("dpdy<coarse (a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:13: missing > for derivative modifier");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MisisngLeftParen) {
auto* p = parser("dpdy<coarse>a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:13: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingRightParen) {
auto* p = parser("dpdy<coarse>(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: missing ) for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_MissingIdentifier) {
auto* p = parser("dpdy<coarse>()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:14: missing identifier for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Dpdy_InvalidIdentifeir) {
auto* p = parser("dpdy<coarse>(12345)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:14: missing identifier for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_NoModifier) {
auto* p = parser("fwidth(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
auto* deriv = e->AsUnaryDerivative();
EXPECT_EQ(deriv->op(), ast::UnaryDerivative::kFwidth);
EXPECT_EQ(deriv->modifier(), ast::DerivativeModifier::kNone);
ASSERT_NE(deriv->param(), nullptr);
ASSERT_TRUE(deriv->param()->IsIdentifier());
auto* ident = deriv->param()->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_WithModifier) {
auto* p = parser("fwidth<coarse>(a)");
auto e = p->unary_expression();
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_NE(e, nullptr);
ASSERT_TRUE(e->IsUnaryDerivative());
auto* deriv = e->AsUnaryDerivative();
EXPECT_EQ(deriv->op(), ast::UnaryDerivative::kFwidth);
EXPECT_EQ(deriv->modifier(), ast::DerivativeModifier::kCoarse);
ASSERT_NE(deriv->param(), nullptr);
ASSERT_TRUE(deriv->param()->IsIdentifier());
auto* ident = deriv->param()->AsIdentifier();
EXPECT_EQ(ident->name(), "a");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingLessThan) {
auto* p = parser("fwidth coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_InvalidModifier) {
auto* p = parser("fwidth<invalid>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: unable to parse derivative modifier");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_EmptyModifer) {
auto* p = parser("fwidth coarse>(a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:8: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingGreaterThan) {
auto* p = parser("fwidth<coarse (a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: missing > for derivative modifier");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MisisngLeftParen) {
auto* p = parser("fwidth<coarse>a)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:15: missing ( for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingRightParen) {
auto* p = parser("fwidth<coarse>(a");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:17: missing ) for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidth_MissingIdentifier) {
auto* p = parser("fwidth<coarse>()");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:16: missing identifier for derivative method");
}
TEST_F(ParserImplTest, UnaryExpression_Fwidht_InvalidIdentifeir) {
auto* p = parser("fwidth<coarse>(12345)");
auto e = p->unary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
EXPECT_EQ(p->error(), "1:16: missing identifier for derivative method");
}
} // namespace
} // namespace wgsl
} // namespace reader

View File

@ -116,7 +116,6 @@ TEST_F(ParserImplTest, VariableDecoration_Builtin_MissingValue) {
EXPECT_EQ(p->error(), "1:8: expected identifier for builtin");
}
TEST_F(ParserImplTest, VariableDecoration_Builtin_InvalidValue) {
auto* p = parser("builtin other_thingy");
auto deco = p->variable_decoration();

View File

@ -105,10 +105,6 @@ std::string Token::TypeToName(Type type) {
case Token::Type::kXor:
return "^";
case Token::Type::kAll:
return "all";
case Token::Type::kAny:
return "any";
case Token::Type::kArray:
return "array";
case Token::Type::kAs:
@ -135,16 +131,8 @@ std::string Token::TypeToName(Type type) {
return "continue";
case Token::Type::kContinuing:
return "continuing";
case Token::Type::kCoarse:
return "coarse";
case Token::Type::kDefault:
return "default";
case Token::Type::kDot:
return "dot";
case Token::Type::kDpdx:
return "dpdx";
case Token::Type::kDpdy:
return "dpdy";
case Token::Type::kElse:
return "else";
case Token::Type::kElseIf:
@ -157,16 +145,12 @@ std::string Token::TypeToName(Type type) {
return "fallthrough";
case Token::Type::kFalse:
return "false";
case Token::Type::kFine:
return "fine";
case Token::Type::kFn:
return "fn";
case Token::Type::kFragment:
return "fragment";
case Token::Type::kFunction:
return "function";
case Token::Type::kFwidth:
return "fwidth";
case Token::Type::kI32:
return "i32";
case Token::Type::kIf:
@ -177,14 +161,6 @@ std::string Token::TypeToName(Type type) {
return "import";
case Token::Type::kIn:
return "in";
case Token::Type::kIsNan:
return "is_nan";
case Token::Type::kIsInf:
return "is_inf";
case Token::Type::kIsFinite:
return "is_finite";
case Token::Type::kIsNormal:
return "is_normal";
case Token::Type::kKill:
return "kill";
case Token::Type::kLocation:
@ -213,8 +189,6 @@ std::string Token::TypeToName(Type type) {
return "offset";
case Token::Type::kOut:
return "out";
case Token::Type::kOuterProduct:
return "outer_product";
case Token::Type::kPremerge:
return "premerge";
case Token::Type::kPrivate:

View File

@ -116,10 +116,6 @@ class Token {
/// A '^'
kXor,
/// A 'all'
kAll,
/// A 'any'
kAny,
/// A 'array'
kArray,
/// A 'as'
@ -146,16 +142,8 @@ class Token {
kContinue,
/// A 'continuing'
kContinuing,
/// A 'coarse'
kCoarse,
/// A 'default'
kDefault,
/// A 'dot'
kDot,
/// A 'dpdx'
kDpdx,
/// A 'dpdy'
kDpdy,
/// A 'else'
kElse,
/// A 'elseif'
@ -168,16 +156,12 @@ class Token {
kFallthrough,
/// A 'false'
kFalse,
/// A 'fine'
kFine,
/// A 'fn'
kFn,
/// A 'fragment'
kFragment,
/// A 'function'
kFunction,
/// A 'fwidth'
kFwidth,
/// A 'i32'
kI32,
/// A 'if'
@ -188,14 +172,6 @@ class Token {
kImport,
/// A 'in'
kIn,
/// A 'is_nan'
kIsNan,
/// A 'is_inf'
kIsInf,
/// A 'is_finite'
kIsFinite,
/// A 'is_normal'
kIsNormal,
/// A 'kill'
kKill,
/// A 'location'
@ -224,8 +200,6 @@ class Token {
kOffset,
/// A 'out'
kOut,
/// A 'outer_product'
kOuterProduct,
/// A 'premerge'
kPremerge,
/// A 'private'
@ -401,10 +375,6 @@ class Token {
/// @returns true if token is a '^'
bool IsXor() const { return type_ == Type::kXor; }
/// @returns true if token is a 'all'
bool IsAll() const { return type_ == Type::kAll; }
/// @returns true if token is a 'any'
bool IsAny() const { return type_ == Type::kAny; }
/// @returns true if token is a 'array'
bool IsArray() const { return type_ == Type::kArray; }
/// @returns true if token is a 'as'
@ -423,8 +393,6 @@ class Token {
bool IsCase() const { return type_ == Type::kCase; }
/// @returns true if token is a 'cast'
bool IsCast() const { return type_ == Type::kCast; }
/// @returns true if token is 'coarse'
bool IsCoarse() const { return type_ == Type::kCoarse; }
/// @returns true if token is a 'compute'
bool IsCompute() const { return type_ == Type::kCompute; }
/// @returns true if token is a 'const'
@ -435,12 +403,6 @@ class Token {
bool IsContinuing() const { return type_ == Type::kContinuing; }
/// @returns true if token is a 'default'
bool IsDefault() const { return type_ == Type::kDefault; }
/// @returns true if token is a 'dot'
bool IsDot() const { return type_ == Type::kDot; }
/// @returns true if token is a 'dpdx'
bool IsDpdx() const { return type_ == Type::kDpdx; }
/// @returns true if token is a 'dpdy'
bool IsDpdy() const { return type_ == Type::kDpdy; }
/// @returns true if token is a 'else'
bool IsElse() const { return type_ == Type::kElse; }
/// @returns true if token is a 'elseif'
@ -453,16 +415,12 @@ class Token {
bool IsFallthrough() const { return type_ == Type::kFallthrough; }
/// @returns true if token is a 'false'
bool IsFalse() const { return type_ == Type::kFalse; }
/// @returns true if token is a 'fine'
bool IsFine() const { return type_ == Type::kFine; }
/// @returns true if token is a 'fn'
bool IsFn() const { return type_ == Type::kFn; }
/// @returns true if token is a 'fragment'
bool IsFragment() const { return type_ == Type::kFragment; }
/// @returns true if token is a 'function'
bool IsFunction() const { return type_ == Type::kFunction; }
/// @returns true if token is a 'fwidth'
bool IsFwidth() const { return type_ == Type::kFwidth; }
/// @returns true if token is a 'i32'
bool IsI32() const { return type_ == Type::kI32; }
/// @returns true if token is a 'if'
@ -473,14 +431,6 @@ class Token {
bool IsImport() const { return type_ == Type::kImport; }
/// @returns true if token is a 'in'
bool IsIn() const { return type_ == Type::kIn; }
/// @returns true if token is a 'is_nan'
bool IsIsNan() const { return type_ == Type::kIsNan; }
/// @returns true if token is a 'is_inf'
bool IsIsInf() const { return type_ == Type::kIsInf; }
/// @returns true if token is a 'is_finite'
bool IsIsFinite() const { return type_ == Type::kIsFinite; }
/// @returns true if token is a 'is_normal'
bool IsIsNormal() const { return type_ == Type::kIsNormal; }
/// @returns true if token is a 'kill'
bool IsKill() const { return type_ == Type::kKill; }
/// @returns true if token is a 'location'
@ -509,8 +459,6 @@ class Token {
bool IsOffset() const { return type_ == Type::kOffset; }
/// @returns true if token is a 'out'
bool IsOut() const { return type_ == Type::kOut; }
/// @returns true if token is a 'outer_product'
bool IsOuterProduct() const { return type_ == Type::kOuterProduct; }
/// @returns true if token is a 'private'
bool IsPrivate() const { return type_ == Type::kPrivate; }
/// @returns true if token is a 'ptr'

View File

@ -42,13 +42,30 @@
#include "src/ast/type/struct_type.h"
#include "src/ast/type/vector_type.h"
#include "src/ast/type_constructor_expression.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/ast/unless_statement.h"
#include "src/ast/variable_decl_statement.h"
namespace tint {
namespace {
bool IsDerivative(const std::string& name) {
return name == "dpdx" || name == "dpdx_fine" || name == "dpdx_coarse" ||
name == "dpdy" || name == "dpdy_fine" || name == "dpdy_coarse" ||
name == "fwidth" || name == "fwidth_fine" || name == "fwidth_coarse";
}
bool IsFloatIntrinsic(const std::string& name) {
return name == "is_finite" || name == "is_inf" || name == "is_nan" ||
name == "is_normal";
}
bool IsIntrinsic(const std::string& name) {
return IsDerivative(name) || name == "all" || name == "any" ||
IsFloatIntrinsic(name) || name == "dot" || name == "outer_product";
}
} // namespace
TypeDeterminer::TypeDeterminer(Context* ctx, ast::Module* mod)
: ctx_(*ctx), mod_(mod) {}
@ -253,12 +270,6 @@ bool TypeDeterminer::DetermineResultType(ast::Expression* expr) {
if (expr->IsMemberAccessor()) {
return DetermineMemberAccessor(expr->AsMemberAccessor());
}
if (expr->IsUnaryDerivative()) {
return DetermineUnaryDerivative(expr->AsUnaryDerivative());
}
if (expr->IsUnaryMethod()) {
return DetermineUnaryMethod(expr->AsUnaryMethod());
}
if (expr->IsUnaryOp()) {
return DetermineUnaryOp(expr->AsUnaryOp());
}
@ -318,7 +329,11 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) {
if (expr->func()->IsIdentifier()) {
auto* ident = expr->func()->AsIdentifier();
if (ident->has_path()) {
if (IsIntrinsic(ident->name())) {
if (!DetermineIntrinsic(ident->name(), expr))
return false;
} else if (ident->has_path()) {
auto* imp = mod_->FindImportByName(ident->path());
if (imp == nullptr) {
set_error(expr->source(), "Unable to find import for " + ident->name());
@ -355,6 +370,75 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* expr) {
return true;
}
bool TypeDeterminer::DetermineIntrinsic(const std::string& name,
ast::CallExpression* expr) {
if (IsDerivative(name)) {
if (expr->params().size() != 1) {
set_error(expr->source(), "incorrect number of parameters for " + name);
return false;
}
// The result type must be the same as the type of the parameter.
auto& param = expr->params()[0];
if (!DetermineResultType(param.get())) {
return false;
}
expr->func()->set_result_type(param->result_type()->UnwrapPtrIfNeeded());
return true;
}
if (name == "any" || name == "all") {
expr->func()->set_result_type(
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>()));
return true;
}
if (IsFloatIntrinsic(name)) {
if (expr->params().size() != 1) {
set_error(expr->source(), "incorrect number of parameters for " + name);
return false;
}
auto* bool_type =
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>());
auto* param_type = expr->params()[0]->result_type()->UnwrapPtrIfNeeded();
if (param_type->IsVector()) {
expr->func()->set_result_type(
ctx_.type_mgr().Get(std::make_unique<ast::type::VectorType>(
bool_type, param_type->AsVector()->size())));
} else {
expr->func()->set_result_type(bool_type);
}
return true;
}
if (name == "dot") {
expr->func()->set_result_type(
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()));
return true;
}
if (name == "outer_product") {
if (expr->params().size() != 2) {
set_error(expr->source(),
"incorrect number of parameters for outer_product");
return false;
}
auto* param0_type = expr->params()[0]->result_type()->UnwrapPtrIfNeeded();
auto* param1_type = expr->params()[1]->result_type()->UnwrapPtrIfNeeded();
if (!param0_type->IsVector() || !param1_type->IsVector()) {
set_error(expr->source(), "invalid parameter type for outer_product");
return false;
}
expr->func()->set_result_type(
ctx_.type_mgr().Get(std::make_unique<ast::type::MatrixType>(
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()),
param0_type->AsVector()->size(), param1_type->AsVector()->size())));
return true;
}
return false;
}
bool TypeDeterminer::DetermineCast(ast::CastExpression* expr) {
if (!DetermineResultType(expr->expr())) {
return false;
@ -550,77 +634,6 @@ bool TypeDeterminer::DetermineBinary(ast::BinaryExpression* expr) {
return false;
}
bool TypeDeterminer::DetermineUnaryDerivative(
ast::UnaryDerivativeExpression* expr) {
// The result type must be the same as the type of the parameter.
if (!DetermineResultType(expr->param())) {
return false;
}
expr->set_result_type(expr->param()->result_type()->UnwrapPtrIfNeeded());
return true;
}
bool TypeDeterminer::DetermineUnaryMethod(ast::UnaryMethodExpression* expr) {
if (!DetermineResultType(expr->params())) {
return false;
}
switch (expr->op()) {
case ast::UnaryMethod::kAny:
case ast::UnaryMethod::kAll: {
expr->set_result_type(
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>()));
break;
}
case ast::UnaryMethod::kIsNan:
case ast::UnaryMethod::kIsInf:
case ast::UnaryMethod::kIsFinite:
case ast::UnaryMethod::kIsNormal: {
if (expr->params().empty()) {
set_error(expr->source(), "incorrect number of parameters");
return false;
}
auto* bool_type =
ctx_.type_mgr().Get(std::make_unique<ast::type::BoolType>());
auto* param_type = expr->params()[0]->result_type()->UnwrapPtrIfNeeded();
if (param_type->IsVector()) {
expr->set_result_type(
ctx_.type_mgr().Get(std::make_unique<ast::type::VectorType>(
bool_type, param_type->AsVector()->size())));
} else {
expr->set_result_type(bool_type);
}
break;
}
case ast::UnaryMethod::kDot: {
expr->set_result_type(
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()));
break;
}
case ast::UnaryMethod::kOuterProduct: {
if (expr->params().size() != 2) {
set_error(expr->source(),
"incorrect number of parameters for outer product");
return false;
}
auto* param0_type = expr->params()[0]->result_type()->UnwrapPtrIfNeeded();
auto* param1_type = expr->params()[1]->result_type()->UnwrapPtrIfNeeded();
if (!param0_type->IsVector() || !param1_type->IsVector()) {
set_error(expr->source(), "invalid parameter type for outer product");
return false;
}
expr->set_result_type(
ctx_.type_mgr().Get(std::make_unique<ast::type::MatrixType>(
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()),
param0_type->AsVector()->size(),
param1_type->AsVector()->size())));
break;
}
}
return true;
}
bool TypeDeterminer::DetermineUnaryOp(ast::UnaryOpExpression* expr) {
// Result type matches the parameter type.
if (!DetermineResultType(expr->expr())) {

View File

@ -34,8 +34,6 @@ class ConstructorExpression;
class Function;
class IdentifierExpression;
class MemberAccessorExpression;
class UnaryDerivativeExpression;
class UnaryMethodExpression;
class UnaryOpExpression;
class Variable;
@ -114,9 +112,8 @@ class TypeDeterminer {
bool DetermineCast(ast::CastExpression* expr);
bool DetermineConstructor(ast::ConstructorExpression* expr);
bool DetermineIdentifier(ast::IdentifierExpression* expr);
bool DetermineIntrinsic(const std::string& name, ast::CallExpression* expr);
bool DetermineMemberAccessor(ast::MemberAccessorExpression* expr);
bool DetermineUnaryDerivative(ast::UnaryDerivativeExpression* expr);
bool DetermineUnaryMethod(ast::UnaryMethodExpression* expr);
bool DetermineUnaryOp(ast::UnaryOpExpression* expr);
Context& ctx_;

View File

@ -51,8 +51,6 @@
#include "src/ast/type/struct_type.h"
#include "src/ast/type/vector_type.h"
#include "src/ast/type_constructor_expression.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/ast/unless_statement.h"
#include "src/ast/variable_decl_statement.h"
@ -1369,13 +1367,34 @@ TEST_F(TypeDeterminerTest, Expr_Binary_Multiply_Matrix_Matrix) {
EXPECT_EQ(mat->columns(), 4u);
}
using UnaryDerivativeExpressionTest =
TypeDeterminerTestWithParam<ast::UnaryDerivative>;
TEST_P(UnaryDerivativeExpressionTest, Expr_UnaryDerivative) {
auto derivative = GetParam();
using IntrinsicDerivativeTest = TypeDeterminerTestWithParam<std::string>;
TEST_P(IntrinsicDerivativeTest, Scalar) {
auto name = GetParam();
ast::type::F32Type f32;
auto var =
std::make_unique<ast::Variable>("ident", ast::StorageClass::kNone, &f32);
mod()->AddGlobalVariable(std::move(var));
// Register the global
EXPECT_TRUE(td()->Determine());
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("ident"));
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
EXPECT_TRUE(td()->DetermineResultType(&expr));
ASSERT_NE(expr.result_type(), nullptr);
ASSERT_TRUE(expr.result_type()->IsF32());
}
TEST_P(IntrinsicDerivativeTest, Vector) {
auto name = GetParam();
ast::type::F32Type f32;
ast::type::VectorType vec4(&f32, 4);
auto var =
@ -1385,25 +1404,75 @@ TEST_P(UnaryDerivativeExpressionTest, Expr_UnaryDerivative) {
// Register the global
EXPECT_TRUE(td()->Determine());
ast::UnaryDerivativeExpression der(
derivative, ast::DerivativeModifier::kNone,
std::make_unique<ast::IdentifierExpression>("ident"));
EXPECT_TRUE(td()->DetermineResultType(&der));
ASSERT_NE(der.result_type(), nullptr);
ASSERT_TRUE(der.result_type()->IsVector());
EXPECT_TRUE(der.result_type()->AsVector()->type()->IsF32());
EXPECT_EQ(der.result_type()->AsVector()->size(), 4u);
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("ident"));
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
EXPECT_TRUE(td()->DetermineResultType(&expr));
ASSERT_NE(expr.result_type(), nullptr);
ASSERT_TRUE(expr.result_type()->IsVector());
EXPECT_TRUE(expr.result_type()->AsVector()->type()->IsF32());
EXPECT_EQ(expr.result_type()->AsVector()->size(), 4u);
}
TEST_P(IntrinsicDerivativeTest, MissingParam) {
auto name = GetParam();
ast::type::F32Type f32;
ast::type::VectorType vec4(&f32, 4);
// Register the global
EXPECT_TRUE(td()->Determine());
ast::ExpressionList call_params;
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
EXPECT_FALSE(td()->DetermineResultType(&expr));
EXPECT_EQ(td()->error(), "incorrect number of parameters for " + name);
}
TEST_P(IntrinsicDerivativeTest, ToomManyParams) {
auto name = GetParam();
ast::type::F32Type f32;
ast::type::VectorType vec4(&f32, 4);
auto var1 = std::make_unique<ast::Variable>("ident1",
ast::StorageClass::kNone, &vec4);
auto var2 = std::make_unique<ast::Variable>("ident2",
ast::StorageClass::kNone, &vec4);
mod()->AddGlobalVariable(std::move(var1));
mod()->AddGlobalVariable(std::move(var2));
// Register the global
EXPECT_TRUE(td()->Determine());
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("ident1"));
call_params.push_back(std::make_unique<ast::IdentifierExpression>("ident2"));
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
EXPECT_FALSE(td()->DetermineResultType(&expr));
EXPECT_EQ(td()->error(), "incorrect number of parameters for " + name);
}
INSTANTIATE_TEST_SUITE_P(TypeDeterminerTest,
UnaryDerivativeExpressionTest,
testing::Values(ast::UnaryDerivative::kDpdx,
ast::UnaryDerivative::kDpdy,
ast::UnaryDerivative::kFwidth));
IntrinsicDerivativeTest,
testing::Values("dpdx",
"dpdx_coarse",
"dpdx_fine",
"dpdy",
"dpdy_coarse",
"dpdy_fine",
"fwidth",
"fwidth_coarse",
"fwidth_fine"));
using UnaryMethodExpressionBoolTest =
TypeDeterminerTestWithParam<ast::UnaryMethod>;
TEST_P(UnaryMethodExpressionBoolTest, Expr_UnaryMethod_Any) {
auto op = GetParam();
using Intrinsic = TypeDeterminerTestWithParam<std::string>;
TEST_P(Intrinsic, Test) {
auto name = GetParam();
ast::type::BoolType bool_type;
ast::type::VectorType vec3(&bool_type, 3);
@ -1412,27 +1481,26 @@ TEST_P(UnaryMethodExpressionBoolTest, Expr_UnaryMethod_Any) {
&vec3);
mod()->AddGlobalVariable(std::move(var));
ast::ExpressionList params;
params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::UnaryMethodExpression exp(op, std::move(params));
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_TRUE(td()->DetermineResultType(&exp));
ASSERT_NE(exp.result_type(), nullptr);
EXPECT_TRUE(exp.result_type()->IsBool());
EXPECT_TRUE(td()->DetermineResultType(&expr));
ASSERT_NE(expr.result_type(), nullptr);
EXPECT_TRUE(expr.result_type()->IsBool());
}
INSTANTIATE_TEST_SUITE_P(TypeDeterminerTest,
UnaryMethodExpressionBoolTest,
testing::Values(ast::UnaryMethod::kAny,
ast::UnaryMethod::kAll));
Intrinsic,
testing::Values("any", "all"));
using UnaryMethodExpressionVecTest =
TypeDeterminerTestWithParam<ast::UnaryMethod>;
TEST_P(UnaryMethodExpressionVecTest, Expr_UnaryMethod_Bool) {
auto op = GetParam();
using Intrinsic_FloatMethod = TypeDeterminerTestWithParam<std::string>;
TEST_P(Intrinsic_FloatMethod, Vector) {
auto name = GetParam();
ast::type::F32Type f32;
ast::type::VectorType vec3(&f32, 3);
@ -1441,22 +1509,24 @@ TEST_P(UnaryMethodExpressionVecTest, Expr_UnaryMethod_Bool) {
&vec3);
mod()->AddGlobalVariable(std::move(var));
ast::ExpressionList params;
params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::UnaryMethodExpression exp(op, std::move(params));
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_TRUE(td()->DetermineResultType(&expr));
EXPECT_TRUE(td()->DetermineResultType(&exp));
ASSERT_NE(exp.result_type(), nullptr);
ASSERT_TRUE(exp.result_type()->IsVector());
EXPECT_TRUE(exp.result_type()->AsVector()->type()->IsBool());
EXPECT_EQ(exp.result_type()->AsVector()->size(), 3u);
ASSERT_NE(expr.result_type(), nullptr);
ASSERT_TRUE(expr.result_type()->IsVector());
EXPECT_TRUE(expr.result_type()->AsVector()->type()->IsBool());
EXPECT_EQ(expr.result_type()->AsVector()->size(), 3u);
}
TEST_P(UnaryMethodExpressionVecTest, Expr_UnaryMethod_Vec) {
auto op = GetParam();
TEST_P(Intrinsic_FloatMethod, Scalar) {
auto name = GetParam();
ast::type::F32Type f32;
@ -1464,26 +1534,65 @@ TEST_P(UnaryMethodExpressionVecTest, Expr_UnaryMethod_Vec) {
std::make_unique<ast::Variable>("my_var", ast::StorageClass::kNone, &f32);
mod()->AddGlobalVariable(std::move(var));
ast::ExpressionList params;
params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::UnaryMethodExpression exp(op, std::move(params));
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_TRUE(td()->DetermineResultType(&exp));
ASSERT_NE(exp.result_type(), nullptr);
EXPECT_TRUE(exp.result_type()->IsBool());
EXPECT_TRUE(td()->DetermineResultType(&expr));
ASSERT_NE(expr.result_type(), nullptr);
EXPECT_TRUE(expr.result_type()->IsBool());
}
INSTANTIATE_TEST_SUITE_P(TypeDeterminerTest,
UnaryMethodExpressionVecTest,
testing::Values(ast::UnaryMethod::kIsInf,
ast::UnaryMethod::kIsNan,
ast::UnaryMethod::kIsFinite,
ast::UnaryMethod::kIsNormal));
TEST_F(TypeDeterminerTest, Expr_UnaryMethod_Dot) {
TEST_P(Intrinsic_FloatMethod, MissingParam) {
auto name = GetParam();
ast::type::F32Type f32;
auto var =
std::make_unique<ast::Variable>("my_var", ast::StorageClass::kNone, &f32);
mod()->AddGlobalVariable(std::move(var));
ast::ExpressionList call_params;
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_FALSE(td()->DetermineResultType(&expr));
EXPECT_EQ(td()->error(), "incorrect number of parameters for " + name);
}
TEST_P(Intrinsic_FloatMethod, TooManyParams) {
auto name = GetParam();
ast::type::F32Type f32;
auto var =
std::make_unique<ast::Variable>("my_var", ast::StorageClass::kNone, &f32);
mod()->AddGlobalVariable(std::move(var));
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
call_params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>(name),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_FALSE(td()->DetermineResultType(&expr));
EXPECT_EQ(td()->error(), "incorrect number of parameters for " + name);
}
INSTANTIATE_TEST_SUITE_P(
TypeDeterminerTest,
Intrinsic_FloatMethod,
testing::Values("is_inf", "is_nan", "is_finite", "is_normal"));
TEST_F(TypeDeterminerTest, Intrinsic_Dot) {
ast::type::F32Type f32;
ast::type::VectorType vec3(&f32, 3);
@ -1491,21 +1600,21 @@ TEST_F(TypeDeterminerTest, Expr_UnaryMethod_Dot) {
&vec3);
mod()->AddGlobalVariable(std::move(var));
ast::ExpressionList params;
params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
call_params.push_back(std::make_unique<ast::IdentifierExpression>("my_var"));
ast::UnaryMethodExpression exp(ast::UnaryMethod::kDot, std::move(params));
ast::CallExpression expr(std::make_unique<ast::IdentifierExpression>("dot"),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_TRUE(td()->DetermineResultType(&exp));
ASSERT_NE(exp.result_type(), nullptr);
EXPECT_TRUE(exp.result_type()->IsF32());
EXPECT_TRUE(td()->DetermineResultType(&expr));
ASSERT_NE(expr.result_type(), nullptr);
EXPECT_TRUE(expr.result_type()->IsF32());
}
TEST_F(TypeDeterminerTest, Expr_UnaryMethod_OuterProduct) {
TEST_F(TypeDeterminerTest, Intrinsic_OuterProduct) {
ast::type::F32Type f32;
ast::type::VectorType vec3(&f32, 3);
ast::type::VectorType vec2(&f32, 2);
@ -1517,25 +1626,73 @@ TEST_F(TypeDeterminerTest, Expr_UnaryMethod_OuterProduct) {
mod()->AddGlobalVariable(std::move(var1));
mod()->AddGlobalVariable(std::move(var2));
ast::ExpressionList params;
params.push_back(std::make_unique<ast::IdentifierExpression>("v3"));
params.push_back(std::make_unique<ast::IdentifierExpression>("v2"));
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("v3"));
call_params.push_back(std::make_unique<ast::IdentifierExpression>("v2"));
ast::UnaryMethodExpression exp(ast::UnaryMethod::kOuterProduct,
std::move(params));
ast::CallExpression expr(
std::make_unique<ast::IdentifierExpression>("outer_product"),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_TRUE(td()->DetermineResultType(&expr));
EXPECT_TRUE(td()->DetermineResultType(&exp));
ASSERT_NE(exp.result_type(), nullptr);
ASSERT_TRUE(exp.result_type()->IsMatrix());
auto* mat = exp.result_type()->AsMatrix();
ASSERT_NE(expr.result_type(), nullptr);
ASSERT_TRUE(expr.result_type()->IsMatrix());
auto* mat = expr.result_type()->AsMatrix();
EXPECT_TRUE(mat->type()->IsF32());
EXPECT_EQ(mat->rows(), 3u);
EXPECT_EQ(mat->columns(), 2u);
}
TEST_F(TypeDeterminerTest, Intrinsic_OuterProduct_TooFewParams) {
ast::type::F32Type f32;
ast::type::VectorType vec3(&f32, 3);
ast::type::VectorType vec2(&f32, 2);
auto var2 =
std::make_unique<ast::Variable>("v2", ast::StorageClass::kNone, &vec2);
mod()->AddGlobalVariable(std::move(var2));
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("v2"));
ast::CallExpression expr(
std::make_unique<ast::IdentifierExpression>("outer_product"),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_FALSE(td()->DetermineResultType(&expr));
EXPECT_EQ(td()->error(), "incorrect number of parameters for outer_product");
}
TEST_F(TypeDeterminerTest, Intrinsic_OuterProduct_TooManyParams) {
ast::type::F32Type f32;
ast::type::VectorType vec3(&f32, 3);
ast::type::VectorType vec2(&f32, 2);
auto var2 =
std::make_unique<ast::Variable>("v2", ast::StorageClass::kNone, &vec2);
mod()->AddGlobalVariable(std::move(var2));
ast::ExpressionList call_params;
call_params.push_back(std::make_unique<ast::IdentifierExpression>("v2"));
call_params.push_back(std::make_unique<ast::IdentifierExpression>("v2"));
call_params.push_back(std::make_unique<ast::IdentifierExpression>("v2"));
ast::CallExpression expr(
std::make_unique<ast::IdentifierExpression>("outer_product"),
std::move(call_params));
// Register the variable
EXPECT_TRUE(td()->Determine());
EXPECT_FALSE(td()->DetermineResultType(&expr));
EXPECT_EQ(td()->error(), "incorrect number of parameters for outer_product");
}
using UnaryOpExpressionTest = TypeDeterminerTestWithParam<ast::UnaryOp>;
TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) {
auto op = GetParam();

View File

@ -54,8 +54,6 @@
#include "src/ast/type/vector_type.h"
#include "src/ast/type_constructor_expression.h"
#include "src/ast/uint_literal.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/ast/unary_op_expression.h"
#include "src/ast/unless_statement.h"
#include "src/ast/variable_decl_statement.h"
@ -166,12 +164,6 @@ bool GeneratorImpl::EmitExpression(ast::Expression* expr) {
if (expr->IsMemberAccessor()) {
return EmitMemberAccessor(expr->AsMemberAccessor());
}
if (expr->IsUnaryDerivative()) {
return EmitUnaryDerivative(expr->AsUnaryDerivative());
}
if (expr->IsUnaryMethod()) {
return EmitUnaryMethod(expr->AsUnaryMethod());
}
if (expr->IsUnaryOp()) {
return EmitUnaryOp(expr->AsUnaryOp());
}
@ -595,78 +587,6 @@ bool GeneratorImpl::EmitBinary(ast::BinaryExpression* expr) {
return true;
}
bool GeneratorImpl::EmitUnaryDerivative(ast::UnaryDerivativeExpression* expr) {
switch (expr->op()) {
case ast::UnaryDerivative::kDpdx:
out_ << "dpdx";
break;
case ast::UnaryDerivative::kDpdy:
out_ << "dpdy";
break;
case ast::UnaryDerivative::kFwidth:
out_ << "fwidth";
break;
}
if (expr->modifier() != ast::DerivativeModifier::kNone) {
out_ << "<" << expr->modifier() << ">";
}
out_ << "(";
if (!EmitExpression(expr->param())) {
return false;
}
out_ << ")";
return true;
}
bool GeneratorImpl::EmitUnaryMethod(ast::UnaryMethodExpression* expr) {
switch (expr->op()) {
case ast::UnaryMethod::kAny:
out_ << "any";
break;
case ast::UnaryMethod::kAll:
out_ << "all";
break;
case ast::UnaryMethod::kIsNan:
out_ << "is_nan";
break;
case ast::UnaryMethod::kIsInf:
out_ << "is_inf";
break;
case ast::UnaryMethod::kIsFinite:
out_ << "is_finite";
break;
case ast::UnaryMethod::kIsNormal:
out_ << "is_normal";
break;
case ast::UnaryMethod::kDot:
out_ << "dot";
break;
case ast::UnaryMethod::kOuterProduct:
out_ << "outer_product";
break;
}
out_ << "(";
bool first = true;
for (const auto& param : expr->params()) {
if (!first) {
out_ << ", ";
}
first = false;
if (!EmitExpression(param.get())) {
return false;
}
}
out_ << ")";
return true;
}
bool GeneratorImpl::EmitUnaryOp(ast::UnaryOpExpression* expr) {
switch (expr->op()) {
case ast::UnaryOp::kNot:

View File

@ -190,14 +190,6 @@ class GeneratorImpl {
/// @param expr the type constructor expression
/// @returns true if the constructor is emitted
bool EmitTypeConstructor(ast::TypeConstructorExpression* expr);
/// Handles a unary derivative expression
/// @param expr the expression to emit
/// @returns true if the expression was emitted
bool EmitUnaryDerivative(ast::UnaryDerivativeExpression* expr);
/// Handles a unary method expression
/// @param expr the expression to emit
/// @returns true if the expression was emitted
bool EmitUnaryMethod(ast::UnaryMethodExpression* expr);
/// Handles a unary op expression
/// @param expr the expression to emit
/// @returns true if the expression was emitted

View File

@ -1,83 +0,0 @@
// 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 <memory>
#include "gtest/gtest.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/unary_derivative_expression.h"
#include "src/writer/wgsl/generator_impl.h"
namespace tint {
namespace writer {
namespace wgsl {
namespace {
struct UnaryDerivativeData {
const char* name;
ast::UnaryDerivative derivative;
};
inline std::ostream& operator<<(std::ostream& out, UnaryDerivativeData data) {
out << data.derivative;
return out;
}
using UnaryDerivativeTest = testing::TestWithParam<UnaryDerivativeData>;
TEST_P(UnaryDerivativeTest, Emit_ModifierNone) {
auto params = GetParam();
auto expr = std::make_unique<ast::IdentifierExpression>("expr");
ast::UnaryDerivativeExpression derivative(
params.derivative, ast::DerivativeModifier::kNone, std::move(expr));
GeneratorImpl g;
ASSERT_TRUE(g.EmitExpression(&derivative)) << g.error();
EXPECT_EQ(g.result(), std::string(params.name) + "(expr)");
}
TEST_P(UnaryDerivativeTest, Emit_ModifierFine) {
auto params = GetParam();
auto expr = std::make_unique<ast::IdentifierExpression>("expr");
ast::UnaryDerivativeExpression derivative(
params.derivative, ast::DerivativeModifier::kFine, std::move(expr));
GeneratorImpl g;
ASSERT_TRUE(g.EmitExpression(&derivative)) << g.error();
EXPECT_EQ(g.result(), std::string(params.name) + "<fine>(expr)");
}
TEST_P(UnaryDerivativeTest, Emit_ModifierCoarse) {
auto params = GetParam();
auto expr = std::make_unique<ast::IdentifierExpression>("expr");
ast::UnaryDerivativeExpression derivative(
params.derivative, ast::DerivativeModifier::kCoarse, std::move(expr));
GeneratorImpl g;
ASSERT_TRUE(g.EmitExpression(&derivative)) << g.error();
EXPECT_EQ(g.result(), std::string(params.name) + "<coarse>(expr)");
}
INSTANTIATE_TEST_SUITE_P(
GeneratorImplTest,
UnaryDerivativeTest,
testing::Values(UnaryDerivativeData{"dpdx", ast::UnaryDerivative::kDpdx},
UnaryDerivativeData{"dpdy", ast::UnaryDerivative::kDpdy},
UnaryDerivativeData{"fwidth",
ast::UnaryDerivative::kFwidth}));
} // namespace
} // namespace wgsl
} // namespace writer
} // namespace tint

View File

@ -1,84 +0,0 @@
// 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 <memory>
#include "gtest/gtest.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/unary_method_expression.h"
#include "src/writer/wgsl/generator_impl.h"
namespace tint {
namespace writer {
namespace wgsl {
namespace {
struct UnaryMethodData {
const char* name;
ast::UnaryMethod method;
};
inline std::ostream& operator<<(std::ostream& out, UnaryMethodData data) {
out << data.method;
return out;
}
using UnaryMethodTest = testing::TestWithParam<UnaryMethodData>;
TEST_P(UnaryMethodTest, Emit) {
auto params = GetParam();
auto expr = std::make_unique<ast::IdentifierExpression>("expr");
ast::ExpressionList ops;
ops.push_back(std::move(expr));
ast::UnaryMethodExpression method(params.method, std::move(ops));
GeneratorImpl g;
ASSERT_TRUE(g.EmitExpression(&method)) << g.error();
EXPECT_EQ(g.result(), std::string(params.name) + "(expr)");
}
INSTANTIATE_TEST_SUITE_P(
GeneratorImplTest,
UnaryMethodTest,
testing::Values(UnaryMethodData{"any", ast::UnaryMethod::kAny},
UnaryMethodData{"all", ast::UnaryMethod::kAll},
UnaryMethodData{"is_nan", ast::UnaryMethod::kIsNan},
UnaryMethodData{"is_finite", ast::UnaryMethod::kIsFinite},
UnaryMethodData{"is_normal", ast::UnaryMethod::kIsNormal}));
using UnaryMethodTest_MultiParam = testing::TestWithParam<UnaryMethodData>;
TEST_P(UnaryMethodTest_MultiParam, Emit) {
auto params = GetParam();
auto expr1 = std::make_unique<ast::IdentifierExpression>("expr1");
auto expr2 = std::make_unique<ast::IdentifierExpression>("expr2");
ast::ExpressionList ops;
ops.push_back(std::move(expr1));
ops.push_back(std::move(expr2));
ast::UnaryMethodExpression method(params.method, std::move(ops));
GeneratorImpl g;
ASSERT_TRUE(g.EmitExpression(&method)) << g.error();
EXPECT_EQ(g.result(), std::string(params.name) + "(expr1, expr2)");
}
INSTANTIATE_TEST_SUITE_P(
GeneratorImplTest,
UnaryMethodTest_MultiParam,
testing::Values(UnaryMethodData{"dot", ast::UnaryMethod::kDot},
UnaryMethodData{"outer_product",
ast::UnaryMethod::kOuterProduct}));
} // namespace
} // namespace wgsl
} // namespace writer
} // namespace tint