1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/reader/wgsl/parser_impl_test_helper.h"
16
17 #include "src/ast/discard_statement.h"
18
19 namespace tint {
20 namespace reader {
21 namespace wgsl {
22 namespace {
23
24 using ForStmtTest = ParserImplTest;
25
26 // Test an empty for loop.
TEST_F(ForStmtTest,Empty)27 TEST_F(ForStmtTest, Empty) {
28 auto p = parser("for (;;) { }");
29 auto fl = p->for_stmt();
30 EXPECT_FALSE(p->has_error()) << p->error();
31 EXPECT_FALSE(fl.errored);
32 ASSERT_TRUE(fl.matched);
33 EXPECT_EQ(fl->initializer, nullptr);
34 EXPECT_EQ(fl->condition, nullptr);
35 EXPECT_EQ(fl->continuing, nullptr);
36 EXPECT_TRUE(fl->body->Empty());
37 }
38
39 // Test a for loop with non-empty body.
TEST_F(ForStmtTest,Body)40 TEST_F(ForStmtTest, Body) {
41 auto p = parser("for (;;) { discard; }");
42 auto fl = p->for_stmt();
43 EXPECT_FALSE(p->has_error()) << p->error();
44 EXPECT_FALSE(fl.errored);
45 ASSERT_TRUE(fl.matched);
46 EXPECT_EQ(fl->initializer, nullptr);
47 EXPECT_EQ(fl->condition, nullptr);
48 EXPECT_EQ(fl->continuing, nullptr);
49 ASSERT_EQ(fl->body->statements.size(), 1u);
50 EXPECT_TRUE(fl->body->statements[0]->Is<ast::DiscardStatement>());
51 }
52
53 // Test a for loop declaring a variable in the initializer statement.
TEST_F(ForStmtTest,InitializerStatementDecl)54 TEST_F(ForStmtTest, InitializerStatementDecl) {
55 auto p = parser("for (var i: i32 ;;) { }");
56 auto fl = p->for_stmt();
57 EXPECT_FALSE(p->has_error()) << p->error();
58 EXPECT_FALSE(fl.errored);
59 ASSERT_TRUE(fl.matched);
60 ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
61 auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
62 EXPECT_FALSE(var->is_const);
63 EXPECT_EQ(var->constructor, nullptr);
64 EXPECT_EQ(fl->condition, nullptr);
65 EXPECT_EQ(fl->continuing, nullptr);
66 EXPECT_TRUE(fl->body->Empty());
67 }
68
69 // Test a for loop declaring and initializing a variable in the initializer
70 // statement.
TEST_F(ForStmtTest,InitializerStatementDeclEqual)71 TEST_F(ForStmtTest, InitializerStatementDeclEqual) {
72 auto p = parser("for (var i: i32 = 0 ;;) { }");
73 auto fl = p->for_stmt();
74 EXPECT_FALSE(p->has_error()) << p->error();
75 EXPECT_FALSE(fl.errored);
76 ASSERT_TRUE(fl.matched);
77 ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
78 auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
79 EXPECT_FALSE(var->is_const);
80 EXPECT_NE(var->constructor, nullptr);
81 EXPECT_EQ(fl->condition, nullptr);
82 EXPECT_EQ(fl->continuing, nullptr);
83 EXPECT_TRUE(fl->body->Empty());
84 }
85
86 // Test a for loop declaring a const variable in the initializer statement.
TEST_F(ForStmtTest,InitializerStatementConstDecl)87 TEST_F(ForStmtTest, InitializerStatementConstDecl) {
88 auto p = parser("for (let i: i32 = 0 ;;) { }");
89 auto fl = p->for_stmt();
90 EXPECT_FALSE(p->has_error()) << p->error();
91 EXPECT_FALSE(fl.errored);
92 ASSERT_TRUE(fl.matched);
93 ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
94 auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
95 EXPECT_TRUE(var->is_const);
96 EXPECT_NE(var->constructor, nullptr);
97 EXPECT_EQ(fl->condition, nullptr);
98 EXPECT_EQ(fl->continuing, nullptr);
99 EXPECT_TRUE(fl->body->Empty());
100 }
101
102 // Test a for loop assigning a variable in the initializer statement.
TEST_F(ForStmtTest,InitializerStatementAssignment)103 TEST_F(ForStmtTest, InitializerStatementAssignment) {
104 auto p = parser("for (i = 0 ;;) { }");
105 auto fl = p->for_stmt();
106 EXPECT_FALSE(p->has_error()) << p->error();
107 EXPECT_FALSE(fl.errored);
108 ASSERT_TRUE(fl.matched);
109 EXPECT_TRUE(Is<ast::AssignmentStatement>(fl->initializer));
110 EXPECT_EQ(fl->condition, nullptr);
111 EXPECT_EQ(fl->continuing, nullptr);
112 EXPECT_TRUE(fl->body->Empty());
113 }
114
115 // Test a for loop calling a function in the initializer statement.
TEST_F(ForStmtTest,InitializerStatementFuncCall)116 TEST_F(ForStmtTest, InitializerStatementFuncCall) {
117 auto p = parser("for (a(b,c) ;;) { }");
118 auto fl = p->for_stmt();
119 EXPECT_FALSE(p->has_error()) << p->error();
120 EXPECT_FALSE(fl.errored);
121 ASSERT_TRUE(fl.matched);
122 EXPECT_TRUE(Is<ast::CallStatement>(fl->initializer));
123 EXPECT_EQ(fl->condition, nullptr);
124 EXPECT_EQ(fl->continuing, nullptr);
125 EXPECT_TRUE(fl->body->Empty());
126 }
127
128 // Test a for loop with a break condition
TEST_F(ForStmtTest,BreakCondition)129 TEST_F(ForStmtTest, BreakCondition) {
130 auto p = parser("for (; 0 == 1;) { }");
131 auto fl = p->for_stmt();
132 EXPECT_FALSE(p->has_error()) << p->error();
133 EXPECT_FALSE(fl.errored);
134 ASSERT_TRUE(fl.matched);
135 EXPECT_EQ(fl->initializer, nullptr);
136 EXPECT_TRUE(Is<ast::BinaryExpression>(fl->condition));
137 EXPECT_EQ(fl->continuing, nullptr);
138 EXPECT_TRUE(fl->body->Empty());
139 }
140
141 // Test a for loop assigning a variable in the continuing statement.
TEST_F(ForStmtTest,ContinuingAssignment)142 TEST_F(ForStmtTest, ContinuingAssignment) {
143 auto p = parser("for (;; x = 2) { }");
144 auto fl = p->for_stmt();
145 EXPECT_FALSE(p->has_error()) << p->error();
146 EXPECT_FALSE(fl.errored);
147 ASSERT_TRUE(fl.matched);
148 EXPECT_EQ(fl->initializer, nullptr);
149 EXPECT_EQ(fl->condition, nullptr);
150 EXPECT_TRUE(Is<ast::AssignmentStatement>(fl->continuing));
151 EXPECT_TRUE(fl->body->Empty());
152 }
153
154 // Test a for loop calling a function in the continuing statement.
TEST_F(ForStmtTest,ContinuingFuncCall)155 TEST_F(ForStmtTest, ContinuingFuncCall) {
156 auto p = parser("for (;; a(b,c)) { }");
157 auto fl = p->for_stmt();
158 EXPECT_FALSE(p->has_error()) << p->error();
159 EXPECT_FALSE(fl.errored);
160 ASSERT_TRUE(fl.matched);
161 EXPECT_EQ(fl->initializer, nullptr);
162 EXPECT_EQ(fl->condition, nullptr);
163 EXPECT_TRUE(Is<ast::CallStatement>(fl->continuing));
164 EXPECT_TRUE(fl->body->Empty());
165 }
166
167 class ForStmtErrorTest : public ParserImplTest {
168 public:
TestForWithError(std::string for_str,std::string error_str)169 void TestForWithError(std::string for_str, std::string error_str) {
170 auto p_for = parser(for_str);
171 auto e_for = p_for->for_stmt();
172
173 EXPECT_FALSE(e_for.matched);
174 EXPECT_TRUE(e_for.errored);
175 EXPECT_TRUE(p_for->has_error());
176 ASSERT_EQ(e_for.value, nullptr);
177 EXPECT_EQ(p_for->error(), error_str);
178 }
179 };
180
181 // Test a for loop with missing left parenthesis is invalid.
TEST_F(ForStmtErrorTest,MissingLeftParen)182 TEST_F(ForStmtErrorTest, MissingLeftParen) {
183 std::string for_str = "for { }";
184 std::string error_str = "1:5: expected '(' for for loop";
185
186 TestForWithError(for_str, error_str);
187 }
188
189 // Test a for loop with missing first semicolon is invalid.
TEST_F(ForStmtErrorTest,MissingFirstSemicolon)190 TEST_F(ForStmtErrorTest, MissingFirstSemicolon) {
191 std::string for_str = "for () {}";
192 std::string error_str = "1:6: expected ';' for initializer in for loop";
193
194 TestForWithError(for_str, error_str);
195 }
196
197 // Test a for loop with missing second semicolon is invalid.
TEST_F(ForStmtErrorTest,MissingSecondSemicolon)198 TEST_F(ForStmtErrorTest, MissingSecondSemicolon) {
199 std::string for_str = "for (;) {}";
200 std::string error_str = "1:7: expected ';' for condition in for loop";
201
202 TestForWithError(for_str, error_str);
203 }
204
205 // Test a for loop with missing right parenthesis is invalid.
TEST_F(ForStmtErrorTest,MissingRightParen)206 TEST_F(ForStmtErrorTest, MissingRightParen) {
207 std::string for_str = "for (;; {}";
208 std::string error_str = "1:9: expected ')' for for loop";
209
210 TestForWithError(for_str, error_str);
211 }
212
213 // Test a for loop with missing left brace is invalid.
TEST_F(ForStmtErrorTest,MissingLeftBrace)214 TEST_F(ForStmtErrorTest, MissingLeftBrace) {
215 std::string for_str = "for (;;)";
216 std::string error_str = "1:9: expected '{' for for loop";
217
218 TestForWithError(for_str, error_str);
219 }
220
221 // Test a for loop with missing right brace is invalid.
TEST_F(ForStmtErrorTest,MissingRightBrace)222 TEST_F(ForStmtErrorTest, MissingRightBrace) {
223 std::string for_str = "for (;;) {";
224 std::string error_str = "1:11: expected '}' for for loop";
225
226 TestForWithError(for_str, error_str);
227 }
228
229 // Test a for loop with an invalid initializer statement.
TEST_F(ForStmtErrorTest,InvalidInitializerAsConstDecl)230 TEST_F(ForStmtErrorTest, InvalidInitializerAsConstDecl) {
231 std::string for_str = "for (let x: i32;;) { }";
232 std::string error_str = "1:16: expected '=' for let declaration";
233
234 TestForWithError(for_str, error_str);
235 }
236
237 // Test a for loop with a initializer statement not matching
238 // variable_stmt | assignment_stmt | func_call_stmt.
TEST_F(ForStmtErrorTest,InvalidInitializerMatch)239 TEST_F(ForStmtErrorTest, InvalidInitializerMatch) {
240 std::string for_str = "for (if (true) {} ;;) { }";
241 std::string error_str = "1:6: expected ';' for initializer in for loop";
242
243 TestForWithError(for_str, error_str);
244 }
245
246 // Test a for loop with an invalid break condition.
TEST_F(ForStmtErrorTest,InvalidBreakConditionAsExpression)247 TEST_F(ForStmtErrorTest, InvalidBreakConditionAsExpression) {
248 std::string for_str = "for (; (0 == 1; ) { }";
249 std::string error_str = "1:15: expected ')'";
250
251 TestForWithError(for_str, error_str);
252 }
253
254 // Test a for loop with a break condition not matching
255 // logical_or_expression.
TEST_F(ForStmtErrorTest,InvalidBreakConditionMatch)256 TEST_F(ForStmtErrorTest, InvalidBreakConditionMatch) {
257 std::string for_str = "for (; var i: i32 = 0;) { }";
258 std::string error_str = "1:8: expected ';' for condition in for loop";
259
260 TestForWithError(for_str, error_str);
261 }
262
263 // Test a for loop with an invalid continuing statement.
TEST_F(ForStmtErrorTest,InvalidContinuingAsFuncCall)264 TEST_F(ForStmtErrorTest, InvalidContinuingAsFuncCall) {
265 std::string for_str = "for (;; a(,) ) { }";
266 std::string error_str = "1:11: expected ')' for function call";
267
268 TestForWithError(for_str, error_str);
269 }
270
271 // Test a for loop with a continuing statement not matching
272 // assignment_stmt | func_call_stmt.
TEST_F(ForStmtErrorTest,InvalidContinuingMatch)273 TEST_F(ForStmtErrorTest, InvalidContinuingMatch) {
274 std::string for_str = "for (;; var i: i32 = 0) { }";
275 std::string error_str = "1:9: expected ')' for for loop";
276
277 TestForWithError(for_str, error_str);
278 }
279
280 // Test a for loop with an invalid body.
TEST_F(ForStmtErrorTest,InvalidBody)281 TEST_F(ForStmtErrorTest, InvalidBody) {
282 std::string for_str = "for (;;) { let x: i32; }";
283 std::string error_str = "1:22: expected '=' for let declaration";
284
285 TestForWithError(for_str, error_str);
286 }
287
288 // Test a for loop with a body not matching statements
TEST_F(ForStmtErrorTest,InvalidBodyMatch)289 TEST_F(ForStmtErrorTest, InvalidBodyMatch) {
290 std::string for_str = "for (;;) { fn main() {} }";
291 std::string error_str = "1:12: expected '}' for for loop";
292
293 TestForWithError(for_str, error_str);
294 }
295
296 } // namespace
297 } // namespace wgsl
298 } // namespace reader
299 } // namespace tint
300