blob: 6caeeb4079463bbbd162c9ed07c86feb5cb30762 [file] [log] [blame]
[email protected]96ea63d2013-07-30 10:17:071// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <iostream>
6#include <sstream>
7
8#include "testing/gtest/include/gtest/gtest.h"
9#include "tools/gn/input_file.h"
10#include "tools/gn/parser.h"
11#include "tools/gn/tokenizer.h"
12
13namespace {
14
15bool GetTokens(const InputFile* input, std::vector<Token>* result) {
16 result->clear();
17 Err err;
18 *result = Tokenizer::Tokenize(input, &err);
19 return !err.has_error();
20}
21
[email protected]96ea63d2013-07-30 10:17:0722void DoParserPrintTest(const char* input, const char* expected) {
23 std::vector<Token> tokens;
24 InputFile input_file(SourceFile("/test"));
25 input_file.SetContents(input);
26 ASSERT_TRUE(GetTokens(&input_file, &tokens));
27
28 Err err;
dchenga500b692016-04-08 19:55:4229 std::unique_ptr<ParseNode> result = Parser::Parse(tokens, &err);
[email protected]51d01722014-03-26 16:57:0730 if (!result)
31 err.PrintToStdout();
[email protected]96ea63d2013-07-30 10:17:0732 ASSERT_TRUE(result);
33
34 std::ostringstream collector;
35 result->Print(collector, 0);
36
37 EXPECT_EQ(expected, collector.str());
38}
39
[email protected]f38ddec2013-08-15 23:59:1140void DoExpressionPrintTest(const char* input, const char* expected) {
41 std::vector<Token> tokens;
42 InputFile input_file(SourceFile("/test"));
43 input_file.SetContents(input);
44 ASSERT_TRUE(GetTokens(&input_file, &tokens));
45
46 Err err;
dchenga500b692016-04-08 19:55:4247 std::unique_ptr<ParseNode> result = Parser::ParseExpression(tokens, &err);
[email protected]f38ddec2013-08-15 23:59:1148 ASSERT_TRUE(result);
49
50 std::ostringstream collector;
51 result->Print(collector, 0);
52
53 EXPECT_EQ(expected, collector.str());
54}
55
[email protected]96ea63d2013-07-30 10:17:0756// Expects the tokenizer or parser to identify an error at the given line and
57// character.
58void DoParserErrorTest(const char* input, int err_line, int err_char) {
59 InputFile input_file(SourceFile("/test"));
60 input_file.SetContents(input);
61
62 Err err;
63 std::vector<Token> tokens = Tokenizer::Tokenize(&input_file, &err);
64 if (!err.has_error()) {
dchenga500b692016-04-08 19:55:4265 std::unique_ptr<ParseNode> result = Parser::Parse(tokens, &err);
[email protected]96ea63d2013-07-30 10:17:0766 ASSERT_FALSE(result);
67 ASSERT_TRUE(err.has_error());
68 }
69
70 EXPECT_EQ(err_line, err.location().line_number());
tfarina21aff0d2016-01-06 19:50:0871 EXPECT_EQ(err_char, err.location().column_number());
[email protected]96ea63d2013-07-30 10:17:0772}
73
[email protected]f38ddec2013-08-15 23:59:1174// Expects the tokenizer or parser to identify an error at the given line and
75// character.
76void DoExpressionErrorTest(const char* input, int err_line, int err_char) {
77 InputFile input_file(SourceFile("/test"));
78 input_file.SetContents(input);
[email protected]96ea63d2013-07-30 10:17:0779
[email protected]96ea63d2013-07-30 10:17:0780 Err err;
[email protected]f38ddec2013-08-15 23:59:1181 std::vector<Token> tokens = Tokenizer::Tokenize(&input_file, &err);
82 if (!err.has_error()) {
dchenga500b692016-04-08 19:55:4283 std::unique_ptr<ParseNode> result = Parser::ParseExpression(tokens, &err);
[email protected]f38ddec2013-08-15 23:59:1184 ASSERT_FALSE(result);
85 ASSERT_TRUE(err.has_error());
86 }
[email protected]96ea63d2013-07-30 10:17:0787
[email protected]f38ddec2013-08-15 23:59:1188 EXPECT_EQ(err_line, err.location().line_number());
tfarina21aff0d2016-01-06 19:50:0889 EXPECT_EQ(err_char, err.location().column_number());
[email protected]96ea63d2013-07-30 10:17:0790}
91
[email protected]f38ddec2013-08-15 23:59:1192} // namespace
[email protected]96ea63d2013-07-30 10:17:0793
[email protected]f38ddec2013-08-15 23:59:1194TEST(Parser, Literal) {
95 DoExpressionPrintTest("5", "LITERAL(5)\n");
96 DoExpressionPrintTest("\"stuff\"", "LITERAL(\"stuff\")\n");
97}
[email protected]96ea63d2013-07-30 10:17:0798
[email protected]f38ddec2013-08-15 23:59:1199TEST(Parser, BinaryOp) {
100 // TODO(scottmg): The tokenizer is dumb, and treats "5-1" as two integers,
101 // not a binary operator between two positive integers.
102 DoExpressionPrintTest("5 - 1",
103 "BINARY(-)\n"
104 " LITERAL(5)\n"
105 " LITERAL(1)\n");
106 DoExpressionPrintTest("5+1",
107 "BINARY(+)\n"
108 " LITERAL(5)\n"
109 " LITERAL(1)\n");
110 DoExpressionPrintTest("5 - 1 - 2",
111 "BINARY(-)\n"
112 " BINARY(-)\n"
113 " LITERAL(5)\n"
114 " LITERAL(1)\n"
115 " LITERAL(2)\n");
[email protected]96ea63d2013-07-30 10:17:07116}
117
118TEST(Parser, FunctionCall) {
[email protected]f38ddec2013-08-15 23:59:11119 DoExpressionPrintTest("foo()",
120 "FUNCTION(foo)\n"
[email protected]d3b92ff2013-08-19 22:26:34121 " LIST\n");
[email protected]f38ddec2013-08-15 23:59:11122 DoExpressionPrintTest("blah(1, 2)",
123 "FUNCTION(blah)\n"
124 " LIST\n"
125 " LITERAL(1)\n"
[email protected]d3b92ff2013-08-19 22:26:34126 " LITERAL(2)\n");
[email protected]f38ddec2013-08-15 23:59:11127 DoExpressionErrorTest("foo(1, 2,)", 1, 10);
[email protected]c7d9b352014-04-29 22:18:04128 DoExpressionErrorTest("foo(1 2)", 1, 7);
[email protected]96ea63d2013-07-30 10:17:07129}
130
131TEST(Parser, ParenExpression) {
[email protected]f38ddec2013-08-15 23:59:11132 const char* input = "(foo(1)) + (a + (b - c) + d)";
[email protected]96ea63d2013-07-30 10:17:07133 const char* expected =
[email protected]f38ddec2013-08-15 23:59:11134 "BINARY(+)\n"
135 " FUNCTION(foo)\n"
136 " LIST\n"
137 " LITERAL(1)\n"
[email protected]96ea63d2013-07-30 10:17:07138 " BINARY(+)\n"
[email protected]96ea63d2013-07-30 10:17:07139 " BINARY(+)\n"
140 " IDENTIFIER(a)\n"
[email protected]f38ddec2013-08-15 23:59:11141 " BINARY(-)\n"
142 " IDENTIFIER(b)\n"
143 " IDENTIFIER(c)\n"
144 " IDENTIFIER(d)\n";
145 DoExpressionPrintTest(input, expected);
146 DoExpressionErrorTest("(a +", 1, 4);
147}
148
149TEST(Parser, OrderOfOperationsLeftAssociative) {
150 const char* input = "5 - 1 - 2\n";
151 const char* expected =
152 "BINARY(-)\n"
153 " BINARY(-)\n"
154 " LITERAL(5)\n"
155 " LITERAL(1)\n"
156 " LITERAL(2)\n";
157 DoExpressionPrintTest(input, expected);
158}
159
160TEST(Parser, OrderOfOperationsEqualityBoolean) {
161 const char* input =
162 "if (a == \"b\" && is_stuff) {\n"
163 " print(\"hai\")\n"
164 "}\n";
165 const char* expected =
166 "BLOCK\n"
167 " CONDITION\n"
168 " BINARY(&&)\n"
169 " BINARY(==)\n"
170 " IDENTIFIER(a)\n"
171 " LITERAL(\"b\")\n"
172 " IDENTIFIER(is_stuff)\n"
173 " BLOCK\n"
174 " FUNCTION(print)\n"
175 " LIST\n"
[email protected]d3b92ff2013-08-19 22:26:34176 " LITERAL(\"hai\")\n";
[email protected]96ea63d2013-07-30 10:17:07177 DoParserPrintTest(input, expected);
[email protected]96ea63d2013-07-30 10:17:07178}
179
180TEST(Parser, UnaryOp) {
[email protected]f38ddec2013-08-15 23:59:11181 DoExpressionPrintTest("!foo",
182 "UNARY(!)\n"
183 " IDENTIFIER(foo)\n");
brettw693c60562015-08-07 19:55:17184
185 // No contents for binary operator.
186 DoExpressionErrorTest("a = !", 1, 5);
[email protected]f38ddec2013-08-15 23:59:11187}
[email protected]96ea63d2013-07-30 10:17:07188
[email protected]f38ddec2013-08-15 23:59:11189TEST(Parser, List) {
190 DoExpressionPrintTest("[]", "LIST\n");
191 DoExpressionPrintTest("[1,asd,]",
192 "LIST\n"
193 " LITERAL(1)\n"
194 " IDENTIFIER(asd)\n");
195 DoExpressionPrintTest("[1, 2+3 - foo]",
196 "LIST\n"
197 " LITERAL(1)\n"
198 " BINARY(-)\n"
199 " BINARY(+)\n"
200 " LITERAL(2)\n"
201 " LITERAL(3)\n"
202 " IDENTIFIER(foo)\n");
203 DoExpressionPrintTest("[1,\n2,\n 3,\n 4]",
204 "LIST\n"
205 " LITERAL(1)\n"
206 " LITERAL(2)\n"
207 " LITERAL(3)\n"
208 " LITERAL(4)\n");
[email protected]96ea63d2013-07-30 10:17:07209
mdempskya2c7d0d2015-04-07 20:31:57210 DoExpressionErrorTest("[a, 2+,]", 1, 7);
[email protected]f38ddec2013-08-15 23:59:11211 DoExpressionErrorTest("[,]", 1, 2);
212 DoExpressionErrorTest("[a,,]", 1, 4);
213}
214
215TEST(Parser, Assignment) {
216 DoParserPrintTest("a=2",
217 "BLOCK\n"
218 " BINARY(=)\n"
219 " IDENTIFIER(a)\n"
220 " LITERAL(2)\n");
brettw693c60562015-08-07 19:55:17221
222 DoExpressionErrorTest("a = ", 1, 3);
[email protected]f38ddec2013-08-15 23:59:11223}
224
225TEST(Parser, Accessor) {
[email protected]51d01722014-03-26 16:57:07226 // Accessor indexing.
227 DoParserPrintTest("a=b[c+2]",
[email protected]f38ddec2013-08-15 23:59:11228 "BLOCK\n"
229 " BINARY(=)\n"
230 " IDENTIFIER(a)\n"
231 " ACCESSOR\n"
232 " b\n" // AccessorNode is a bit weird in that it holds
233 // a Token, not a ParseNode for the base.
[email protected]51d01722014-03-26 16:57:07234 " BINARY(+)\n"
235 " IDENTIFIER(c)\n"
236 " LITERAL(2)\n");
[email protected]f38ddec2013-08-15 23:59:11237 DoParserErrorTest("a = b[1][0]", 1, 5);
[email protected]51d01722014-03-26 16:57:07238
239 // Member accessors.
240 DoParserPrintTest("a=b.c+2",
241 "BLOCK\n"
242 " BINARY(=)\n"
243 " IDENTIFIER(a)\n"
244 " BINARY(+)\n"
245 " ACCESSOR\n"
246 " b\n"
247 " IDENTIFIER(c)\n"
248 " LITERAL(2)\n");
brettw01cdea12016-08-04 00:00:34249 DoParserPrintTest("a.b = 5",
250 "BLOCK\n"
251 " BINARY(=)\n"
252 " ACCESSOR\n"
253 " a\n"
254 " IDENTIFIER(b)\n"
255 " LITERAL(5)\n");
[email protected]51d01722014-03-26 16:57:07256 DoParserErrorTest("a = b.c.d", 1, 6); // Can't nest accessors (currently).
mdempskya2c7d0d2015-04-07 20:31:57257
258 // Error at the bad dot in the RHS, not the + operator (crbug.com/472038).
259 DoParserErrorTest("foo(a + b.c.d)", 1, 10);
[email protected]f38ddec2013-08-15 23:59:11260}
261
262TEST(Parser, Condition) {
263 DoParserPrintTest("if(1) { a = 2 }",
264 "BLOCK\n"
265 " CONDITION\n"
266 " LITERAL(1)\n"
267 " BLOCK\n"
268 " BINARY(=)\n"
269 " IDENTIFIER(a)\n"
270 " LITERAL(2)\n");
271
272 DoParserPrintTest("if(1) { a = 2 } else if (0) { a = 3 } else { a = 4 }",
273 "BLOCK\n"
274 " CONDITION\n"
275 " LITERAL(1)\n"
276 " BLOCK\n"
277 " BINARY(=)\n"
278 " IDENTIFIER(a)\n"
279 " LITERAL(2)\n"
280 " CONDITION\n"
281 " LITERAL(0)\n"
282 " BLOCK\n"
283 " BINARY(=)\n"
284 " IDENTIFIER(a)\n"
285 " LITERAL(3)\n"
286 " BLOCK\n"
287 " BINARY(=)\n"
288 " IDENTIFIER(a)\n"
289 " LITERAL(4)\n");
290}
291
292TEST(Parser, OnlyCallAndAssignInBody) {
293 DoParserErrorTest("[]", 1, 2);
294 DoParserErrorTest("3 + 4", 1, 5);
295 DoParserErrorTest("6 - 7", 1, 5);
296 DoParserErrorTest("if (1) { 5 } else { print(4) }", 1, 12);
297}
298
299TEST(Parser, NoAssignmentInCondition) {
300 DoParserErrorTest("if (a=2) {}", 1, 5);
[email protected]96ea63d2013-07-30 10:17:07301}
302
303TEST(Parser, CompleteFunction) {
304 const char* input =
305 "cc_test(\"foo\") {\n"
306 " sources = [\n"
307 " \"foo.cc\",\n"
308 " \"foo.h\"\n"
309 " ]\n"
310 " dependencies = [\n"
311 " \"base\"\n"
312 " ]\n"
313 "}\n";
314 const char* expected =
315 "BLOCK\n"
316 " FUNCTION(cc_test)\n"
317 " LIST\n"
318 " LITERAL(\"foo\")\n"
319 " BLOCK\n"
320 " BINARY(=)\n"
321 " IDENTIFIER(sources)\n"
322 " LIST\n"
323 " LITERAL(\"foo.cc\")\n"
324 " LITERAL(\"foo.h\")\n"
325 " BINARY(=)\n"
326 " IDENTIFIER(dependencies)\n"
327 " LIST\n"
328 " LITERAL(\"base\")\n";
329 DoParserPrintTest(input, expected);
330}
331
332TEST(Parser, FunctionWithConditional) {
333 const char* input =
334 "cc_test(\"foo\") {\n"
335 " sources = [\"foo.cc\"]\n"
336 " if (OS == \"mac\") {\n"
337 " sources += \"bar.cc\"\n"
338 " } else if (OS == \"win\") {\n"
339 " sources -= [\"asd.cc\", \"foo.cc\"]\n"
340 " } else {\n"
341 " dependencies += [\"bar.cc\"]\n"
342 " }\n"
343 "}\n";
344 const char* expected =
345 "BLOCK\n"
346 " FUNCTION(cc_test)\n"
347 " LIST\n"
348 " LITERAL(\"foo\")\n"
349 " BLOCK\n"
350 " BINARY(=)\n"
351 " IDENTIFIER(sources)\n"
352 " LIST\n"
353 " LITERAL(\"foo.cc\")\n"
354 " CONDITION\n"
355 " BINARY(==)\n"
356 " IDENTIFIER(OS)\n"
357 " LITERAL(\"mac\")\n"
358 " BLOCK\n"
359 " BINARY(+=)\n"
360 " IDENTIFIER(sources)\n"
361 " LITERAL(\"bar.cc\")\n"
362 " CONDITION\n"
363 " BINARY(==)\n"
364 " IDENTIFIER(OS)\n"
365 " LITERAL(\"win\")\n"
366 " BLOCK\n"
367 " BINARY(-=)\n"
368 " IDENTIFIER(sources)\n"
369 " LIST\n"
370 " LITERAL(\"asd.cc\")\n"
371 " LITERAL(\"foo.cc\")\n"
372 " BLOCK\n"
373 " BINARY(+=)\n"
374 " IDENTIFIER(dependencies)\n"
375 " LIST\n"
376 " LITERAL(\"bar.cc\")\n";
377 DoParserPrintTest(input, expected);
378}
379
[email protected]96ea63d2013-07-30 10:17:07380TEST(Parser, UnterminatedBlock) {
[email protected]f38ddec2013-08-15 23:59:11381 DoParserErrorTest("stuff() {", 1, 9);
[email protected]96ea63d2013-07-30 10:17:07382}
383
384TEST(Parser, BadlyTerminatedNumber) {
385 DoParserErrorTest("1234z", 1, 5);
386}
[email protected]02f80b72013-08-19 20:53:01387
388TEST(Parser, NewlinesInUnusualPlaces) {
389 DoParserPrintTest(
390 "if\n"
391 "(\n"
392 "a\n"
393 ")\n"
394 "{\n"
395 "}\n",
396 "BLOCK\n"
397 " CONDITION\n"
398 " IDENTIFIER(a)\n"
399 " BLOCK\n");
400}
401
402TEST(Parser, NewlinesInUnusualPlaces2) {
403 DoParserPrintTest(
404 "a\n=\n2\n",
405 "BLOCK\n"
406 " BINARY(=)\n"
407 " IDENTIFIER(a)\n"
408 " LITERAL(2)\n");
409 DoParserPrintTest(
410 "x =\ny if\n(1\n) {}",
411 "BLOCK\n"
412 " BINARY(=)\n"
413 " IDENTIFIER(x)\n"
414 " IDENTIFIER(y)\n"
415 " CONDITION\n"
416 " LITERAL(1)\n"
417 " BLOCK\n");
418 DoParserPrintTest(
419 "x = 3\n+2",
420 "BLOCK\n"
421 " BINARY(=)\n"
422 " IDENTIFIER(x)\n"
423 " BINARY(+)\n"
424 " LITERAL(3)\n"
425 " LITERAL(2)\n"
426 );
427}
428
429TEST(Parser, NewlineBeforeSubscript) {
430 const char* input = "a = b[1]";
431 const char* input_with_newline = "a = b\n[1]";
432 const char* expected =
433 "BLOCK\n"
434 " BINARY(=)\n"
435 " IDENTIFIER(a)\n"
436 " ACCESSOR\n"
437 " b\n"
438 " LITERAL(1)\n";
439 DoParserPrintTest(
440 input,
441 expected);
442 DoParserPrintTest(
443 input_with_newline,
444 expected);
445}
446
447TEST(Parser, SequenceOfExpressions) {
448 DoParserPrintTest(
449 "a = 1 b = 2",
450 "BLOCK\n"
451 " BINARY(=)\n"
452 " IDENTIFIER(a)\n"
453 " LITERAL(1)\n"
454 " BINARY(=)\n"
455 " IDENTIFIER(b)\n"
456 " LITERAL(2)\n");
457}
458
459TEST(Parser, BlockAfterFunction) {
460 const char* input = "func(\"stuff\") {\n}";
461 // TODO(scottmg): Do we really want these to mean different things?
462 const char* input_with_newline = "func(\"stuff\")\n{\n}";
463 const char* expected =
464 "BLOCK\n"
465 " FUNCTION(func)\n"
466 " LIST\n"
467 " LITERAL(\"stuff\")\n"
468 " BLOCK\n";
469 DoParserPrintTest(input, expected);
470 DoParserPrintTest(input_with_newline, expected);
471}
472
473TEST(Parser, LongExpression) {
474 const char* input = "a = b + c && d || e";
475 const char* expected =
476 "BLOCK\n"
477 " BINARY(=)\n"
478 " IDENTIFIER(a)\n"
479 " BINARY(||)\n"
480 " BINARY(&&)\n"
481 " BINARY(+)\n"
482 " IDENTIFIER(b)\n"
483 " IDENTIFIER(c)\n"
484 " IDENTIFIER(d)\n"
485 " IDENTIFIER(e)\n";
486 DoParserPrintTest(input, expected);
487}
[email protected]6ac871ea2013-08-19 21:04:50488
scottmgbe5d4512014-09-24 02:29:12489TEST(Parser, CommentsStandalone) {
490 const char* input =
491 "# Toplevel comment.\n"
492 "\n"
493 "executable(\"wee\") {}\n";
494 const char* expected =
495 "BLOCK\n"
scottmg2dd93e8b2014-09-26 04:07:05496 " BLOCK_COMMENT(# Toplevel comment.)\n"
scottmgbe5d4512014-09-24 02:29:12497 " FUNCTION(executable)\n"
498 " LIST\n"
499 " LITERAL(\"wee\")\n"
500 " BLOCK\n";
501 DoParserPrintTest(input, expected);
502}
503
504TEST(Parser, CommentsStandaloneEof) {
505 const char* input =
506 "executable(\"wee\") {}\n"
507 "# EOF comment.\n";
508 const char* expected =
509 "BLOCK\n"
510 " +AFTER_COMMENT(\"# EOF comment.\")\n"
511 " FUNCTION(executable)\n"
512 " LIST\n"
513 " LITERAL(\"wee\")\n"
514 " BLOCK\n";
515 DoParserPrintTest(input, expected);
516}
517
518TEST(Parser, CommentsLineAttached) {
519 const char* input =
520 "executable(\"wee\") {\n"
521 " # Some sources.\n"
522 " sources = [\n"
523 " \"stuff.cc\",\n"
524 " \"things.cc\",\n"
525 " # This file is special or something.\n"
526 " \"another.cc\",\n"
527 " ]\n"
528 "}\n";
529 const char* expected =
530 "BLOCK\n"
531 " FUNCTION(executable)\n"
532 " LIST\n"
533 " LITERAL(\"wee\")\n"
534 " BLOCK\n"
535 " BINARY(=)\n"
536 " +BEFORE_COMMENT(\"# Some sources.\")\n"
537 " IDENTIFIER(sources)\n"
538 " LIST\n"
539 " LITERAL(\"stuff.cc\")\n"
540 " LITERAL(\"things.cc\")\n"
541 " LITERAL(\"another.cc\")\n"
542 " +BEFORE_COMMENT(\"# This file is special or something.\")\n";
543 DoParserPrintTest(input, expected);
544}
545
546TEST(Parser, CommentsSuffix) {
547 const char* input =
548 "executable(\"wee\") { # This is some stuff.\n"
549 "sources = [ \"a.cc\" # And another comment here.\n"
550 "] }";
551 const char* expected =
552 "BLOCK\n"
553 " FUNCTION(executable)\n"
554 " LIST\n"
555 " LITERAL(\"wee\")\n"
scottmg571a81f2014-11-05 23:44:45556 " END())\n"
scottmgbe5d4512014-09-24 02:29:12557 " +SUFFIX_COMMENT(\"# This is some stuff.\")\n"
558 " BLOCK\n"
559 " BINARY(=)\n"
560 " IDENTIFIER(sources)\n"
561 " LIST\n"
562 " LITERAL(\"a.cc\")\n"
563 " +SUFFIX_COMMENT(\"# And another comment here.\")\n";
564 DoParserPrintTest(input, expected);
565}
566
567TEST(Parser, CommentsSuffixDifferentLine) {
568 const char* input =
569 "executable(\"wee\") {\n"
570 " sources = [ \"a\",\n"
571 " \"b\" ] # Comment\n"
572 "}\n";
573 const char* expected =
574 "BLOCK\n"
575 " FUNCTION(executable)\n"
576 " LIST\n"
577 " LITERAL(\"wee\")\n"
578 " BLOCK\n"
579 " BINARY(=)\n"
580 " IDENTIFIER(sources)\n"
581 " LIST\n"
582 " LITERAL(\"a\")\n"
583 " LITERAL(\"b\")\n"
scottmg571a81f2014-11-05 23:44:45584 " END(])\n"
scottmgbe5d4512014-09-24 02:29:12585 " +SUFFIX_COMMENT(\"# Comment\")\n";
586 DoParserPrintTest(input, expected);
587}
588
scottmg7b80f172014-09-24 03:35:13589TEST(Parser, CommentsSuffixMultiple) {
590 const char* input =
591 "executable(\"wee\") {\n"
592 " sources = [\n"
593 " \"a\", # This is a comment,\n"
594 " # and some more,\n" // Note that this is aligned with above.
595 " # then the end.\n"
596 " ]\n"
597 "}\n";
598 const char* expected =
599 "BLOCK\n"
600 " FUNCTION(executable)\n"
601 " LIST\n"
602 " LITERAL(\"wee\")\n"
603 " BLOCK\n"
604 " BINARY(=)\n"
605 " IDENTIFIER(sources)\n"
606 " LIST\n"
607 " LITERAL(\"a\")\n"
608 " +SUFFIX_COMMENT(\"# This is a comment,\")\n"
609 " +SUFFIX_COMMENT(\"# and some more,\")\n"
610 " +SUFFIX_COMMENT(\"# then the end.\")\n";
611 DoParserPrintTest(input, expected);
612}
613
scottmg2dd93e8b2014-09-26 04:07:05614TEST(Parser, CommentsConnectedInList) {
615 const char* input =
616 "defines = [\n"
617 "\n"
618 " # Connected comment.\n"
619 " \"WEE\",\n"
620 " \"BLORPY\",\n"
621 "]\n";
622 const char* expected =
623 "BLOCK\n"
624 " BINARY(=)\n"
625 " IDENTIFIER(defines)\n"
626 " LIST\n"
627 " LITERAL(\"WEE\")\n"
628 " +BEFORE_COMMENT(\"# Connected comment.\")\n"
629 " LITERAL(\"BLORPY\")\n";
630 DoParserPrintTest(input, expected);
631}
632
scottmgf7e13e522014-09-29 19:21:09633TEST(Parser, CommentsAtEndOfBlock) {
634 const char* input =
635 "if (is_win) {\n"
636 " sources = [\"a.cc\"]\n"
637 " # Some comment at end.\n"
638 "}\n";
639 const char* expected =
640 "BLOCK\n"
641 " CONDITION\n"
642 " IDENTIFIER(is_win)\n"
643 " BLOCK\n"
644 " BINARY(=)\n"
645 " IDENTIFIER(sources)\n"
646 " LIST\n"
647 " LITERAL(\"a.cc\")\n"
648 " END(})\n"
649 " +BEFORE_COMMENT(\"# Some comment at end.\")\n";
650 DoParserPrintTest(input, expected);
651}
652
653// TODO(scottmg): I could be convinced this is incorrect. It's not clear to me
654// which thing this comment is intended to be attached to.
655TEST(Parser, CommentsEndOfBlockSingleLine) {
656 const char* input =
657 "defines = [ # EOL defines.\n"
658 "]\n";
659 const char* expected =
660 "BLOCK\n"
661 " BINARY(=)\n"
662 " IDENTIFIER(defines)\n"
663 " +SUFFIX_COMMENT(\"# EOL defines.\")\n"
664 " LIST\n";
665 DoParserPrintTest(input, expected);
666}
667
[email protected]6ac871ea2013-08-19 21:04:50668TEST(Parser, HangingIf) {
669 DoParserErrorTest("if", 1, 1);
670}
[email protected]8f4f9a842013-09-11 20:35:03671
672TEST(Parser, NegatingList) {
673 DoParserErrorTest("executable(\"wee\") { sources =- [ \"foo.cc\" ] }", 1, 30);
674}
scottmg3d5823f2015-03-10 21:28:41675
676TEST(Parser, ConditionNoBracesIf) {
677 DoParserErrorTest(
678 "if (true)\n"
679 " foreach(foo, []) {}\n"
680 "else {\n"
681 " foreach(bar, []) {}\n"
682 "}\n",
683 2, 3);
684}
685
686TEST(Parser, ConditionNoBracesElse) {
687 DoParserErrorTest(
688 "if (true) {\n"
689 " foreach(foo, []) {}\n"
690 "} else\n"
691 " foreach(bar, []) {}\n",
692 4, 3);
693}
694
695TEST(Parser, ConditionNoBracesElseIf) {
696 DoParserErrorTest(
697 "if (true) {\n"
698 " foreach(foo, []) {}\n"
699 "} else if (true)\n"
700 " foreach(bar, []) {}\n",
701 4, 3);
702}
Brett Wilson989adc842015-03-16 17:52:52703
704// Disallow standalone {} for introducing new scopes. These are ambiguous with
705// target declarations (e.g. is:
706// foo("bar") {}
707// a function with an associated block, or a standalone function with a
708// freestanding block.
709TEST(Parser, StandaloneBlock) {
brettw01cdea12016-08-04 00:00:34710 // The error is reported at the end of the block when nothing is done
711 // with it. If we had said "a = { ..." then it would have been OK.
Brett Wilson989adc842015-03-16 17:52:52712 DoParserErrorTest(
713 "if (true) {\n"
714 "}\n"
715 "{\n"
716 " assert(false)\n"
717 "}\n",
brettw01cdea12016-08-04 00:00:34718 5, 1);
719}
720
721TEST(Parser, BlockValues) {
722 const char* input =
723 "print({a = 1 b = 2}, 3)\n"
724 "a = { b = \"asd\" }";
725 const char* expected =
726 "BLOCK\n"
727 " FUNCTION(print)\n"
728 " LIST\n"
729 " BLOCK\n"
730 " BINARY(=)\n"
731 " IDENTIFIER(a)\n"
732 " LITERAL(1)\n"
733 " BINARY(=)\n"
734 " IDENTIFIER(b)\n"
735 " LITERAL(2)\n"
736 " LITERAL(3)\n"
737 " BINARY(=)\n"
738 " IDENTIFIER(a)\n"
739 " BLOCK\n"
740 " BINARY(=)\n"
741 " IDENTIFIER(b)\n"
742 " LITERAL(\"asd\")\n";
743 DoParserPrintTest(input, expected);
Brett Wilson989adc842015-03-16 17:52:52744}