blob: 226143ac8f6a46d9d128dd7ab4ce41a7a5fc07a6 [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");
184}
[email protected]96ea63d2013-07-30 10:17:07185
[email protected]f38ddec2013-08-15 23:59:11186TEST(Parser, List) {
187 DoExpressionPrintTest("[]", "LIST\n");
188 DoExpressionPrintTest("[1,asd,]",
189 "LIST\n"
190 " LITERAL(1)\n"
191 " IDENTIFIER(asd)\n");
192 DoExpressionPrintTest("[1, 2+3 - foo]",
193 "LIST\n"
194 " LITERAL(1)\n"
195 " BINARY(-)\n"
196 " BINARY(+)\n"
197 " LITERAL(2)\n"
198 " LITERAL(3)\n"
199 " IDENTIFIER(foo)\n");
200 DoExpressionPrintTest("[1,\n2,\n 3,\n 4]",
201 "LIST\n"
202 " LITERAL(1)\n"
203 " LITERAL(2)\n"
204 " LITERAL(3)\n"
205 " LITERAL(4)\n");
[email protected]96ea63d2013-07-30 10:17:07206
[email protected]f38ddec2013-08-15 23:59:11207 DoExpressionErrorTest("[a, 2+,]", 1, 6);
208 DoExpressionErrorTest("[,]", 1, 2);
209 DoExpressionErrorTest("[a,,]", 1, 4);
210}
211
212TEST(Parser, Assignment) {
213 DoParserPrintTest("a=2",
214 "BLOCK\n"
215 " BINARY(=)\n"
216 " IDENTIFIER(a)\n"
217 " LITERAL(2)\n");
218}
219
220TEST(Parser, Accessor) {
[email protected]51d01722014-03-26 16:57:07221 // Accessor indexing.
222 DoParserPrintTest("a=b[c+2]",
[email protected]f38ddec2013-08-15 23:59:11223 "BLOCK\n"
224 " BINARY(=)\n"
225 " IDENTIFIER(a)\n"
226 " ACCESSOR\n"
227 " b\n" // AccessorNode is a bit weird in that it holds
228 // a Token, not a ParseNode for the base.
[email protected]51d01722014-03-26 16:57:07229 " BINARY(+)\n"
230 " IDENTIFIER(c)\n"
231 " LITERAL(2)\n");
[email protected]f38ddec2013-08-15 23:59:11232 DoParserErrorTest("a = b[1][0]", 1, 5);
[email protected]51d01722014-03-26 16:57:07233
234 // Member accessors.
235 DoParserPrintTest("a=b.c+2",
236 "BLOCK\n"
237 " BINARY(=)\n"
238 " IDENTIFIER(a)\n"
239 " BINARY(+)\n"
240 " ACCESSOR\n"
241 " b\n"
242 " IDENTIFIER(c)\n"
243 " LITERAL(2)\n");
244 DoParserErrorTest("a = b.c.d", 1, 6); // Can't nest accessors (currently).
245 DoParserErrorTest("a.b = 5", 1, 1); // Can't assign to accessors (currently).
[email protected]f38ddec2013-08-15 23:59:11246}
247
248TEST(Parser, Condition) {
249 DoParserPrintTest("if(1) { a = 2 }",
250 "BLOCK\n"
251 " CONDITION\n"
252 " LITERAL(1)\n"
253 " BLOCK\n"
254 " BINARY(=)\n"
255 " IDENTIFIER(a)\n"
256 " LITERAL(2)\n");
257
258 DoParserPrintTest("if(1) { a = 2 } else if (0) { a = 3 } else { a = 4 }",
259 "BLOCK\n"
260 " CONDITION\n"
261 " LITERAL(1)\n"
262 " BLOCK\n"
263 " BINARY(=)\n"
264 " IDENTIFIER(a)\n"
265 " LITERAL(2)\n"
266 " CONDITION\n"
267 " LITERAL(0)\n"
268 " BLOCK\n"
269 " BINARY(=)\n"
270 " IDENTIFIER(a)\n"
271 " LITERAL(3)\n"
272 " BLOCK\n"
273 " BINARY(=)\n"
274 " IDENTIFIER(a)\n"
275 " LITERAL(4)\n");
276}
277
278TEST(Parser, OnlyCallAndAssignInBody) {
279 DoParserErrorTest("[]", 1, 2);
280 DoParserErrorTest("3 + 4", 1, 5);
281 DoParserErrorTest("6 - 7", 1, 5);
282 DoParserErrorTest("if (1) { 5 } else { print(4) }", 1, 12);
283}
284
285TEST(Parser, NoAssignmentInCondition) {
286 DoParserErrorTest("if (a=2) {}", 1, 5);
[email protected]96ea63d2013-07-30 10:17:07287}
288
289TEST(Parser, CompleteFunction) {
290 const char* input =
291 "cc_test(\"foo\") {\n"
292 " sources = [\n"
293 " \"foo.cc\",\n"
294 " \"foo.h\"\n"
295 " ]\n"
296 " dependencies = [\n"
297 " \"base\"\n"
298 " ]\n"
299 "}\n";
300 const char* expected =
301 "BLOCK\n"
302 " FUNCTION(cc_test)\n"
303 " LIST\n"
304 " LITERAL(\"foo\")\n"
305 " BLOCK\n"
306 " BINARY(=)\n"
307 " IDENTIFIER(sources)\n"
308 " LIST\n"
309 " LITERAL(\"foo.cc\")\n"
310 " LITERAL(\"foo.h\")\n"
311 " BINARY(=)\n"
312 " IDENTIFIER(dependencies)\n"
313 " LIST\n"
314 " LITERAL(\"base\")\n";
315 DoParserPrintTest(input, expected);
316}
317
318TEST(Parser, FunctionWithConditional) {
319 const char* input =
320 "cc_test(\"foo\") {\n"
321 " sources = [\"foo.cc\"]\n"
322 " if (OS == \"mac\") {\n"
323 " sources += \"bar.cc\"\n"
324 " } else if (OS == \"win\") {\n"
325 " sources -= [\"asd.cc\", \"foo.cc\"]\n"
326 " } else {\n"
327 " dependencies += [\"bar.cc\"]\n"
328 " }\n"
329 "}\n";
330 const char* expected =
331 "BLOCK\n"
332 " FUNCTION(cc_test)\n"
333 " LIST\n"
334 " LITERAL(\"foo\")\n"
335 " BLOCK\n"
336 " BINARY(=)\n"
337 " IDENTIFIER(sources)\n"
338 " LIST\n"
339 " LITERAL(\"foo.cc\")\n"
340 " CONDITION\n"
341 " BINARY(==)\n"
342 " IDENTIFIER(OS)\n"
343 " LITERAL(\"mac\")\n"
344 " BLOCK\n"
345 " BINARY(+=)\n"
346 " IDENTIFIER(sources)\n"
347 " LITERAL(\"bar.cc\")\n"
348 " CONDITION\n"
349 " BINARY(==)\n"
350 " IDENTIFIER(OS)\n"
351 " LITERAL(\"win\")\n"
352 " BLOCK\n"
353 " BINARY(-=)\n"
354 " IDENTIFIER(sources)\n"
355 " LIST\n"
356 " LITERAL(\"asd.cc\")\n"
357 " LITERAL(\"foo.cc\")\n"
358 " BLOCK\n"
359 " BINARY(+=)\n"
360 " IDENTIFIER(dependencies)\n"
361 " LIST\n"
362 " LITERAL(\"bar.cc\")\n";
363 DoParserPrintTest(input, expected);
364}
365
366TEST(Parser, NestedBlocks) {
[email protected]f38ddec2013-08-15 23:59:11367 const char* input = "{cc_test(\"foo\") {{foo=1}\n{}}}";
[email protected]96ea63d2013-07-30 10:17:07368 const char* expected =
369 "BLOCK\n"
370 " BLOCK\n"
371 " FUNCTION(cc_test)\n"
372 " LIST\n"
373 " LITERAL(\"foo\")\n"
374 " BLOCK\n"
375 " BLOCK\n"
376 " BINARY(=)\n"
377 " IDENTIFIER(foo)\n"
378 " LITERAL(1)\n"
379 " BLOCK\n";
380 DoParserPrintTest(input, expected);
[email protected]02f80b72013-08-19 20:53:01381 const char* input_with_newline = "{cc_test(\"foo\") {{foo=1}\n{}}}";
382 DoParserPrintTest(input_with_newline, expected);
[email protected]96ea63d2013-07-30 10:17:07383}
384
385TEST(Parser, UnterminatedBlock) {
[email protected]f38ddec2013-08-15 23:59:11386 DoParserErrorTest("stuff() {", 1, 9);
[email protected]96ea63d2013-07-30 10:17:07387}
388
389TEST(Parser, BadlyTerminatedNumber) {
390 DoParserErrorTest("1234z", 1, 5);
391}
[email protected]02f80b72013-08-19 20:53:01392
393TEST(Parser, NewlinesInUnusualPlaces) {
394 DoParserPrintTest(
395 "if\n"
396 "(\n"
397 "a\n"
398 ")\n"
399 "{\n"
400 "}\n",
401 "BLOCK\n"
402 " CONDITION\n"
403 " IDENTIFIER(a)\n"
404 " BLOCK\n");
405}
406
407TEST(Parser, NewlinesInUnusualPlaces2) {
408 DoParserPrintTest(
409 "a\n=\n2\n",
410 "BLOCK\n"
411 " BINARY(=)\n"
412 " IDENTIFIER(a)\n"
413 " LITERAL(2)\n");
414 DoParserPrintTest(
415 "x =\ny if\n(1\n) {}",
416 "BLOCK\n"
417 " BINARY(=)\n"
418 " IDENTIFIER(x)\n"
419 " IDENTIFIER(y)\n"
420 " CONDITION\n"
421 " LITERAL(1)\n"
422 " BLOCK\n");
423 DoParserPrintTest(
424 "x = 3\n+2",
425 "BLOCK\n"
426 " BINARY(=)\n"
427 " IDENTIFIER(x)\n"
428 " BINARY(+)\n"
429 " LITERAL(3)\n"
430 " LITERAL(2)\n"
431 );
432}
433
434TEST(Parser, NewlineBeforeSubscript) {
435 const char* input = "a = b[1]";
436 const char* input_with_newline = "a = b\n[1]";
437 const char* expected =
438 "BLOCK\n"
439 " BINARY(=)\n"
440 " IDENTIFIER(a)\n"
441 " ACCESSOR\n"
442 " b\n"
443 " LITERAL(1)\n";
444 DoParserPrintTest(
445 input,
446 expected);
447 DoParserPrintTest(
448 input_with_newline,
449 expected);
450}
451
452TEST(Parser, SequenceOfExpressions) {
453 DoParserPrintTest(
454 "a = 1 b = 2",
455 "BLOCK\n"
456 " BINARY(=)\n"
457 " IDENTIFIER(a)\n"
458 " LITERAL(1)\n"
459 " BINARY(=)\n"
460 " IDENTIFIER(b)\n"
461 " LITERAL(2)\n");
462}
463
464TEST(Parser, BlockAfterFunction) {
465 const char* input = "func(\"stuff\") {\n}";
466 // TODO(scottmg): Do we really want these to mean different things?
467 const char* input_with_newline = "func(\"stuff\")\n{\n}";
468 const char* expected =
469 "BLOCK\n"
470 " FUNCTION(func)\n"
471 " LIST\n"
472 " LITERAL(\"stuff\")\n"
473 " BLOCK\n";
474 DoParserPrintTest(input, expected);
475 DoParserPrintTest(input_with_newline, expected);
476}
477
478TEST(Parser, LongExpression) {
479 const char* input = "a = b + c && d || e";
480 const char* expected =
481 "BLOCK\n"
482 " BINARY(=)\n"
483 " IDENTIFIER(a)\n"
484 " BINARY(||)\n"
485 " BINARY(&&)\n"
486 " BINARY(+)\n"
487 " IDENTIFIER(b)\n"
488 " IDENTIFIER(c)\n"
489 " IDENTIFIER(d)\n"
490 " IDENTIFIER(e)\n";
491 DoParserPrintTest(input, expected);
492}
[email protected]6ac871ea2013-08-19 21:04:50493
scottmgbe5d4512014-09-24 02:29:12494TEST(Parser, CommentsStandalone) {
495 const char* input =
496 "# Toplevel comment.\n"
497 "\n"
498 "executable(\"wee\") {}\n";
499 const char* expected =
500 "BLOCK\n"
scottmg2dd93e8b2014-09-26 04:07:05501 " BLOCK_COMMENT(# Toplevel comment.)\n"
scottmgbe5d4512014-09-24 02:29:12502 " FUNCTION(executable)\n"
503 " LIST\n"
504 " LITERAL(\"wee\")\n"
505 " BLOCK\n";
506 DoParserPrintTest(input, expected);
507}
508
509TEST(Parser, CommentsStandaloneEof) {
510 const char* input =
511 "executable(\"wee\") {}\n"
512 "# EOF comment.\n";
513 const char* expected =
514 "BLOCK\n"
515 " +AFTER_COMMENT(\"# EOF comment.\")\n"
516 " FUNCTION(executable)\n"
517 " LIST\n"
518 " LITERAL(\"wee\")\n"
519 " BLOCK\n";
520 DoParserPrintTest(input, expected);
521}
522
523TEST(Parser, CommentsLineAttached) {
524 const char* input =
525 "executable(\"wee\") {\n"
526 " # Some sources.\n"
527 " sources = [\n"
528 " \"stuff.cc\",\n"
529 " \"things.cc\",\n"
530 " # This file is special or something.\n"
531 " \"another.cc\",\n"
532 " ]\n"
533 "}\n";
534 const char* expected =
535 "BLOCK\n"
536 " FUNCTION(executable)\n"
537 " LIST\n"
538 " LITERAL(\"wee\")\n"
539 " BLOCK\n"
540 " BINARY(=)\n"
541 " +BEFORE_COMMENT(\"# Some sources.\")\n"
542 " IDENTIFIER(sources)\n"
543 " LIST\n"
544 " LITERAL(\"stuff.cc\")\n"
545 " LITERAL(\"things.cc\")\n"
546 " LITERAL(\"another.cc\")\n"
547 " +BEFORE_COMMENT(\"# This file is special or something.\")\n";
548 DoParserPrintTest(input, expected);
549}
550
551TEST(Parser, CommentsSuffix) {
552 const char* input =
553 "executable(\"wee\") { # This is some stuff.\n"
554 "sources = [ \"a.cc\" # And another comment here.\n"
555 "] }";
556 const char* expected =
557 "BLOCK\n"
558 " FUNCTION(executable)\n"
559 " LIST\n"
560 " LITERAL(\"wee\")\n"
561 " +SUFFIX_COMMENT(\"# This is some stuff.\")\n"
562 " BLOCK\n"
563 " BINARY(=)\n"
564 " IDENTIFIER(sources)\n"
565 " LIST\n"
566 " LITERAL(\"a.cc\")\n"
567 " +SUFFIX_COMMENT(\"# And another comment here.\")\n";
568 DoParserPrintTest(input, expected);
569}
570
571TEST(Parser, CommentsSuffixDifferentLine) {
572 const char* input =
573 "executable(\"wee\") {\n"
574 " sources = [ \"a\",\n"
575 " \"b\" ] # Comment\n"
576 "}\n";
577 const char* expected =
578 "BLOCK\n"
579 " FUNCTION(executable)\n"
580 " LIST\n"
581 " LITERAL(\"wee\")\n"
582 " BLOCK\n"
583 " BINARY(=)\n"
584 " IDENTIFIER(sources)\n"
585 " LIST\n"
586 " LITERAL(\"a\")\n"
587 " LITERAL(\"b\")\n"
588 " +SUFFIX_COMMENT(\"# Comment\")\n";
589 DoParserPrintTest(input, expected);
590}
591
scottmg7b80f172014-09-24 03:35:13592TEST(Parser, CommentsSuffixMultiple) {
593 const char* input =
594 "executable(\"wee\") {\n"
595 " sources = [\n"
596 " \"a\", # This is a comment,\n"
597 " # and some more,\n" // Note that this is aligned with above.
598 " # then the end.\n"
599 " ]\n"
600 "}\n";
601 const char* expected =
602 "BLOCK\n"
603 " FUNCTION(executable)\n"
604 " LIST\n"
605 " LITERAL(\"wee\")\n"
606 " BLOCK\n"
607 " BINARY(=)\n"
608 " IDENTIFIER(sources)\n"
609 " LIST\n"
610 " LITERAL(\"a\")\n"
611 " +SUFFIX_COMMENT(\"# This is a comment,\")\n"
612 " +SUFFIX_COMMENT(\"# and some more,\")\n"
613 " +SUFFIX_COMMENT(\"# then the end.\")\n";
614 DoParserPrintTest(input, expected);
615}
616
scottmg2dd93e8b2014-09-26 04:07:05617TEST(Parser, CommentsConnectedInList) {
618 const char* input =
619 "defines = [\n"
620 "\n"
621 " # Connected comment.\n"
622 " \"WEE\",\n"
623 " \"BLORPY\",\n"
624 "]\n";
625 const char* expected =
626 "BLOCK\n"
627 " BINARY(=)\n"
628 " IDENTIFIER(defines)\n"
629 " LIST\n"
630 " LITERAL(\"WEE\")\n"
631 " +BEFORE_COMMENT(\"# Connected comment.\")\n"
632 " LITERAL(\"BLORPY\")\n";
633 DoParserPrintTest(input, expected);
634}
635
[email protected]6ac871ea2013-08-19 21:04:50636TEST(Parser, HangingIf) {
637 DoParserErrorTest("if", 1, 1);
638}
[email protected]8f4f9a842013-09-11 20:35:03639
640TEST(Parser, NegatingList) {
641 DoParserErrorTest("executable(\"wee\") { sources =- [ \"foo.cc\" ] }", 1, 30);
642}