blob: 39b69b7845c619f1d2709b2ae3330957d7944d69 [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;
29 scoped_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;
47 scoped_ptr<ParseNode> result = Parser::ParseExpression(tokens, &err);
48 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()) {
65 scoped_ptr<ParseNode> result = Parser::Parse(tokens, &err);
66 ASSERT_FALSE(result);
67 ASSERT_TRUE(err.has_error());
68 }
69
70 EXPECT_EQ(err_line, err.location().line_number());
71 EXPECT_EQ(err_char, err.location().char_offset());
72}
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()) {
83 scoped_ptr<ParseNode> result = Parser::ParseExpression(tokens, &err);
84 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());
89 EXPECT_EQ(err_char, err.location().char_offset());
[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");
249 DoParserErrorTest("a = b.c.d", 1, 6); // Can't nest accessors (currently).
250 DoParserErrorTest("a.b = 5", 1, 1); // Can't assign to accessors (currently).
mdempskya2c7d0d2015-04-07 20:31:57251
252 // Error at the bad dot in the RHS, not the + operator (crbug.com/472038).
253 DoParserErrorTest("foo(a + b.c.d)", 1, 10);
[email protected]f38ddec2013-08-15 23:59:11254}
255
256TEST(Parser, Condition) {
257 DoParserPrintTest("if(1) { a = 2 }",
258 "BLOCK\n"
259 " CONDITION\n"
260 " LITERAL(1)\n"
261 " BLOCK\n"
262 " BINARY(=)\n"
263 " IDENTIFIER(a)\n"
264 " LITERAL(2)\n");
265
266 DoParserPrintTest("if(1) { a = 2 } else if (0) { a = 3 } else { a = 4 }",
267 "BLOCK\n"
268 " CONDITION\n"
269 " LITERAL(1)\n"
270 " BLOCK\n"
271 " BINARY(=)\n"
272 " IDENTIFIER(a)\n"
273 " LITERAL(2)\n"
274 " CONDITION\n"
275 " LITERAL(0)\n"
276 " BLOCK\n"
277 " BINARY(=)\n"
278 " IDENTIFIER(a)\n"
279 " LITERAL(3)\n"
280 " BLOCK\n"
281 " BINARY(=)\n"
282 " IDENTIFIER(a)\n"
283 " LITERAL(4)\n");
284}
285
286TEST(Parser, OnlyCallAndAssignInBody) {
287 DoParserErrorTest("[]", 1, 2);
288 DoParserErrorTest("3 + 4", 1, 5);
289 DoParserErrorTest("6 - 7", 1, 5);
290 DoParserErrorTest("if (1) { 5 } else { print(4) }", 1, 12);
291}
292
293TEST(Parser, NoAssignmentInCondition) {
294 DoParserErrorTest("if (a=2) {}", 1, 5);
[email protected]96ea63d2013-07-30 10:17:07295}
296
297TEST(Parser, CompleteFunction) {
298 const char* input =
299 "cc_test(\"foo\") {\n"
300 " sources = [\n"
301 " \"foo.cc\",\n"
302 " \"foo.h\"\n"
303 " ]\n"
304 " dependencies = [\n"
305 " \"base\"\n"
306 " ]\n"
307 "}\n";
308 const char* expected =
309 "BLOCK\n"
310 " FUNCTION(cc_test)\n"
311 " LIST\n"
312 " LITERAL(\"foo\")\n"
313 " BLOCK\n"
314 " BINARY(=)\n"
315 " IDENTIFIER(sources)\n"
316 " LIST\n"
317 " LITERAL(\"foo.cc\")\n"
318 " LITERAL(\"foo.h\")\n"
319 " BINARY(=)\n"
320 " IDENTIFIER(dependencies)\n"
321 " LIST\n"
322 " LITERAL(\"base\")\n";
323 DoParserPrintTest(input, expected);
324}
325
326TEST(Parser, FunctionWithConditional) {
327 const char* input =
328 "cc_test(\"foo\") {\n"
329 " sources = [\"foo.cc\"]\n"
330 " if (OS == \"mac\") {\n"
331 " sources += \"bar.cc\"\n"
332 " } else if (OS == \"win\") {\n"
333 " sources -= [\"asd.cc\", \"foo.cc\"]\n"
334 " } else {\n"
335 " dependencies += [\"bar.cc\"]\n"
336 " }\n"
337 "}\n";
338 const char* expected =
339 "BLOCK\n"
340 " FUNCTION(cc_test)\n"
341 " LIST\n"
342 " LITERAL(\"foo\")\n"
343 " BLOCK\n"
344 " BINARY(=)\n"
345 " IDENTIFIER(sources)\n"
346 " LIST\n"
347 " LITERAL(\"foo.cc\")\n"
348 " CONDITION\n"
349 " BINARY(==)\n"
350 " IDENTIFIER(OS)\n"
351 " LITERAL(\"mac\")\n"
352 " BLOCK\n"
353 " BINARY(+=)\n"
354 " IDENTIFIER(sources)\n"
355 " LITERAL(\"bar.cc\")\n"
356 " CONDITION\n"
357 " BINARY(==)\n"
358 " IDENTIFIER(OS)\n"
359 " LITERAL(\"win\")\n"
360 " BLOCK\n"
361 " BINARY(-=)\n"
362 " IDENTIFIER(sources)\n"
363 " LIST\n"
364 " LITERAL(\"asd.cc\")\n"
365 " LITERAL(\"foo.cc\")\n"
366 " BLOCK\n"
367 " BINARY(+=)\n"
368 " IDENTIFIER(dependencies)\n"
369 " LIST\n"
370 " LITERAL(\"bar.cc\")\n";
371 DoParserPrintTest(input, expected);
372}
373
[email protected]96ea63d2013-07-30 10:17:07374TEST(Parser, UnterminatedBlock) {
[email protected]f38ddec2013-08-15 23:59:11375 DoParserErrorTest("stuff() {", 1, 9);
[email protected]96ea63d2013-07-30 10:17:07376}
377
378TEST(Parser, BadlyTerminatedNumber) {
379 DoParserErrorTest("1234z", 1, 5);
380}
[email protected]02f80b72013-08-19 20:53:01381
382TEST(Parser, NewlinesInUnusualPlaces) {
383 DoParserPrintTest(
384 "if\n"
385 "(\n"
386 "a\n"
387 ")\n"
388 "{\n"
389 "}\n",
390 "BLOCK\n"
391 " CONDITION\n"
392 " IDENTIFIER(a)\n"
393 " BLOCK\n");
394}
395
396TEST(Parser, NewlinesInUnusualPlaces2) {
397 DoParserPrintTest(
398 "a\n=\n2\n",
399 "BLOCK\n"
400 " BINARY(=)\n"
401 " IDENTIFIER(a)\n"
402 " LITERAL(2)\n");
403 DoParserPrintTest(
404 "x =\ny if\n(1\n) {}",
405 "BLOCK\n"
406 " BINARY(=)\n"
407 " IDENTIFIER(x)\n"
408 " IDENTIFIER(y)\n"
409 " CONDITION\n"
410 " LITERAL(1)\n"
411 " BLOCK\n");
412 DoParserPrintTest(
413 "x = 3\n+2",
414 "BLOCK\n"
415 " BINARY(=)\n"
416 " IDENTIFIER(x)\n"
417 " BINARY(+)\n"
418 " LITERAL(3)\n"
419 " LITERAL(2)\n"
420 );
421}
422
423TEST(Parser, NewlineBeforeSubscript) {
424 const char* input = "a = b[1]";
425 const char* input_with_newline = "a = b\n[1]";
426 const char* expected =
427 "BLOCK\n"
428 " BINARY(=)\n"
429 " IDENTIFIER(a)\n"
430 " ACCESSOR\n"
431 " b\n"
432 " LITERAL(1)\n";
433 DoParserPrintTest(
434 input,
435 expected);
436 DoParserPrintTest(
437 input_with_newline,
438 expected);
439}
440
441TEST(Parser, SequenceOfExpressions) {
442 DoParserPrintTest(
443 "a = 1 b = 2",
444 "BLOCK\n"
445 " BINARY(=)\n"
446 " IDENTIFIER(a)\n"
447 " LITERAL(1)\n"
448 " BINARY(=)\n"
449 " IDENTIFIER(b)\n"
450 " LITERAL(2)\n");
451}
452
453TEST(Parser, BlockAfterFunction) {
454 const char* input = "func(\"stuff\") {\n}";
455 // TODO(scottmg): Do we really want these to mean different things?
456 const char* input_with_newline = "func(\"stuff\")\n{\n}";
457 const char* expected =
458 "BLOCK\n"
459 " FUNCTION(func)\n"
460 " LIST\n"
461 " LITERAL(\"stuff\")\n"
462 " BLOCK\n";
463 DoParserPrintTest(input, expected);
464 DoParserPrintTest(input_with_newline, expected);
465}
466
467TEST(Parser, LongExpression) {
468 const char* input = "a = b + c && d || e";
469 const char* expected =
470 "BLOCK\n"
471 " BINARY(=)\n"
472 " IDENTIFIER(a)\n"
473 " BINARY(||)\n"
474 " BINARY(&&)\n"
475 " BINARY(+)\n"
476 " IDENTIFIER(b)\n"
477 " IDENTIFIER(c)\n"
478 " IDENTIFIER(d)\n"
479 " IDENTIFIER(e)\n";
480 DoParserPrintTest(input, expected);
481}
[email protected]6ac871ea2013-08-19 21:04:50482
scottmgbe5d4512014-09-24 02:29:12483TEST(Parser, CommentsStandalone) {
484 const char* input =
485 "# Toplevel comment.\n"
486 "\n"
487 "executable(\"wee\") {}\n";
488 const char* expected =
489 "BLOCK\n"
scottmg2dd93e8b2014-09-26 04:07:05490 " BLOCK_COMMENT(# Toplevel comment.)\n"
scottmgbe5d4512014-09-24 02:29:12491 " FUNCTION(executable)\n"
492 " LIST\n"
493 " LITERAL(\"wee\")\n"
494 " BLOCK\n";
495 DoParserPrintTest(input, expected);
496}
497
498TEST(Parser, CommentsStandaloneEof) {
499 const char* input =
500 "executable(\"wee\") {}\n"
501 "# EOF comment.\n";
502 const char* expected =
503 "BLOCK\n"
504 " +AFTER_COMMENT(\"# EOF comment.\")\n"
505 " FUNCTION(executable)\n"
506 " LIST\n"
507 " LITERAL(\"wee\")\n"
508 " BLOCK\n";
509 DoParserPrintTest(input, expected);
510}
511
512TEST(Parser, CommentsLineAttached) {
513 const char* input =
514 "executable(\"wee\") {\n"
515 " # Some sources.\n"
516 " sources = [\n"
517 " \"stuff.cc\",\n"
518 " \"things.cc\",\n"
519 " # This file is special or something.\n"
520 " \"another.cc\",\n"
521 " ]\n"
522 "}\n";
523 const char* expected =
524 "BLOCK\n"
525 " FUNCTION(executable)\n"
526 " LIST\n"
527 " LITERAL(\"wee\")\n"
528 " BLOCK\n"
529 " BINARY(=)\n"
530 " +BEFORE_COMMENT(\"# Some sources.\")\n"
531 " IDENTIFIER(sources)\n"
532 " LIST\n"
533 " LITERAL(\"stuff.cc\")\n"
534 " LITERAL(\"things.cc\")\n"
535 " LITERAL(\"another.cc\")\n"
536 " +BEFORE_COMMENT(\"# This file is special or something.\")\n";
537 DoParserPrintTest(input, expected);
538}
539
540TEST(Parser, CommentsSuffix) {
541 const char* input =
542 "executable(\"wee\") { # This is some stuff.\n"
543 "sources = [ \"a.cc\" # And another comment here.\n"
544 "] }";
545 const char* expected =
546 "BLOCK\n"
547 " FUNCTION(executable)\n"
548 " LIST\n"
549 " LITERAL(\"wee\")\n"
scottmg571a81f2014-11-05 23:44:45550 " END())\n"
scottmgbe5d4512014-09-24 02:29:12551 " +SUFFIX_COMMENT(\"# This is some stuff.\")\n"
552 " BLOCK\n"
553 " BINARY(=)\n"
554 " IDENTIFIER(sources)\n"
555 " LIST\n"
556 " LITERAL(\"a.cc\")\n"
557 " +SUFFIX_COMMENT(\"# And another comment here.\")\n";
558 DoParserPrintTest(input, expected);
559}
560
561TEST(Parser, CommentsSuffixDifferentLine) {
562 const char* input =
563 "executable(\"wee\") {\n"
564 " sources = [ \"a\",\n"
565 " \"b\" ] # Comment\n"
566 "}\n";
567 const char* expected =
568 "BLOCK\n"
569 " FUNCTION(executable)\n"
570 " LIST\n"
571 " LITERAL(\"wee\")\n"
572 " BLOCK\n"
573 " BINARY(=)\n"
574 " IDENTIFIER(sources)\n"
575 " LIST\n"
576 " LITERAL(\"a\")\n"
577 " LITERAL(\"b\")\n"
scottmg571a81f2014-11-05 23:44:45578 " END(])\n"
scottmgbe5d4512014-09-24 02:29:12579 " +SUFFIX_COMMENT(\"# Comment\")\n";
580 DoParserPrintTest(input, expected);
581}
582
scottmg7b80f172014-09-24 03:35:13583TEST(Parser, CommentsSuffixMultiple) {
584 const char* input =
585 "executable(\"wee\") {\n"
586 " sources = [\n"
587 " \"a\", # This is a comment,\n"
588 " # and some more,\n" // Note that this is aligned with above.
589 " # then the end.\n"
590 " ]\n"
591 "}\n";
592 const char* expected =
593 "BLOCK\n"
594 " FUNCTION(executable)\n"
595 " LIST\n"
596 " LITERAL(\"wee\")\n"
597 " BLOCK\n"
598 " BINARY(=)\n"
599 " IDENTIFIER(sources)\n"
600 " LIST\n"
601 " LITERAL(\"a\")\n"
602 " +SUFFIX_COMMENT(\"# This is a comment,\")\n"
603 " +SUFFIX_COMMENT(\"# and some more,\")\n"
604 " +SUFFIX_COMMENT(\"# then the end.\")\n";
605 DoParserPrintTest(input, expected);
606}
607
scottmg2dd93e8b2014-09-26 04:07:05608TEST(Parser, CommentsConnectedInList) {
609 const char* input =
610 "defines = [\n"
611 "\n"
612 " # Connected comment.\n"
613 " \"WEE\",\n"
614 " \"BLORPY\",\n"
615 "]\n";
616 const char* expected =
617 "BLOCK\n"
618 " BINARY(=)\n"
619 " IDENTIFIER(defines)\n"
620 " LIST\n"
621 " LITERAL(\"WEE\")\n"
622 " +BEFORE_COMMENT(\"# Connected comment.\")\n"
623 " LITERAL(\"BLORPY\")\n";
624 DoParserPrintTest(input, expected);
625}
626
scottmgf7e13e522014-09-29 19:21:09627TEST(Parser, CommentsAtEndOfBlock) {
628 const char* input =
629 "if (is_win) {\n"
630 " sources = [\"a.cc\"]\n"
631 " # Some comment at end.\n"
632 "}\n";
633 const char* expected =
634 "BLOCK\n"
635 " CONDITION\n"
636 " IDENTIFIER(is_win)\n"
637 " BLOCK\n"
638 " BINARY(=)\n"
639 " IDENTIFIER(sources)\n"
640 " LIST\n"
641 " LITERAL(\"a.cc\")\n"
642 " END(})\n"
643 " +BEFORE_COMMENT(\"# Some comment at end.\")\n";
644 DoParserPrintTest(input, expected);
645}
646
647// TODO(scottmg): I could be convinced this is incorrect. It's not clear to me
648// which thing this comment is intended to be attached to.
649TEST(Parser, CommentsEndOfBlockSingleLine) {
650 const char* input =
651 "defines = [ # EOL defines.\n"
652 "]\n";
653 const char* expected =
654 "BLOCK\n"
655 " BINARY(=)\n"
656 " IDENTIFIER(defines)\n"
657 " +SUFFIX_COMMENT(\"# EOL defines.\")\n"
658 " LIST\n";
659 DoParserPrintTest(input, expected);
660}
661
[email protected]6ac871ea2013-08-19 21:04:50662TEST(Parser, HangingIf) {
663 DoParserErrorTest("if", 1, 1);
664}
[email protected]8f4f9a842013-09-11 20:35:03665
666TEST(Parser, NegatingList) {
667 DoParserErrorTest("executable(\"wee\") { sources =- [ \"foo.cc\" ] }", 1, 30);
668}
scottmg3d5823f2015-03-10 21:28:41669
670TEST(Parser, ConditionNoBracesIf) {
671 DoParserErrorTest(
672 "if (true)\n"
673 " foreach(foo, []) {}\n"
674 "else {\n"
675 " foreach(bar, []) {}\n"
676 "}\n",
677 2, 3);
678}
679
680TEST(Parser, ConditionNoBracesElse) {
681 DoParserErrorTest(
682 "if (true) {\n"
683 " foreach(foo, []) {}\n"
684 "} else\n"
685 " foreach(bar, []) {}\n",
686 4, 3);
687}
688
689TEST(Parser, ConditionNoBracesElseIf) {
690 DoParserErrorTest(
691 "if (true) {\n"
692 " foreach(foo, []) {}\n"
693 "} else if (true)\n"
694 " foreach(bar, []) {}\n",
695 4, 3);
696}
Brett Wilson989adc842015-03-16 17:52:52697
698// Disallow standalone {} for introducing new scopes. These are ambiguous with
699// target declarations (e.g. is:
700// foo("bar") {}
701// a function with an associated block, or a standalone function with a
702// freestanding block.
703TEST(Parser, StandaloneBlock) {
704 DoParserErrorTest(
705 "if (true) {\n"
706 "}\n"
707 "{\n"
708 " assert(false)\n"
709 "}\n",
710 3, 1);
711}