• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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