writer/wgsl: Handle for-loops
Bug: tint:952
Change-Id: I712a0b448f187f02ef97f7f9b3887e00f674716a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56763
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 077e990..762f832 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -75,9 +75,11 @@
return false;
}
} else if (auto* var = decl->As<ast::Variable>()) {
+ make_indent();
if (!EmitVariable(var)) {
return false;
}
+ out_ << ";" << std::endl;
} else {
TINT_UNREACHABLE(Writer, diagnostics_);
return false;
@@ -575,8 +577,6 @@
}
bool GeneratorImpl::EmitVariable(ast::Variable* var) {
- make_indent();
-
if (!var->decorations().empty()) {
if (!EmitDecorations(var->decorations())) {
return false;
@@ -617,7 +617,6 @@
return false;
}
}
- out_ << ";" << std::endl;
return true;
}
@@ -819,16 +818,6 @@
return true;
}
-bool GeneratorImpl::EmitIndentedBlockAndNewline(
- const ast::BlockStatement* stmt) {
- make_indent();
- const bool result = EmitBlock(stmt);
- if (result) {
- out_ << std::endl;
- }
- return result;
-}
-
bool GeneratorImpl::EmitBlockAndNewline(const ast::BlockStatement* stmt) {
const bool result = EmitBlock(stmt);
if (result) {
@@ -838,22 +827,32 @@
}
bool GeneratorImpl::EmitStatement(ast::Statement* stmt) {
+ make_indent();
+
+ if (!EmitRawStatement(stmt)) {
+ return false;
+ }
+
+ if (!stmt->IsAnyOf<ast::BlockStatement, ast::IfStatement,
+ ast::SwitchStatement, ast::LoopStatement,
+ ast::ForLoopStatement>()) {
+ out_ << ";" << std::endl;
+ }
+ return true;
+}
+
+bool GeneratorImpl::EmitRawStatement(ast::Statement* stmt) {
if (auto* a = stmt->As<ast::AssignmentStatement>()) {
return EmitAssign(a);
}
if (auto* b = stmt->As<ast::BlockStatement>()) {
- return EmitIndentedBlockAndNewline(b);
+ return EmitBlockAndNewline(b);
}
if (auto* b = stmt->As<ast::BreakStatement>()) {
return EmitBreak(b);
}
if (auto* c = stmt->As<ast::CallStatement>()) {
- make_indent();
- if (!EmitCall(c->expr())) {
- return false;
- }
- out_ << ";" << std::endl;
- return true;
+ return EmitCall(c->expr());
}
if (auto* c = stmt->As<ast::ContinueStatement>()) {
return EmitContinue(c);
@@ -870,6 +869,9 @@
if (auto* l = stmt->As<ast::LoopStatement>()) {
return EmitLoop(l);
}
+ if (auto* l = stmt->As<ast::ForLoopStatement>()) {
+ return EmitForLoop(l);
+ }
if (auto* r = stmt->As<ast::ReturnStatement>()) {
return EmitReturn(r);
}
@@ -886,8 +888,6 @@
}
bool GeneratorImpl::EmitAssign(ast::AssignmentStatement* stmt) {
- make_indent();
-
if (!EmitExpression(stmt->lhs())) {
return false;
}
@@ -898,14 +898,11 @@
return false;
}
- out_ << ";" << std::endl;
-
return true;
}
bool GeneratorImpl::EmitBreak(ast::BreakStatement*) {
- make_indent();
- out_ << "break;" << std::endl;
+ out_ << "break";
return true;
}
@@ -935,8 +932,7 @@
}
bool GeneratorImpl::EmitContinue(ast::ContinueStatement*) {
- make_indent();
- out_ << "continue;" << std::endl;
+ out_ << "continue";
return true;
}
@@ -955,14 +951,11 @@
}
bool GeneratorImpl::EmitFallthrough(ast::FallthroughStatement*) {
- make_indent();
- out_ << "fallthrough;" << std::endl;
+ out_ << "fallthrough";
return true;
}
bool GeneratorImpl::EmitIf(ast::IfStatement* stmt) {
- make_indent();
-
out_ << "if (";
if (!EmitExpression(stmt->condition())) {
return false;
@@ -984,14 +977,11 @@
}
bool GeneratorImpl::EmitDiscard(ast::DiscardStatement*) {
- make_indent();
- out_ << "discard;" << std::endl;
+ out_ << "discard";
return true;
}
bool GeneratorImpl::EmitLoop(ast::LoopStatement* stmt) {
- make_indent();
-
out_ << "loop {" << std::endl;
increment_indent();
@@ -1019,9 +1009,50 @@
return true;
}
-bool GeneratorImpl::EmitReturn(ast::ReturnStatement* stmt) {
- make_indent();
+bool GeneratorImpl::EmitForLoop(ast::ForLoopStatement* stmt) {
+ out_ << "for";
+ {
+ ScopedParen sp(out_);
+ if (auto* init = stmt->initializer()) {
+ if (!EmitRawStatement(init)) {
+ return false;
+ }
+ }
+ out_ << "; ";
+
+ if (auto* cond = stmt->condition()) {
+ if (!EmitExpression(cond)) {
+ return false;
+ }
+ }
+
+ out_ << "; ";
+
+ if (auto* cont = stmt->continuing()) {
+ if (!EmitRawStatement(cont)) {
+ return false;
+ }
+ }
+ }
+ out_ << " {" << std::endl;
+
+ {
+ ScopedIndent si(this);
+ for (auto* s : stmt->body()->statements()) {
+ if (!EmitStatement(s)) {
+ return false;
+ }
+ }
+ }
+
+ make_indent();
+ out_ << "}" << std::endl;
+
+ return true;
+}
+
+bool GeneratorImpl::EmitReturn(ast::ReturnStatement* stmt) {
out_ << "return";
if (stmt->has_value()) {
out_ << " ";
@@ -1029,13 +1060,10 @@
return false;
}
}
- out_ << ";" << std::endl;
return true;
}
bool GeneratorImpl::EmitSwitch(ast::SwitchStatement* stmt) {
- make_indent();
-
out_ << "switch(";
if (!EmitExpression(stmt->condition())) {
return false;
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index 7d7c732..34d5fa1 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -25,6 +25,7 @@
#include "src/ast/continue_statement.h"
#include "src/ast/discard_statement.h"
#include "src/ast/fallthrough_statement.h"
+#include "src/ast/for_loop_statement.h"
#include "src/ast/if_statement.h"
#include "src/ast/loop_statement.h"
#include "src/ast/member_accessor_expression.h"
@@ -81,10 +82,6 @@
/// Handles a block statement with a newline at the end
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
- bool EmitIndentedBlockAndNewline(const ast::BlockStatement* stmt);
- /// Handles a block statement with a newline at the end
- /// @param stmt the statement to emit
- /// @returns true if the statement was emitted successfully
bool EmitBlockAndNewline(const ast::BlockStatement* stmt);
/// Handles a break statement
/// @param stmt the statement to emit
@@ -146,6 +143,10 @@
/// @param stmt the statement to emit
/// @returns true if the statement was emtited
bool EmitLoop(ast::LoopStatement* stmt);
+ /// Handles a for-loop statement
+ /// @param stmt the statement to emit
+ /// @returns true if the statement was emtited
+ bool EmitForLoop(ast::ForLoopStatement* stmt);
/// Handles a member accessor expression
/// @param expr the member accessor expression
/// @returns true if the member accessor was emitted
@@ -158,6 +159,11 @@
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
bool EmitStatement(ast::Statement* stmt);
+ /// Emits a statement without an indentation or trailing semi-colon and
+ /// newline
+ /// @param stmt the statement to emit
+ /// @returns true if the statement was emitted
+ bool EmitRawStatement(ast::Statement* stmt);
/// Handles generating a switch statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted
diff --git a/src/writer/wgsl/generator_impl_variable_test.cc b/src/writer/wgsl/generator_impl_variable_test.cc
index 2122c60..5cc340e 100644
--- a/src/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/writer/wgsl/generator_impl_variable_test.cc
@@ -29,8 +29,7 @@
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
- EXPECT_EQ(gen.result(), R"(var<private> a : f32;
-)");
+ EXPECT_EQ(gen.result(), R"(var<private> a : f32)");
}
TEST_F(WgslGeneratorImplTest, EmitVariable_StorageClass) {
@@ -39,8 +38,7 @@
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
- EXPECT_EQ(gen.result(), R"(var<private> a : f32;
-)");
+ EXPECT_EQ(gen.result(), R"(var<private> a : f32)");
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Read) {
@@ -56,8 +54,8 @@
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
- EXPECT_EQ(gen.result(), R"([[binding(0), group(0)]] var<storage, read> a : S;
-)");
+ EXPECT_EQ(gen.result(),
+ R"([[binding(0), group(0)]] var<storage, read> a : S)");
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Write) {
@@ -73,8 +71,8 @@
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
- EXPECT_EQ(gen.result(), R"([[binding(0), group(0)]] var<storage, write> a : S;
-)");
+ EXPECT_EQ(gen.result(),
+ R"([[binding(0), group(0)]] var<storage, write> a : S)");
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Access_ReadWrite) {
@@ -91,8 +89,7 @@
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
EXPECT_EQ(gen.result(),
- R"([[binding(0), group(0)]] var<storage, read_write> a : S;
-)");
+ R"([[binding(0), group(0)]] var<storage, read_write> a : S)");
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) {
@@ -106,9 +103,7 @@
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
- EXPECT_EQ(gen.result(),
- R"([[group(1), binding(2)]] var a : sampler;
-)");
+ EXPECT_EQ(gen.result(), R"([[group(1), binding(2)]] var a : sampler)");
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Constructor) {
@@ -117,8 +112,7 @@
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
- EXPECT_EQ(gen.result(), R"(var<private> a : f32 = 1.0;
-)");
+ EXPECT_EQ(gen.result(), R"(var<private> a : f32 = 1.0)");
}
TEST_F(WgslGeneratorImplTest, EmitVariable_Const) {
@@ -128,8 +122,7 @@
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
- EXPECT_EQ(gen.result(), R"(let a : f32 = 1.0;
-)");
+ EXPECT_EQ(gen.result(), R"(let a : f32 = 1.0)");
}
} // namespace