blob: cfc9641fff4b4009df9de4f2b53cab1d7170133c [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Ulf Adams89f012d2015-02-26 13:39:28 +00002//
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.
14package com.google.devtools.build.lib.syntax;
15
16import static com.google.common.truth.Truth.assertThat;
17import static com.google.common.truth.Truth.assertWithMessage;
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000018import static org.junit.Assert.fail;
Ulf Adams89f012d2015-02-26 13:39:28 +000019
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +000020import com.google.common.collect.ImmutableList;
nharmata6dbfafe2019-02-05 08:55:07 -080021import com.google.common.collect.Sets;
John Field1ea7fc32015-12-22 19:37:19 +000022import com.google.devtools.build.lib.cmdline.Label;
Ulf Adams89f012d2015-02-26 13:39:28 +000023import com.google.devtools.build.lib.events.Location;
fzaiser2a46d742017-10-02 19:59:28 +020024import com.google.devtools.build.lib.events.Location.LineAndColumn;
Ulf Adams89f012d2015-02-26 13:39:28 +000025import com.google.devtools.build.lib.syntax.DictionaryLiteral.DictionaryEntryLiteral;
fzaiseraa8540d2017-09-26 06:01:30 -040026import com.google.devtools.build.lib.syntax.Parser.ParsingLevel;
laurentlbc6c9b8e2019-04-15 11:26:26 -070027import com.google.devtools.build.lib.syntax.SkylarkImport.SkylarkImportSyntaxException;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000028import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
Vladimir Moskva8d610c62016-09-15 14:36:41 +000029import java.util.LinkedList;
30import java.util.List;
nharmata6dbfafe2019-02-05 08:55:07 -080031import java.util.Set;
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000032import org.junit.Test;
33import org.junit.runner.RunWith;
34import org.junit.runners.JUnit4;
35
Ulf Adams89f012d2015-02-26 13:39:28 +000036/**
37 * Tests of parser behaviour.
Ulf Adams89f012d2015-02-26 13:39:28 +000038 */
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000039@RunWith(JUnit4.class)
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000040public class ParserTest extends EvaluationTestCase {
41
Laurent Le Brun8e965b82016-08-03 11:50:24 +000042 private BuildFileAST parseFileWithComments(String... input) {
laurentlbab062912019-04-12 07:00:20 -070043 return BuildFileAST.parseString(getEventHandler(), input);
Francois-Rene Rideau5a94e592015-09-04 19:13:47 +000044 }
45
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000046 /** Parses build code (not Skylark) */
47 @Override
48 protected List<Statement> parseFile(String... input) {
Laurent Le Brun8e965b82016-08-03 11:50:24 +000049 return parseFileWithComments(input).getStatements();
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000050 }
51
nharmata6dbfafe2019-02-05 08:55:07 -080052 private BuildFileAST parseFileForSkylarkAsAST(String... input) {
53 BuildFileAST ast = BuildFileAST.parseString(getEventHandler(), input);
54 return ast.validate(env, getEventHandler());
55 }
56
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000057 /** Parses Skylark code */
58 private List<Statement> parseFileForSkylark(String... input) {
nharmata6dbfafe2019-02-05 08:55:07 -080059 return parseFileForSkylarkAsAST(input).getStatements();
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000060 }
Ulf Adams89f012d2015-02-26 13:39:28 +000061
62 private static String getText(String text, ASTNode node) {
63 return text.substring(node.getLocation().getStartOffset(),
64 node.getLocation().getEndOffset());
65 }
66
brandjonf2ed8582017-06-27 15:05:35 +020067 private void assertLocation(int start, int end, Location location)
68 throws Exception {
69 int actualStart = location.getStartOffset();
70 int actualEnd = location.getEndOffset();
71
72 if (actualStart != start || actualEnd != end) {
73 fail("Expected location = [" + start + ", " + end + "), found ["
74 + actualStart + ", " + actualEnd + ")");
75 }
76 }
77
Ulf Adams89f012d2015-02-26 13:39:28 +000078 // helper func for testListLiterals:
79 private static int getIntElem(DictionaryEntryLiteral entry, boolean key) {
80 return ((IntegerLiteral) (key ? entry.getKey() : entry.getValue())).getValue();
81 }
82
83 // helper func for testListLiterals:
brandjonaadf6602018-01-17 10:40:38 -080084 private static int getIntElem(ListLiteral list, int index) {
85 return ((IntegerLiteral) list.getElements().get(index)).getValue();
Ulf Adams89f012d2015-02-26 13:39:28 +000086 }
87
88 // helper func for testListLiterals:
brandjonaadf6602018-01-17 10:40:38 -080089 private static DictionaryEntryLiteral getElem(DictionaryLiteral list, int index) {
90 return list.getEntries().get(index);
Ulf Adams89f012d2015-02-26 13:39:28 +000091 }
92
93 // helper func for testListLiterals:
94 private static Expression getElem(ListLiteral list, int index) {
95 return list.getElements().get(index);
96 }
97
98 // helper func for testing arguments:
99 private static Expression getArg(FuncallExpression f, int index) {
100 return f.getArguments().get(index).getValue();
101 }
102
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000103 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000104 public void testPrecedence1() throws Exception {
105 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000106 (BinaryOperatorExpression) parseExpression("'%sx' % 'foo' + 'bar'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000107
Googler6748ccb2019-07-01 10:22:59 -0700108 assertThat(e.getOperator()).isEqualTo(TokenKind.PLUS);
Ulf Adams89f012d2015-02-26 13:39:28 +0000109 }
110
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000111 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000112 public void testPrecedence2() throws Exception {
113 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000114 (BinaryOperatorExpression) parseExpression("('%sx' % 'foo') + 'bar'");
Googler6748ccb2019-07-01 10:22:59 -0700115 assertThat(e.getOperator()).isEqualTo(TokenKind.PLUS);
Ulf Adams89f012d2015-02-26 13:39:28 +0000116 }
117
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000118 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000119 public void testPrecedence3() throws Exception {
120 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000121 (BinaryOperatorExpression) parseExpression("'%sx' % ('foo' + 'bar')");
Googler6748ccb2019-07-01 10:22:59 -0700122 assertThat(e.getOperator()).isEqualTo(TokenKind.PERCENT);
Ulf Adams89f012d2015-02-26 13:39:28 +0000123 }
124
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000125 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000126 public void testPrecedence4() throws Exception {
127 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000128 (BinaryOperatorExpression) parseExpression("1 + - (2 - 3)");
Googler6748ccb2019-07-01 10:22:59 -0700129 assertThat(e.getOperator()).isEqualTo(TokenKind.PLUS);
Ulf Adams89f012d2015-02-26 13:39:28 +0000130 }
131
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000132 @Test
Laurent Le Brun7bda87e2015-08-24 15:13:53 +0000133 public void testPrecedence5() throws Exception {
134 BinaryOperatorExpression e =
135 (BinaryOperatorExpression) parseExpression("2 * x | y + 1");
Googler6748ccb2019-07-01 10:22:59 -0700136 assertThat(e.getOperator()).isEqualTo(TokenKind.PIPE);
Laurent Le Brun7bda87e2015-08-24 15:13:53 +0000137 }
138
139 @Test
laurentlb1fcea382017-06-19 16:02:42 +0200140 public void testNonAssociativeOperators() throws Exception {
141 setFailFast(false);
142
143 parseExpression("0 < 2 < 4");
144 assertContainsError("Operator '<' is not associative with operator '<'");
145 clearEvents();
146
147 parseExpression("0 == 2 < 4");
148 assertContainsError("Operator '==' is not associative with operator '<'");
149 clearEvents();
150
151 parseExpression("1 in [1, 2] == True");
152 assertContainsError("Operator 'in' is not associative with operator '=='");
153 clearEvents();
154
155 parseExpression("1 >= 2 <= 3");
156 assertContainsError("Operator '>=' is not associative with operator '<='");
157 clearEvents();
158 }
159
160 @Test
161 public void testNonAssociativeOperatorsWithParens() throws Exception {
162 parseExpression("(0 < 2) < 4");
163 parseExpression("(0 == 2) < 4");
164 parseExpression("(1 in [1, 2]) == True");
165 parseExpression("1 >= (2 <= 3)");
166 }
167
168 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000169 public void testUnaryMinusExpr() throws Exception {
brandjonf2ed8582017-06-27 15:05:35 +0200170 UnaryOperatorExpression e = (UnaryOperatorExpression) parseExpression("-5");
171 UnaryOperatorExpression e2 = (UnaryOperatorExpression) parseExpression("- 5");
Ulf Adams89f012d2015-02-26 13:39:28 +0000172
Googler6748ccb2019-07-01 10:22:59 -0700173 IntegerLiteral i = (IntegerLiteral) e.getX();
brandjonf2ed8582017-06-27 15:05:35 +0200174 assertThat(i.getValue()).isEqualTo(5);
Googler6748ccb2019-07-01 10:22:59 -0700175 IntegerLiteral i2 = (IntegerLiteral) e2.getX();
brandjonf2ed8582017-06-27 15:05:35 +0200176 assertThat(i2.getValue()).isEqualTo(5);
177 assertLocation(0, 2, e.getLocation());
178 assertLocation(0, 3, e2.getLocation());
Ulf Adams89f012d2015-02-26 13:39:28 +0000179 }
180
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000181 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000182 public void testFuncallExpr() throws Exception {
fzaisere0f13332017-08-14 12:00:51 +0200183 FuncallExpression e = (FuncallExpression) parseExpression("foo[0](1, 2, bar=wiz)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000184
fzaisere0f13332017-08-14 12:00:51 +0200185 IndexExpression function = (IndexExpression) e.getFunction();
186 Identifier functionList = (Identifier) function.getObject();
187 assertThat(functionList.getName()).isEqualTo("foo");
188 IntegerLiteral listIndex = (IntegerLiteral) function.getKey();
189 assertThat(listIndex.getValue()).isEqualTo(0);
Ulf Adams89f012d2015-02-26 13:39:28 +0000190
191 assertThat(e.getArguments()).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200192 assertThat(e.getNumPositionalArguments()).isEqualTo(2);
Ulf Adams89f012d2015-02-26 13:39:28 +0000193
194 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
lberkiaea56b32017-05-30 12:35:33 +0200195 assertThat((int) arg0.getValue()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000196
197 IntegerLiteral arg1 = (IntegerLiteral) e.getArguments().get(1).getValue();
lberkiaea56b32017-05-30 12:35:33 +0200198 assertThat((int) arg1.getValue()).isEqualTo(2);
Ulf Adams89f012d2015-02-26 13:39:28 +0000199
200 Argument.Passed arg2 = e.getArguments().get(2);
lberkiaea56b32017-05-30 12:35:33 +0200201 assertThat(arg2.getName()).isEqualTo("bar");
Florian Weikert6f864c32015-07-23 11:26:39 +0000202 Identifier arg2val = (Identifier) arg2.getValue();
lberkiaea56b32017-05-30 12:35:33 +0200203 assertThat(arg2val.getName()).isEqualTo("wiz");
Ulf Adams89f012d2015-02-26 13:39:28 +0000204 }
205
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000206 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000207 public void testMethCallExpr() throws Exception {
208 FuncallExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000209 (FuncallExpression) parseExpression("foo.foo(1, 2, bar=wiz)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000210
fzaiser8c27a892017-08-11 17:26:44 +0200211 DotExpression dotExpression = (DotExpression) e.getFunction();
212 assertThat(dotExpression.getField().getName()).isEqualTo("foo");
Ulf Adams89f012d2015-02-26 13:39:28 +0000213
214 assertThat(e.getArguments()).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200215 assertThat(e.getNumPositionalArguments()).isEqualTo(2);
Ulf Adams89f012d2015-02-26 13:39:28 +0000216
217 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
lberkiaea56b32017-05-30 12:35:33 +0200218 assertThat((int) arg0.getValue()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000219
220 IntegerLiteral arg1 = (IntegerLiteral) e.getArguments().get(1).getValue();
lberkiaea56b32017-05-30 12:35:33 +0200221 assertThat((int) arg1.getValue()).isEqualTo(2);
Ulf Adams89f012d2015-02-26 13:39:28 +0000222
223 Argument.Passed arg2 = e.getArguments().get(2);
lberkiaea56b32017-05-30 12:35:33 +0200224 assertThat(arg2.getName()).isEqualTo("bar");
Florian Weikert6f864c32015-07-23 11:26:39 +0000225 Identifier arg2val = (Identifier) arg2.getValue();
lberkiaea56b32017-05-30 12:35:33 +0200226 assertThat(arg2val.getName()).isEqualTo("wiz");
Ulf Adams89f012d2015-02-26 13:39:28 +0000227 }
228
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000229 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000230 public void testChainedMethCallExpr() throws Exception {
231 FuncallExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000232 (FuncallExpression) parseExpression("foo.replace().split(1)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000233
fzaiser8c27a892017-08-11 17:26:44 +0200234 DotExpression dotExpr = (DotExpression) e.getFunction();
235 assertThat(dotExpr.getField().getName()).isEqualTo("split");
Ulf Adams89f012d2015-02-26 13:39:28 +0000236
237 assertThat(e.getArguments()).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200238 assertThat(e.getNumPositionalArguments()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000239
240 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
lberkiaea56b32017-05-30 12:35:33 +0200241 assertThat((int) arg0.getValue()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000242 }
243
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000244 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000245 public void testPropRefExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000246 DotExpression e = (DotExpression) parseExpression("foo.foo");
Ulf Adams89f012d2015-02-26 13:39:28 +0000247
Florian Weikert6f864c32015-07-23 11:26:39 +0000248 Identifier ident = e.getField();
lberkiaea56b32017-05-30 12:35:33 +0200249 assertThat(ident.getName()).isEqualTo("foo");
Ulf Adams89f012d2015-02-26 13:39:28 +0000250 }
251
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000252 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000253 public void testStringMethExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000254 FuncallExpression e = (FuncallExpression) parseExpression("'foo'.foo()");
Ulf Adams89f012d2015-02-26 13:39:28 +0000255
fzaiser8c27a892017-08-11 17:26:44 +0200256 DotExpression dotExpression = (DotExpression) e.getFunction();
257 assertThat(dotExpression.getField().getName()).isEqualTo("foo");
Ulf Adams89f012d2015-02-26 13:39:28 +0000258
259 assertThat(e.getArguments()).isEmpty();
260 }
261
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000262 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000263 public void testStringLiteralOptimizationValue() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000264 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
lberkiaea56b32017-05-30 12:35:33 +0200265 assertThat(l.value).isEqualTo("abcdef");
Ulf Adams89f012d2015-02-26 13:39:28 +0000266 }
267
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000268 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000269 public void testStringLiteralOptimizationToString() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000270 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
lberkiaea56b32017-05-30 12:35:33 +0200271 assertThat(l.toString()).isEqualTo("\"abcdef\"");
Ulf Adams89f012d2015-02-26 13:39:28 +0000272 }
273
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000274 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000275 public void testStringLiteralOptimizationLocation() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000276 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
lberkiaea56b32017-05-30 12:35:33 +0200277 assertThat(l.getLocation().getStartOffset()).isEqualTo(0);
278 assertThat(l.getLocation().getEndOffset()).isEqualTo(13);
Ulf Adams89f012d2015-02-26 13:39:28 +0000279 }
280
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000281 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000282 public void testStringLiteralOptimizationDifferentQuote() throws Exception {
Michajlo Matijkiw8c539ea2017-02-22 23:02:46 +0000283 StringLiteral l = (StringLiteral) parseExpression("'abc' + \"def\"");
lberkiaea56b32017-05-30 12:35:33 +0200284 assertThat(l.getLocation().getStartOffset()).isEqualTo(0);
285 assertThat(l.getLocation().getEndOffset()).isEqualTo(13);
Ulf Adams89f012d2015-02-26 13:39:28 +0000286 }
287
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000288 @Test
brandjonf2ed8582017-06-27 15:05:35 +0200289 public void testIndex() throws Exception {
290 IndexExpression e = (IndexExpression) parseExpression("a[i]");
291 assertThat(e.getObject().toString()).isEqualTo("a");
292 assertThat(e.getKey().toString()).isEqualTo("i");
293 assertLocation(0, 4, e.getLocation());
294 }
295
296 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000297 public void testSubstring() throws Exception {
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000298 SliceExpression s = (SliceExpression) parseExpression("'FOO.CC'[:].lower()[1:]");
laurentlbf2854bd2017-08-16 12:43:15 +0200299 assertThat(((IntegerLiteral) s.getStart()).getValue()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000300
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000301 FuncallExpression e = (FuncallExpression) parseExpression(
302 "'FOO.CC'.lower()[1:].startswith('oo')");
fzaiser8c27a892017-08-11 17:26:44 +0200303 DotExpression dotExpression = (DotExpression) e.getFunction();
304 assertThat(dotExpression.getField().getName()).isEqualTo("startswith");
Ulf Adams89f012d2015-02-26 13:39:28 +0000305 assertThat(e.getArguments()).hasSize(1);
306
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000307 s = (SliceExpression) parseExpression("'FOO.CC'[1:][:2]");
laurentlbf2854bd2017-08-16 12:43:15 +0200308 assertThat(((IntegerLiteral) s.getEnd()).getValue()).isEqualTo(2);
Florian Weikerte3421962015-12-17 12:46:08 +0000309 }
310
311 @Test
312 public void testSlice() throws Exception {
laurentlb9b96c0b2018-02-12 02:53:19 -0800313 evalSlice("'0123'[:]", "", "", "");
314 evalSlice("'0123'[1:]", 1, "", "");
315 evalSlice("'0123'[:3]", "", 3, "");
316 evalSlice("'0123'[::]", "", "", "");
317 evalSlice("'0123'[1::]", 1, "", "");
318 evalSlice("'0123'[:3:]", "", 3, "");
319 evalSlice("'0123'[::-1]", "", "", -1);
320 evalSlice("'0123'[1:3:]", 1, 3, "");
321 evalSlice("'0123'[1::-1]", 1, "", -1);
322 evalSlice("'0123'[:3:-1]", "", 3, -1);
Florian Weikerte3421962015-12-17 12:46:08 +0000323 evalSlice("'0123'[1:3:-1]", 1, 3, -1);
brandjonf2ed8582017-06-27 15:05:35 +0200324
325 Expression slice = parseExpression("'0123'[1:3:-1]");
326 assertLocation(0, 14, slice.getLocation());
Florian Weikerte3421962015-12-17 12:46:08 +0000327 }
328
329 private void evalSlice(String statement, Object... expectedArgs) {
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000330 SliceExpression e = (SliceExpression) parseExpression(statement);
331
332 // There is no way to evaluate the expression here, so we rely on string comparison.
laurentlb9b96c0b2018-02-12 02:53:19 -0800333 String start = e.getStart() == null ? "" : e.getStart().toString();
334 String end = e.getEnd() == null ? "" : e.getEnd().toString();
335 String step = e.getStep() == null ? "" : e.getStep().toString();
336
337 assertThat(start).isEqualTo(expectedArgs[0].toString());
338 assertThat(end).isEqualTo(expectedArgs[1].toString());
339 assertThat(step).isEqualTo(expectedArgs[2].toString());
Ulf Adams89f012d2015-02-26 13:39:28 +0000340 }
341
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000342 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000343 public void testErrorRecovery() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000344 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000345
Laurent Le Brun443aaae2015-04-21 19:49:49 +0000346 String expr = "f(1, [x for foo foo foo foo], 3)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000347 FuncallExpression e = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000348
Ulf Adamsc708f962015-10-22 12:02:28 +0000349 assertContainsError("syntax error at 'foo'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000350
351 // Test that the actual parameters are: (1, $error$, 3):
352
fzaiser8c27a892017-08-11 17:26:44 +0200353 Identifier ident = (Identifier) e.getFunction();
lberkiaea56b32017-05-30 12:35:33 +0200354 assertThat(ident.getName()).isEqualTo("f");
Ulf Adams89f012d2015-02-26 13:39:28 +0000355
356 assertThat(e.getArguments()).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200357 assertThat(e.getNumPositionalArguments()).isEqualTo(3);
Ulf Adams89f012d2015-02-26 13:39:28 +0000358
359 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
lberkiaea56b32017-05-30 12:35:33 +0200360 assertThat((int) arg0.getValue()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000361
362 Argument.Passed arg1 = e.getArguments().get(1);
Florian Weikert6f864c32015-07-23 11:26:39 +0000363 Identifier arg1val = ((Identifier) arg1.getValue());
lberkiaea56b32017-05-30 12:35:33 +0200364 assertThat(arg1val.getName()).isEqualTo("$error$");
Ulf Adams89f012d2015-02-26 13:39:28 +0000365
Laurent Le Brun443aaae2015-04-21 19:49:49 +0000366 assertLocation(5, 29, arg1val.getLocation());
lberkiaea56b32017-05-30 12:35:33 +0200367 assertThat(expr.substring(5, 28)).isEqualTo("[x for foo foo foo foo]");
fzaiser2a46d742017-10-02 19:59:28 +0200368 assertThat(arg1val.getLocation().getEndLineAndColumn().getColumn()).isEqualTo(29);
Ulf Adams89f012d2015-02-26 13:39:28 +0000369
370 IntegerLiteral arg2 = (IntegerLiteral) e.getArguments().get(2).getValue();
lberkiaea56b32017-05-30 12:35:33 +0200371 assertThat((int) arg2.getValue()).isEqualTo(3);
Ulf Adams89f012d2015-02-26 13:39:28 +0000372 }
373
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000374 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000375 public void testDoesntGetStuck() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000376 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000377
378 // Make sure the parser does not get stuck when trying
379 // to parse an expression containing a syntax error.
380 // This usually results in OutOfMemoryError because the
381 // parser keeps filling up the error log.
382 // We need to make sure that we will always advance
383 // in the token stream.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000384 parseExpression("f(1, ], 3)");
385 parseExpression("f(1, ), 3)");
386 parseExpression("[ ) for v in 3)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000387
Ulf Adamsc708f962015-10-22 12:02:28 +0000388 assertContainsError(""); // "" matches any, i.e., there were some events
Ulf Adams89f012d2015-02-26 13:39:28 +0000389 }
390
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000391 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000392 public void testSecondaryLocation() {
393 String expr = "f(1 % 2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000394 FuncallExpression call = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000395 Argument.Passed arg = call.getArguments().get(0);
Francois-Rene Rideauc673a822015-03-02 19:52:39 +0000396 assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
Ulf Adams89f012d2015-02-26 13:39:28 +0000397 }
398
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000399 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000400 public void testPrimaryLocation() {
401 String expr = "f(1 + 2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000402 FuncallExpression call = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000403 Argument.Passed arg = call.getArguments().get(0);
Francois-Rene Rideauc673a822015-03-02 19:52:39 +0000404 assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
Ulf Adams89f012d2015-02-26 13:39:28 +0000405 }
406
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000407 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000408 public void testAssignLocation() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000409 List<Statement> statements = parseFile("a = b;c = d\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000410 Statement statement = statements.get(0);
lberkiaea56b32017-05-30 12:35:33 +0200411 assertThat(statement.getLocation().getEndOffset()).isEqualTo(5);
Ulf Adams89f012d2015-02-26 13:39:28 +0000412 }
413
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000414 @Test
Laurent Le Brunc9041bf2015-03-23 15:34:12 +0000415 public void testAssignKeyword() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000416 setFailFast(false);
417 parseExpression("with = 4");
Ulf Adamsc708f962015-10-22 12:02:28 +0000418 assertContainsError("keyword 'with' not supported");
419 assertContainsError("syntax error at 'with': expected expression");
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000420 }
421
422 @Test
Laurent Le Brunee991a12015-06-16 10:56:46 +0000423 public void testBreak() {
424 setFailFast(false);
425 parseExpression("break");
Ulf Adamsc708f962015-10-22 12:02:28 +0000426 assertContainsError("syntax error at 'break': expected expression");
Laurent Le Brunee991a12015-06-16 10:56:46 +0000427 }
428
429 @Test
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000430 public void testTry() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000431 setFailFast(false);
432 parseExpression("try: 1 + 1");
Ulf Adamsc708f962015-10-22 12:02:28 +0000433 assertContainsError("'try' not supported, all exceptions are fatal");
434 assertContainsError("syntax error at 'try': expected expression");
Laurent Le Brunc9041bf2015-03-23 15:34:12 +0000435 }
436
437 @Test
Laurent Le Brun44ad7fa2016-10-11 12:09:05 +0000438 public void testDel() {
439 setFailFast(false);
440 parseExpression("del d['a']");
441 assertContainsError("'del' not supported, use '.pop()' to delete");
442 }
443
444 @Test
Laurent Le Brun56093892015-03-20 13:01:58 +0000445 public void testTupleAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000446 List<Statement> statements = parseFile("list[0] = 5; dict['key'] = value\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000447 assertThat(statements).hasSize(2);
Laurent Le Brun56093892015-03-20 13:01:58 +0000448 assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
449 assertThat(statements.get(1)).isInstanceOf(AssignmentStatement.class);
450 }
451
452 @Test
453 public void testAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000454 List<Statement> statements = parseFile("a, b = 5\n");
Laurent Le Brun56093892015-03-20 13:01:58 +0000455 assertThat(statements).hasSize(1);
456 assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
457 AssignmentStatement assign = (AssignmentStatement) statements.get(0);
Googlerade53272019-07-01 07:29:11 -0700458 assertThat(assign.getLHS()).isInstanceOf(ListLiteral.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000459 }
460
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000461 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000462 public void testInvalidAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000463 setFailFast(false);
464 parseExpression("1 + (b = c)");
Ulf Adamsc708f962015-10-22 12:02:28 +0000465 assertContainsError("syntax error");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000466 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000467 }
468
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000469 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000470 public void testAugmentedAssign() throws Exception {
lberkiaea56b32017-05-30 12:35:33 +0200471 assertThat(parseFile("x += 1").toString()).isEqualTo("[x += 1\n]");
472 assertThat(parseFile("x -= 1").toString()).isEqualTo("[x -= 1\n]");
473 assertThat(parseFile("x *= 1").toString()).isEqualTo("[x *= 1\n]");
474 assertThat(parseFile("x /= 1").toString()).isEqualTo("[x /= 1\n]");
475 assertThat(parseFile("x %= 1").toString()).isEqualTo("[x %= 1\n]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000476 }
477
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000478 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000479 public void testPrettyPrintFunctions() throws Exception {
lberkiaea56b32017-05-30 12:35:33 +0200480 assertThat(parseFile("x[1:3]").toString()).isEqualTo("[x[1:3]\n]");
laurentlb9b96c0b2018-02-12 02:53:19 -0800481 assertThat(parseFile("x[1:3:1]").toString()).isEqualTo("[x[1:3:1]\n]");
lberkiaea56b32017-05-30 12:35:33 +0200482 assertThat(parseFile("x[1:3:2]").toString()).isEqualTo("[x[1:3:2]\n]");
483 assertThat(parseFile("x[1::2]").toString()).isEqualTo("[x[1::2]\n]");
484 assertThat(parseFile("x[1:]").toString()).isEqualTo("[x[1:]\n]");
485 assertThat(parseFile("str[42]").toString()).isEqualTo("[str[42]\n]");
dslomov2e84e7c2017-06-27 14:38:45 +0200486 assertThat(parseFile("ctx.actions.declare_file('hello')").toString())
487 .isEqualTo("[ctx.actions.declare_file(\"hello\")\n]");
lberkiaea56b32017-05-30 12:35:33 +0200488 assertThat(parseFile("new_file(\"hello\")").toString()).isEqualTo("[new_file(\"hello\")\n]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000489 }
490
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000491 @Test
fzaiser2a46d742017-10-02 19:59:28 +0200492 public void testEndLineAndColumnIsInclusive() {
493 AssignmentStatement stmt =
494 (AssignmentStatement) parseStatement(ParsingLevel.LOCAL_LEVEL, "a = b");
Googlerade53272019-07-01 07:29:11 -0700495 assertThat(stmt.getLHS().getLocation().getEndLineAndColumn())
fzaiser2a46d742017-10-02 19:59:28 +0200496 .isEqualTo(new LineAndColumn(1, 1));
497 }
498
499 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000500 public void testFuncallLocation() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000501 List<Statement> statements = parseFile("a(b);c = d\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000502 Statement statement = statements.get(0);
lberkiaea56b32017-05-30 12:35:33 +0200503 assertThat(statement.getLocation().getEndOffset()).isEqualTo(4);
Ulf Adams89f012d2015-02-26 13:39:28 +0000504 }
505
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000506 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000507 public void testListPositions() throws Exception {
508 String expr = "[0,f(1),2]";
fzaiseraa8540d2017-09-26 06:01:30 -0400509 assertExpressionLocationCorrect(expr);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000510 ListLiteral list = (ListLiteral) parseExpression(expr);
lberkiaea56b32017-05-30 12:35:33 +0200511 assertThat(getText(expr, getElem(list, 0))).isEqualTo("0");
512 assertThat(getText(expr, getElem(list, 1))).isEqualTo("f(1)");
513 assertThat(getText(expr, getElem(list, 2))).isEqualTo("2");
Ulf Adams89f012d2015-02-26 13:39:28 +0000514 }
515
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000516 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000517 public void testDictPositions() throws Exception {
518 String expr = "{1:2,2:f(1),3:4}";
fzaiseraa8540d2017-09-26 06:01:30 -0400519 assertExpressionLocationCorrect(expr);
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000520 DictionaryLiteral list = (DictionaryLiteral) parseExpression(expr);
lberkiaea56b32017-05-30 12:35:33 +0200521 assertThat(getText(expr, getElem(list, 0))).isEqualTo("1:2");
522 assertThat(getText(expr, getElem(list, 1))).isEqualTo("2:f(1)");
523 assertThat(getText(expr, getElem(list, 2))).isEqualTo("3:4");
Ulf Adams89f012d2015-02-26 13:39:28 +0000524 }
525
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000526 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000527 public void testArgumentPositions() throws Exception {
fzaiseraa8540d2017-09-26 06:01:30 -0400528 String expr = "f(0,g(1,2),2)";
529 assertExpressionLocationCorrect(expr);
530 FuncallExpression f = (FuncallExpression) parseExpression(expr);
531 assertThat(getText(expr, getArg(f, 0))).isEqualTo("0");
532 assertThat(getText(expr, getArg(f, 1))).isEqualTo("g(1,2)");
533 assertThat(getText(expr, getArg(f, 2))).isEqualTo("2");
534 }
535
536 @Test
537 public void testSuffixPosition() throws Exception {
538 assertExpressionLocationCorrect("'a'.len");
539 assertExpressionLocationCorrect("'a'[0]");
540 assertExpressionLocationCorrect("'a'[0:1]");
541 }
542
543 @Test
544 public void testTuplePosition() throws Exception {
545 String input = "for a,b in []: pass";
546 ForStatement stmt = (ForStatement) parseStatement(ParsingLevel.LOCAL_LEVEL, input);
Googlerade53272019-07-01 07:29:11 -0700547 assertThat(getText(input, stmt.getLHS())).isEqualTo("a,b");
fzaiseraa8540d2017-09-26 06:01:30 -0400548 input = "for (a,b) in []: pass";
549 stmt = (ForStatement) parseStatement(ParsingLevel.LOCAL_LEVEL, input);
Googlerade53272019-07-01 07:29:11 -0700550 assertThat(getText(input, stmt.getLHS())).isEqualTo("(a,b)");
fzaiseraa8540d2017-09-26 06:01:30 -0400551 assertExpressionLocationCorrect("a, b");
552 assertExpressionLocationCorrect("(a, b)");
553 }
554
555 @Test
556 public void testComprehensionPosition() throws Exception {
557 assertExpressionLocationCorrect("[[] for x in []]");
558 assertExpressionLocationCorrect("{1: [] for x in []}");
559 }
560
561 @Test
562 public void testUnaryOperationPosition() throws Exception {
563 assertExpressionLocationCorrect("not True");
564 }
565
fzaiserb5768af2017-10-09 15:16:50 +0200566 @Test
567 public void testLoadStatementPosition() throws Exception {
568 String input = "load(':foo.bzl', 'bar')";
569 LoadStatement stmt = (LoadStatement) parseFile(input).get(0);
570 assertThat(getText(input, stmt)).isEqualTo(input);
571 // Also try it with another token at the end (newline), which broke the location in the past.
572 stmt = (LoadStatement) parseFile(input + "\n").get(0);
573 assertThat(getText(input, stmt)).isEqualTo(input);
574 }
575
fzaiser1a92d562017-10-24 15:37:50 +0200576 @Test
577 public void testIfStatementPosition() throws Exception {
578 assertStatementLocationCorrect(ParsingLevel.LOCAL_LEVEL, "if True:\n pass");
579 assertStatementLocationCorrect(
580 ParsingLevel.LOCAL_LEVEL, "if True:\n pass\nelif True:\n pass");
581 assertStatementLocationCorrect(ParsingLevel.LOCAL_LEVEL, "if True:\n pass\nelse:\n pass");
582 }
583
584 @Test
585 public void testForStatementPosition() throws Exception {
586 assertStatementLocationCorrect(ParsingLevel.LOCAL_LEVEL, "for x in []:\n pass");
587 }
588
589 @Test
590 public void testDefStatementPosition() throws Exception {
591 assertStatementLocationCorrect(ParsingLevel.TOP_LEVEL, "def foo():\n pass");
592 }
593
594 private void assertStatementLocationCorrect(ParsingLevel level, String stmtStr) {
595 Statement stmt = parseStatement(level, stmtStr);
596 assertThat(getText(stmtStr, stmt)).isEqualTo(stmtStr);
597 // Also try it with another token at the end (newline), which broke the location in the past.
598 stmt = parseStatement(level, stmtStr + "\n");
599 assertThat(getText(stmtStr, stmt)).isEqualTo(stmtStr);
600 }
601
fzaiseraa8540d2017-09-26 06:01:30 -0400602 private void assertExpressionLocationCorrect(String exprStr) {
603 Expression expr = parseExpression(exprStr);
604 assertThat(getText(exprStr, expr)).isEqualTo(exprStr);
605 // Also try it with another token at the end (newline), which broke the location in the past.
606 expr = parseExpression(exprStr + "\n");
607 assertThat(getText(exprStr, expr)).isEqualTo(exprStr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000608 }
609
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000610 @Test
Googler5d72d4e2019-06-30 21:10:44 -0700611 public void testForBreakContinue() throws Exception {
612 List<Statement> file = parseFileForSkylark(
613 "def foo():",
614 " for i in [1, 2]:",
615 " break",
616 " continue",
617 " break");
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000618 assertThat(file).hasSize(1);
619 List<Statement> body = ((FunctionDefStatement) file.get(0)).getStatements();
620 assertThat(body).hasSize(1);
621
brandjon990622b2017-07-11 19:56:45 +0200622 List<Statement> loop = ((ForStatement) body.get(0)).getBlock();
Googler5d72d4e2019-06-30 21:10:44 -0700623 assertThat(loop).hasSize(3);
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000624
Googler5d72d4e2019-06-30 21:10:44 -0700625 assertThat(((FlowStatement) loop.get(0)).getKind()).isEqualTo(FlowStatement.Kind.BREAK);
Laurent Le Bruna3c25a62016-10-26 10:59:09 +0000626 assertLocation(34, 39, loop.get(0).getLocation());
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000627
Googler5d72d4e2019-06-30 21:10:44 -0700628 assertThat(((FlowStatement) loop.get(1)).getKind()).isEqualTo(FlowStatement.Kind.CONTINUE);
Laurent Le Bruna3c25a62016-10-26 10:59:09 +0000629 assertLocation(44, 52, loop.get(1).getLocation());
Laurent Le Brun7d6a3812015-10-26 12:07:12 +0000630
Googler5d72d4e2019-06-30 21:10:44 -0700631 assertThat(((FlowStatement) loop.get(2)).getKind()).isEqualTo(FlowStatement.Kind.BREAK);
632 assertLocation(57, 62, loop.get(2).getLocation());
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000633 }
634
635 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000636 public void testListLiterals1() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000637 ListLiteral list = (ListLiteral) parseExpression("[0,1,2]");
lberkiaea56b32017-05-30 12:35:33 +0200638 assertThat(list.isTuple()).isFalse();
Ulf Adams89f012d2015-02-26 13:39:28 +0000639 assertThat(list.getElements()).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200640 assertThat(list.isTuple()).isFalse();
Ulf Adams89f012d2015-02-26 13:39:28 +0000641 for (int i = 0; i < 3; ++i) {
lberkiaea56b32017-05-30 12:35:33 +0200642 assertThat(getIntElem(list, i)).isEqualTo(i);
Ulf Adams89f012d2015-02-26 13:39:28 +0000643 }
644 }
645
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000646 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000647 public void testTupleLiterals2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000648 ListLiteral tuple = (ListLiteral) parseExpression("(0,1,2)");
lberkiaea56b32017-05-30 12:35:33 +0200649 assertThat(tuple.isTuple()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000650 assertThat(tuple.getElements()).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200651 assertThat(tuple.isTuple()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000652 for (int i = 0; i < 3; ++i) {
lberkiaea56b32017-05-30 12:35:33 +0200653 assertThat(getIntElem(tuple, i)).isEqualTo(i);
Ulf Adams89f012d2015-02-26 13:39:28 +0000654 }
655 }
656
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000657 @Test
Laurent Le Brun56093892015-03-20 13:01:58 +0000658 public void testTupleWithoutParens() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000659 ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2");
lberkiaea56b32017-05-30 12:35:33 +0200660 assertThat(tuple.isTuple()).isTrue();
Laurent Le Brun56093892015-03-20 13:01:58 +0000661 assertThat(tuple.getElements()).hasSize(3);
lberkiaea56b32017-05-30 12:35:33 +0200662 assertThat(tuple.isTuple()).isTrue();
Laurent Le Brun56093892015-03-20 13:01:58 +0000663 for (int i = 0; i < 3; ++i) {
lberkiaea56b32017-05-30 12:35:33 +0200664 assertThat(getIntElem(tuple, i)).isEqualTo(i);
Laurent Le Brun56093892015-03-20 13:01:58 +0000665 }
666 }
667
668 @Test
Laurent Le Brunb639ca82017-01-17 11:18:23 +0000669 public void testTupleWithTrailingComma() throws Exception {
670 setFailFast(false);
671
672 // Unlike Python, we require parens here.
673 parseExpression("0, 1, 2, 3,");
674 assertContainsError("Trailing comma");
675 clearEvents();
676
677 parseExpression("1 + 2,");
678 assertContainsError("Trailing comma");
679 clearEvents();
680
681 ListLiteral tuple = (ListLiteral) parseExpression("(0, 1, 2, 3,)");
lberkiaea56b32017-05-30 12:35:33 +0200682 assertThat(tuple.isTuple()).isTrue();
Laurent Le Brun56093892015-03-20 13:01:58 +0000683 assertThat(tuple.getElements()).hasSize(4);
lberkiaea56b32017-05-30 12:35:33 +0200684 assertThat(tuple.isTuple()).isTrue();
Laurent Le Brun56093892015-03-20 13:01:58 +0000685 for (int i = 0; i < 4; ++i) {
lberkiaea56b32017-05-30 12:35:33 +0200686 assertThat(getIntElem(tuple, i)).isEqualTo(i);
Laurent Le Brun56093892015-03-20 13:01:58 +0000687 }
688 }
689
690 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000691 public void testTupleLiterals3() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000692 ListLiteral emptyTuple = (ListLiteral) parseExpression("()");
lberkiaea56b32017-05-30 12:35:33 +0200693 assertThat(emptyTuple.isTuple()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000694 assertThat(emptyTuple.getElements()).isEmpty();
695 }
696
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000697 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000698 public void testTupleLiterals4() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000699 ListLiteral singletonTuple = (ListLiteral) parseExpression("(42,)");
lberkiaea56b32017-05-30 12:35:33 +0200700 assertThat(singletonTuple.isTuple()).isTrue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000701 assertThat(singletonTuple.getElements()).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200702 assertThat(getIntElem(singletonTuple, 0)).isEqualTo(42);
Ulf Adams89f012d2015-02-26 13:39:28 +0000703 }
704
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000705 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000706 public void testTupleLiterals5() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000707 IntegerLiteral intLit = (IntegerLiteral) parseExpression("(42)"); // not a tuple!
lberkiaea56b32017-05-30 12:35:33 +0200708 assertThat((int) intLit.getValue()).isEqualTo(42);
Ulf Adams89f012d2015-02-26 13:39:28 +0000709 }
710
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000711 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000712 public void testListLiterals6() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000713 ListLiteral emptyList = (ListLiteral) parseExpression("[]");
lberkiaea56b32017-05-30 12:35:33 +0200714 assertThat(emptyList.isTuple()).isFalse();
Ulf Adams89f012d2015-02-26 13:39:28 +0000715 assertThat(emptyList.getElements()).isEmpty();
716 }
717
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000718 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000719 public void testListLiterals7() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000720 ListLiteral singletonList = (ListLiteral) parseExpression("[42,]");
lberkiaea56b32017-05-30 12:35:33 +0200721 assertThat(singletonList.isTuple()).isFalse();
Ulf Adams89f012d2015-02-26 13:39:28 +0000722 assertThat(singletonList.getElements()).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200723 assertThat(getIntElem(singletonList, 0)).isEqualTo(42);
Ulf Adams89f012d2015-02-26 13:39:28 +0000724 }
725
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000726 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000727 public void testListLiterals8() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000728 ListLiteral singletonList = (ListLiteral) parseExpression("[42]"); // a singleton
lberkiaea56b32017-05-30 12:35:33 +0200729 assertThat(singletonList.isTuple()).isFalse();
Ulf Adams89f012d2015-02-26 13:39:28 +0000730 assertThat(singletonList.getElements()).hasSize(1);
lberkiaea56b32017-05-30 12:35:33 +0200731 assertThat(getIntElem(singletonList, 0)).isEqualTo(42);
Ulf Adams89f012d2015-02-26 13:39:28 +0000732 }
733
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000734 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000735 public void testDictionaryLiterals() throws Exception {
736 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000737 (DictionaryLiteral) parseExpression("{1:42}"); // a singleton dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000738 assertThat(dictionaryList.getEntries()).hasSize(1);
739 DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
lberkiaea56b32017-05-30 12:35:33 +0200740 assertThat(getIntElem(tuple, true)).isEqualTo(1);
741 assertThat(getIntElem(tuple, false)).isEqualTo(42);
Ulf Adams89f012d2015-02-26 13:39:28 +0000742 }
743
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000744 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000745 public void testDictionaryLiterals1() throws Exception {
746 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000747 (DictionaryLiteral) parseExpression("{}"); // an empty dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000748 assertThat(dictionaryList.getEntries()).isEmpty();
749 }
750
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000751 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000752 public void testDictionaryLiterals2() throws Exception {
753 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000754 (DictionaryLiteral) parseExpression("{1:42,}"); // a singleton dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000755 assertThat(dictionaryList.getEntries()).hasSize(1);
756 DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
lberkiaea56b32017-05-30 12:35:33 +0200757 assertThat(getIntElem(tuple, true)).isEqualTo(1);
758 assertThat(getIntElem(tuple, false)).isEqualTo(42);
Ulf Adams89f012d2015-02-26 13:39:28 +0000759 }
760
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000761 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000762 public void testDictionaryLiterals3() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000763 DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpression("{1:42,2:43,3:44}");
Ulf Adams89f012d2015-02-26 13:39:28 +0000764 assertThat(dictionaryList.getEntries()).hasSize(3);
765 for (int i = 0; i < 3; i++) {
766 DictionaryEntryLiteral tuple = getElem(dictionaryList, i);
lberkiaea56b32017-05-30 12:35:33 +0200767 assertThat(getIntElem(tuple, true)).isEqualTo(i + 1);
768 assertThat(getIntElem(tuple, false)).isEqualTo(i + 42);
Ulf Adams89f012d2015-02-26 13:39:28 +0000769 }
770 }
771
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000772 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000773 public void testListLiterals9() throws Exception {
774 ListLiteral singletonList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000775 (ListLiteral) parseExpression("[ abi + opt_level + \'/include\' ]");
lberkiaea56b32017-05-30 12:35:33 +0200776 assertThat(singletonList.isTuple()).isFalse();
Ulf Adams89f012d2015-02-26 13:39:28 +0000777 assertThat(singletonList.getElements()).hasSize(1);
778 }
779
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000780 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000781 public void testListComprehensionSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000782 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000783
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000784 parseExpression("[x for");
Ulf Adamsc708f962015-10-22 12:02:28 +0000785 assertContainsError("syntax error at 'newline'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000786 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000787
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000788 parseExpression("[x for x");
Ulf Adamsc708f962015-10-22 12:02:28 +0000789 assertContainsError("syntax error at 'newline'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000790 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000791
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000792 parseExpression("[x for x in");
Ulf Adamsc708f962015-10-22 12:02:28 +0000793 assertContainsError("syntax error at 'newline'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000794 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000795
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000796 parseExpression("[x for x in []");
Ulf Adamsc708f962015-10-22 12:02:28 +0000797 assertContainsError("syntax error at 'newline'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000798 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000799
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000800 parseExpression("[x for x for y in ['a']]");
Ulf Adamsc708f962015-10-22 12:02:28 +0000801 assertContainsError("syntax error at 'for'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000802 clearEvents();
laurentlbc3a1af62017-06-16 14:37:43 +0200803
804 parseExpression("[x for x for y in 1, 2]");
805 assertContainsError("syntax error at 'for'");
806 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000807 }
808
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000809 @Test
Laurent Le Brun52021662015-05-18 09:28:26 +0000810 public void testListComprehensionEmptyList() throws Exception {
811 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
812 "['foo/%s.java' % x for x in []]")).getClauses();
813 assertThat(clauses).hasSize(1);
814 assertThat(clauses.get(0).getExpression().toString()).isEqualTo("[]");
Googlerade53272019-07-01 07:29:11 -0700815 assertThat(clauses.get(0).getLHS().toString()).isEqualTo("x");
Laurent Le Brun52021662015-05-18 09:28:26 +0000816 }
817
818 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000819 public void testListComprehension() throws Exception {
Laurent Le Brun52021662015-05-18 09:28:26 +0000820 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
821 "['foo/%s.java' % x for x in ['bar', 'wiz', 'quux']]")).getClauses();
822 assertThat(clauses).hasSize(1);
Googlerade53272019-07-01 07:29:11 -0700823 assertThat(clauses.get(0).getLHS().toString()).isEqualTo("x");
Laurent Le Brun52021662015-05-18 09:28:26 +0000824 assertThat(clauses.get(0).getExpression()).isInstanceOf(ListLiteral.class);
825 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000826
Laurent Le Brun52021662015-05-18 09:28:26 +0000827 @Test
828 public void testForForListComprehension() throws Exception {
829 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
830 "['%s/%s.java' % (x, y) for x in ['foo', 'bar'] for y in list]")).getClauses();
831 assertThat(clauses).hasSize(2);
Googlerade53272019-07-01 07:29:11 -0700832 assertThat(clauses.get(0).getLHS().toString()).isEqualTo("x");
Laurent Le Brun52021662015-05-18 09:28:26 +0000833 assertThat(clauses.get(0).getExpression()).isInstanceOf(ListLiteral.class);
Googlerade53272019-07-01 07:29:11 -0700834 assertThat(clauses.get(1).getLHS().toString()).isEqualTo("y");
Florian Weikert6f864c32015-07-23 11:26:39 +0000835 assertThat(clauses.get(1).getExpression()).isInstanceOf(Identifier.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000836 }
837
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000838 @Test
Laurent Le Brun9060e162015-04-02 10:07:28 +0000839 public void testParserRecovery() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000840 setFailFast(false);
841 List<Statement> statements = parseFileForSkylark(
Laurent Le Brun9060e162015-04-02 10:07:28 +0000842 "def foo():",
Laurent Le Brune3f4ed72015-05-08 14:47:26 +0000843 " a = 2 for 4", // parse error
Laurent Le Brun9060e162015-04-02 10:07:28 +0000844 " b = [3, 4]",
845 "",
846 "d = 4 ada", // parse error
847 "",
848 "def bar():",
849 " a = [3, 4]",
850 " b = 2 + + 5", // parse error
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000851 "");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000852
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000853 assertThat(getEventCollector()).hasSize(3);
Ulf Adamsc708f962015-10-22 12:02:28 +0000854 assertContainsError("syntax error at 'for': expected newline");
855 assertContainsError("syntax error at 'ada': expected newline");
856 assertContainsError("syntax error at '+': expected expression");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000857 assertThat(statements).hasSize(3);
858 }
859
860 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000861 public void testParserContainsErrorsIfSyntaxException() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000862 setFailFast(false);
863 parseExpression("'foo' %%");
Ulf Adamsc708f962015-10-22 12:02:28 +0000864 assertContainsError("syntax error at '%'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000865 }
866
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000867 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000868 public void testParserDoesNotContainErrorsIfSuccess() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000869 parseExpression("'foo'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000870 }
871
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000872 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000873 public void testParserContainsErrors() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000874 setFailFast(false);
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000875 parseFile("+");
Ulf Adamsc708f962015-10-22 12:02:28 +0000876 assertContainsError("syntax error at '+'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000877 }
878
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000879 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000880 public void testSemicolonAndNewline() throws Exception {
881 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000882 "foo='bar'; foo(bar)",
883 "",
884 "foo='bar'; foo(bar)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000885 assertThat(stmts).hasSize(4);
886 }
887
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000888 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000889 public void testSemicolonAndNewline2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000890 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000891 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000892 "foo='foo' error(bar)",
893 "",
894 "");
Ulf Adamsc708f962015-10-22 12:02:28 +0000895 assertContainsError("syntax error at 'error'");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000896 assertThat(stmts).hasSize(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000897 }
898
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000899 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000900 public void testExprAsStatement() throws Exception {
901 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000902 "li = []",
903 "li.append('a.c')",
904 "\"\"\" string comment \"\"\"",
905 "foo(bar)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000906 assertThat(stmts).hasSize(4);
907 }
908
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000909 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000910 public void testParseBuildFileWithSingeRule() throws Exception {
911 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000912 "genrule(name = 'foo',",
913 " srcs = ['input.csv'],",
914 " outs = [ 'result.txt',",
915 " 'result.log'],",
916 " cmd = 'touch result.txt result.log')",
917 "");
Ulf Adams89f012d2015-02-26 13:39:28 +0000918 assertThat(stmts).hasSize(1);
919 }
920
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000921 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000922 public void testParseBuildFileWithMultipleRules() throws Exception {
923 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000924 "genrule(name = 'foo',",
925 " srcs = ['input.csv'],",
926 " outs = [ 'result.txt',",
927 " 'result.log'],",
928 " cmd = 'touch result.txt result.log')",
929 "",
930 "genrule(name = 'bar',",
931 " srcs = ['input.csv'],",
932 " outs = [ 'graph.svg'],",
933 " cmd = 'touch graph.svg')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000934 assertThat(stmts).hasSize(2);
935 }
936
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000937 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000938 public void testParseBuildFileWithComments() throws Exception {
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000939 BuildFileAST result = parseFileWithComments(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000940 "# Test BUILD file",
941 "# with multi-line comment",
942 "",
943 "genrule(name = 'foo',",
944 " srcs = ['input.csv'],",
945 " outs = [ 'result.txt',",
946 " 'result.log'],",
947 " cmd = 'touch result.txt result.log')");
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000948 assertThat(result.getStatements()).hasSize(1);
949 assertThat(result.getComments()).hasSize(2);
Ulf Adams89f012d2015-02-26 13:39:28 +0000950 }
951
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000952 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000953 public void testParseBuildFileWithManyComments() throws Exception {
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000954 BuildFileAST result = parseFileWithComments(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000955 "# 1",
956 "# 2",
957 "",
958 "# 4 ",
959 "# 5",
960 "#", // 6 - find empty comment for syntax highlighting
961 "# 7 ",
962 "# 8",
963 "genrule(name = 'foo',",
964 " srcs = ['input.csv'],",
965 " # 11",
966 " outs = [ 'result.txt',",
967 " 'result.log'], # 13",
968 " cmd = 'touch result.txt result.log')",
969 "# 15");
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000970 assertThat(result.getStatements()).hasSize(1); // Single genrule
Ulf Adams89f012d2015-02-26 13:39:28 +0000971 StringBuilder commentLines = new StringBuilder();
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000972 for (Comment comment : result.getComments()) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000973 // Comments start and end on the same line
lberkiaea56b32017-05-30 12:35:33 +0200974 assertWithMessage(
975 comment.getLocation().getStartLineAndColumn().getLine()
976 + " ends on "
977 + comment.getLocation().getEndLineAndColumn().getLine())
978 .that(comment.getLocation().getEndLineAndColumn().getLine())
979 .isEqualTo(comment.getLocation().getStartLineAndColumn().getLine());
Ulf Adams89f012d2015-02-26 13:39:28 +0000980 commentLines.append('(');
981 commentLines.append(comment.getLocation().getStartLineAndColumn().getLine());
982 commentLines.append(',');
983 commentLines.append(comment.getLocation().getStartLineAndColumn().getColumn());
984 commentLines.append(") ");
985 }
986 assertWithMessage("Found: " + commentLines)
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000987 .that(result.getComments().size()).isEqualTo(10); // One per '#'
Ulf Adams89f012d2015-02-26 13:39:28 +0000988 }
989
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000990 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000991 public void testMissingComma() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000992 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000993 // Regression test.
994 // Note: missing comma after name='foo'
995 parseFile("genrule(name = 'foo'\n"
996 + " srcs = ['in'])");
Ulf Adamsc708f962015-10-22 12:02:28 +0000997 assertContainsError("syntax error at 'srcs'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000998 }
999
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001000 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001001 public void testDoubleSemicolon() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001002 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001003 // Regression test.
1004 parseFile("x = 1; ; x = 2;");
Ulf Adamsc708f962015-10-22 12:02:28 +00001005 assertContainsError("syntax error at ';'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001006 }
1007
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001008 @Test
Laurent Le Brun5f674452015-03-17 19:29:13 +00001009 public void testDefSingleLine() throws Exception {
1010 List<Statement> statements = parseFileForSkylark(
1011 "def foo(): x = 1; y = 2\n");
1012 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
1013 assertThat(stmt.getStatements()).hasSize(2);
1014 }
1015
1016 @Test
Googler5d72d4e2019-06-30 21:10:44 -07001017 public void testPass() throws Exception {
1018 List<Statement> statements = parseFileForSkylark("pass\n");
1019 assertThat(statements).hasSize(1);
1020 assertThat(statements.get(0)).isInstanceOf(PassStatement.class);
1021 }
1022
1023 @Test
Laurent Le Brun0942ee92015-03-17 20:22:16 +00001024 public void testForPass() throws Exception {
1025 List<Statement> statements = parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001026 "def foo():",
1027 " pass\n");
Laurent Le Brun0942ee92015-03-17 20:22:16 +00001028
1029 assertThat(statements).hasSize(1);
1030 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
Googler5d72d4e2019-06-30 21:10:44 -07001031 assertThat(stmt.getStatements().get(0)).isInstanceOf(PassStatement.class);
Laurent Le Brun0942ee92015-03-17 20:22:16 +00001032 }
1033
1034 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001035 public void testForLoopMultipleVariables() throws Exception {
Laurent Le Brun185392d2015-03-20 14:41:25 +00001036 List<Statement> stmts1 = parseFile("[ i for i, j, k in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +00001037 assertThat(stmts1).hasSize(1);
1038
Laurent Le Brun185392d2015-03-20 14:41:25 +00001039 List<Statement> stmts2 = parseFile("[ i for i, j in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +00001040 assertThat(stmts2).hasSize(1);
1041
Laurent Le Brun185392d2015-03-20 14:41:25 +00001042 List<Statement> stmts3 = parseFile("[ i for (i, j, k) in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +00001043 assertThat(stmts3).hasSize(1);
1044 }
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001045
Googlercc0d9952015-08-10 12:01:34 +00001046 @Test
1047 public void testReturnNone() throws Exception {
1048 List<Statement> defNone = parseFileForSkylark("def foo():", " return None\n");
1049 assertThat(defNone).hasSize(1);
1050
1051 List<Statement> bodyNone = ((FunctionDefStatement) defNone.get(0)).getStatements();
1052 assertThat(bodyNone).hasSize(1);
1053
1054 ReturnStatement returnNone = (ReturnStatement) bodyNone.get(0);
lberkiaea56b32017-05-30 12:35:33 +02001055 assertThat(((Identifier) returnNone.getReturnExpression()).getName()).isEqualTo("None");
Googlercc0d9952015-08-10 12:01:34 +00001056
1057 int i = 0;
1058 for (String end : new String[]{";", "\n"}) {
1059 List<Statement> defNoExpr = parseFileForSkylark("def bar" + i + "():", " return" + end);
1060 i++;
1061 assertThat(defNoExpr).hasSize(1);
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001062
Googlercc0d9952015-08-10 12:01:34 +00001063 List<Statement> bodyNoExpr = ((FunctionDefStatement) defNoExpr.get(0)).getStatements();
1064 assertThat(bodyNoExpr).hasSize(1);
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001065
Googlercc0d9952015-08-10 12:01:34 +00001066 ReturnStatement returnNoExpr = (ReturnStatement) bodyNoExpr.get(0);
fzaiser317a2692017-08-23 16:40:30 +02001067 assertThat(returnNoExpr.getReturnExpression()).isNull();
Googlercc0d9952015-08-10 12:01:34 +00001068 }
1069 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001070
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001071 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001072 public void testForLoopBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001073 setFailFast(false);
Laurent Le Brun185392d2015-03-20 14:41:25 +00001074 parseFile("[1 for (a, b, c in var]\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001075 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001076 }
1077
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001078 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001079 public void testForLoopBadSyntax2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001080 setFailFast(false);
Laurent Le Brun185392d2015-03-20 14:41:25 +00001081 parseFile("[1 for in var]\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001082 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001083 }
1084
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001085 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001086 public void testFunCallBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001087 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001088 parseFile("f(1,\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001089 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001090 }
1091
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001092 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001093 public void testFunCallBadSyntax2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001094 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001095 parseFile("f(1, 5, ,)\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001096 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001097 }
1098
John Field1ea7fc32015-12-22 19:37:19 +00001099 private void validNonAbsoluteImportTest(String importString, String containingFileLabelString,
Miguel Alcon Pinto927f3b22016-08-22 14:21:30 +00001100 String expectedLabelString) throws SkylarkImportSyntaxException {
John Field1ea7fc32015-12-22 19:37:19 +00001101 List<Statement> statements =
1102 parseFileForSkylark("load('" + importString + "', 'fun_test')\n");
1103 LoadStatement stmt = (LoadStatement) statements.get(0);
laurentlbc6c9b8e2019-04-15 11:26:26 -07001104 SkylarkImport imp = SkylarkImport.create(stmt.getImport().getValue());
John Field9201fda2015-12-30 19:30:34 +00001105
cpovirk348ae532019-04-29 15:14:34 -07001106 assertWithMessage("getImportString()").that(imp.getImportString()).isEqualTo(importString);
John Field9201fda2015-12-30 19:30:34 +00001107
John Field1ea7fc32015-12-22 19:37:19 +00001108 Label containingFileLabel = Label.parseAbsoluteUnchecked(containingFileLabelString);
cpovirk348ae532019-04-29 15:14:34 -07001109 assertWithMessage("containingFileLabel()")
1110 .that(imp.getLabel(containingFileLabel))
Michajlo Matijkiw8c539ea2017-02-22 23:02:46 +00001111 .isEqualTo(Label.parseAbsoluteUnchecked(expectedLabelString));
John Field9201fda2015-12-30 19:30:34 +00001112
Laurent Le Brun7b1708c2016-10-13 10:05:12 +00001113 int startOffset = stmt.getImport().getLocation().getStartOffset();
1114 int endOffset = stmt.getImport().getLocation().getEndOffset();
cpovirk348ae532019-04-29 15:14:34 -07001115 assertWithMessage("getStartOffset()").that(startOffset).isEqualTo(5);
1116 assertWithMessage("getEndOffset()")
1117 .that(endOffset)
John Field9201fda2015-12-30 19:30:34 +00001118 .isEqualTo(startOffset + importString.length() + 2);
John Field1ea7fc32015-12-22 19:37:19 +00001119 }
1120
1121 private void invalidImportTest(String importString, String expectedMsg) {
Florian Weikert308c0bf2015-07-10 10:46:56 +00001122 setFailFast(false);
Michajlo Matijkiw8c539ea2017-02-22 23:02:46 +00001123 parseFileForSkylark("load('" + importString + "', 'fun_test')\n");
Jon Brandveinee8b7aa2016-07-28 15:01:26 +00001124 assertContainsError(expectedMsg);
Florian Weikert308c0bf2015-07-10 10:46:56 +00001125 }
1126
1127 @Test
laurentlb940dbc52018-03-01 08:07:14 -08001128 public void testRelativeImportPathInIsInvalid() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001129 invalidImportTest("file", SkylarkImport.MUST_HAVE_BZL_EXT_MSG);
John Field1ea7fc32015-12-22 19:37:19 +00001130 }
1131
1132 @Test
1133 public void testInvalidRelativePathBzlExtImplicit() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001134 invalidImportTest("file.bzl", SkylarkImport.INVALID_PATH_SYNTAX);
John Field1ea7fc32015-12-22 19:37:19 +00001135 }
1136
1137 @Test
1138 public void testInvalidRelativePathNoSubdirs() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001139 invalidImportTest("path/to/file.bzl", SkylarkImport.INVALID_PATH_SYNTAX);
John Field1ea7fc32015-12-22 19:37:19 +00001140 }
1141
1142 @Test
1143 public void testInvalidRelativePathInvalidFilename() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001144 invalidImportTest("\tfile.bzl", SkylarkImport.INVALID_PATH_SYNTAX);
John Field1ea7fc32015-12-22 19:37:19 +00001145 }
1146
Miguel Alcon Pinto927f3b22016-08-22 14:21:30 +00001147 private void validAbsoluteImportLabelTest(String importString)
1148 throws SkylarkImportSyntaxException {
John Field1ea7fc32015-12-22 19:37:19 +00001149 validNonAbsoluteImportTest(importString, /*irrelevant*/ "//another/path:BUILD",
1150 /*expected*/ importString);
1151 }
1152
1153 @Test
1154 public void testValidAbsoluteImportLabel() throws Exception {
1155 validAbsoluteImportLabelTest("//some/skylark:file.bzl");
1156 }
1157
1158 @Test
1159 public void testValidAbsoluteImportLabelWithRepo() throws Exception {
1160 validAbsoluteImportLabelTest("@my_repo//some/skylark:file.bzl");
1161 }
1162
1163 @Test
1164 public void testInvalidAbsoluteImportLabel() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001165 invalidImportTest("//some/skylark/:file.bzl", SkylarkImport.INVALID_LABEL_PREFIX);
John Field1ea7fc32015-12-22 19:37:19 +00001166 }
1167
1168 @Test
1169 public void testInvalidAbsoluteImportLabelWithRepo() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001170 invalidImportTest("@my_repo//some/skylark/:file.bzl", SkylarkImport.INVALID_LABEL_PREFIX);
John Field1ea7fc32015-12-22 19:37:19 +00001171 }
1172
1173 @Test
1174 public void testInvalidAbsoluteImportLabelMissingBzlExt() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001175 invalidImportTest("//some/skylark:file", SkylarkImport.MUST_HAVE_BZL_EXT_MSG);
John Field1ea7fc32015-12-22 19:37:19 +00001176 }
1177
1178 @Test
1179 public void testInvalidAbsoluteImportReferencesExternalPkg() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001180 invalidImportTest("//external:file.bzl", SkylarkImport.EXTERNAL_PKG_NOT_ALLOWED_MSG);
John Field1ea7fc32015-12-22 19:37:19 +00001181 }
1182
1183 @Test
1184 public void testValidRelativeImportSimpleLabelInPackageDir() throws Exception {
1185 validNonAbsoluteImportTest(":file.bzl", /*containing*/ "//some/skylark:BUILD",
1186 /*expected*/ "//some/skylark:file.bzl");
1187 }
1188
1189 @Test
1190 public void testValidRelativeImportSimpleLabelInPackageSubdir() throws Exception {
1191 validNonAbsoluteImportTest(":file.bzl", /*containing*/ "//some/path/to:skylark/parent.bzl",
1192 /*expected*/ "//some/path/to:file.bzl");
1193 }
1194
1195 @Test
1196 public void testValidRelativeImportComplexLabelInPackageDir() throws Exception {
1197 validNonAbsoluteImportTest(":subdir/containing/file.bzl", /*containing*/ "//some/skylark:BUILD",
1198 /*expected*/ "//some/skylark:subdir/containing/file.bzl");
1199 }
1200
1201 @Test
1202 public void testValidRelativeImportComplexLabelInPackageSubdir() throws Exception {
1203 validNonAbsoluteImportTest(":subdir/containing/file.bzl",
1204 /*containing*/ "//some/path/to:skylark/parent.bzl",
1205 /*expected*/ "//some/path/to:subdir/containing/file.bzl");
1206 }
1207
1208 @Test
1209 public void testInvalidRelativeImportLabelMissingBzlExt() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001210 invalidImportTest(":file", SkylarkImport.MUST_HAVE_BZL_EXT_MSG);
John Field1ea7fc32015-12-22 19:37:19 +00001211 }
1212
1213 @Test
1214 public void testInvalidRelativeImportLabelSyntax() throws Exception {
laurentlbc6c9b8e2019-04-15 11:26:26 -07001215 invalidImportTest("::file.bzl", SkylarkImport.INVALID_TARGET_PREFIX);
John Field1ea7fc32015-12-22 19:37:19 +00001216 }
1217
1218 @Test
Laurent Le Brun73a98492015-03-17 15:46:19 +00001219 public void testLoadNoSymbol() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001220 setFailFast(false);
laurentlb940dbc52018-03-01 08:07:14 -08001221 parseFileForSkylark("load('//foo/bar:file.bzl')\n");
brandjonfe29c7242018-02-22 16:24:24 -08001222 assertContainsError("expected at least one symbol to load");
Laurent Le Brun73a98492015-03-17 15:46:19 +00001223 }
1224
1225 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001226 public void testLoadOneSymbol() throws Exception {
laurentlb940dbc52018-03-01 08:07:14 -08001227 List<Statement> statements = parseFileForSkylark("load('//foo/bar:file.bzl', 'fun_test')\n");
Ulf Adams89f012d2015-02-26 13:39:28 +00001228 LoadStatement stmt = (LoadStatement) statements.get(0);
laurentlb940dbc52018-03-01 08:07:14 -08001229 assertThat(stmt.getImport().getValue()).isEqualTo("//foo/bar:file.bzl");
laurentlb14c0f402018-11-09 13:59:34 -08001230 assertThat(stmt.getBindings()).hasSize(1);
1231 Identifier sym = stmt.getBindings().get(0).getLocalName();
Jon Brandveinee8b7aa2016-07-28 15:01:26 +00001232 int startOffset = sym.getLocation().getStartOffset();
1233 int endOffset = sym.getLocation().getEndOffset();
cpovirk348ae532019-04-29 15:14:34 -07001234 assertWithMessage("getStartOffset()").that(startOffset).isEqualTo(27);
1235 assertWithMessage("getEndOffset()").that(endOffset).isEqualTo(startOffset + 10);
Ulf Adams89f012d2015-02-26 13:39:28 +00001236 }
1237
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001238 @Test
Laurent Le Brun59f587a2015-03-16 14:51:36 +00001239 public void testLoadOneSymbolWithTrailingComma() throws Exception {
laurentlb940dbc52018-03-01 08:07:14 -08001240 List<Statement> statements = parseFileForSkylark("load('//foo/bar:file.bzl', 'fun_test',)\n");
Laurent Le Brun59f587a2015-03-16 14:51:36 +00001241 LoadStatement stmt = (LoadStatement) statements.get(0);
laurentlb940dbc52018-03-01 08:07:14 -08001242 assertThat(stmt.getImport().getValue()).isEqualTo("//foo/bar:file.bzl");
laurentlb14c0f402018-11-09 13:59:34 -08001243 assertThat(stmt.getBindings()).hasSize(1);
Laurent Le Brun59f587a2015-03-16 14:51:36 +00001244 }
1245
1246 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001247 public void testLoadMultipleSymbols() throws Exception {
laurentlb940dbc52018-03-01 08:07:14 -08001248 List<Statement> statements = parseFileForSkylark("load(':file.bzl', 'foo', 'bar')\n");
Ulf Adams89f012d2015-02-26 13:39:28 +00001249 LoadStatement stmt = (LoadStatement) statements.get(0);
laurentlb940dbc52018-03-01 08:07:14 -08001250 assertThat(stmt.getImport().getValue()).isEqualTo(":file.bzl");
laurentlb14c0f402018-11-09 13:59:34 -08001251 assertThat(stmt.getBindings()).hasSize(2);
Ulf Adams89f012d2015-02-26 13:39:28 +00001252 }
1253
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001254 @Test
brandjon09771fd2017-07-06 08:54:29 -04001255 public void testLoadLabelQuoteError() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001256 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001257 parseFileForSkylark("load(non_quoted, 'a')\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001258 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001259 }
1260
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001261 @Test
brandjon09771fd2017-07-06 08:54:29 -04001262 public void testLoadSymbolQuoteError() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001263 setFailFast(false);
brandjon09771fd2017-07-06 08:54:29 -04001264 parseFileForSkylark("load('label', non_quoted)\n");
1265 assertContainsError("syntax error");
1266 }
1267
1268 @Test
1269 public void testLoadDisallowSameLine() throws Exception {
1270 setFailFast(false);
1271 parseFileForSkylark("load('foo.bzl', 'foo') load('bar.bzl', 'bar')");
Ulf Adamsc708f962015-10-22 12:02:28 +00001272 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001273 }
1274
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001275 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001276 public void testLoadNotAtTopLevel() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001277 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001278 parseFileForSkylark("if 1: load(8)\n");
laurentlb2843ead2017-07-05 07:20:45 -04001279 assertContainsError("syntax error at 'load': expected expression");
Ulf Adams89f012d2015-02-26 13:39:28 +00001280 }
1281
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001282 @Test
Florian Weikert9d659ad2015-07-23 14:44:36 +00001283 public void testLoadAlias() throws Exception {
laurentlb940dbc52018-03-01 08:07:14 -08001284 List<Statement> statements =
1285 parseFileForSkylark("load('//foo/bar:file.bzl', my_alias = 'lawl')\n");
Jon Brandveinee8b7aa2016-07-28 15:01:26 +00001286 LoadStatement stmt = (LoadStatement) statements.get(0);
laurentlb14c0f402018-11-09 13:59:34 -08001287 ImmutableList<LoadStatement.Binding> actualSymbols = stmt.getBindings();
Jon Brandveinee8b7aa2016-07-28 15:01:26 +00001288
1289 assertThat(actualSymbols).hasSize(1);
laurentlb14c0f402018-11-09 13:59:34 -08001290 Identifier sym = actualSymbols.get(0).getLocalName();
Jon Brandveinee8b7aa2016-07-28 15:01:26 +00001291 assertThat(sym.getName()).isEqualTo("my_alias");
1292 int startOffset = sym.getLocation().getStartOffset();
1293 int endOffset = sym.getLocation().getEndOffset();
cpovirk348ae532019-04-29 15:14:34 -07001294 assertWithMessage("getStartOffset()").that(startOffset).isEqualTo(27);
1295 assertWithMessage("getEndOffset()").that(endOffset).isEqualTo(startOffset + 8);
Florian Weikert9d659ad2015-07-23 14:44:36 +00001296 }
1297
1298 @Test
1299 public void testLoadAliasMultiple() throws Exception {
1300 runLoadAliasTestForSymbols(
1301 "my_alias = 'lawl', 'lol', next_alias = 'rofl'", "my_alias", "lol", "next_alias");
1302 }
1303
1304 private void runLoadAliasTestForSymbols(String loadSymbolString, String... expectedSymbols) {
1305 List<Statement> statements =
laurentlb940dbc52018-03-01 08:07:14 -08001306 parseFileForSkylark(String.format("load('//foo/bar:file.bzl', %s)\n", loadSymbolString));
Florian Weikert9d659ad2015-07-23 14:44:36 +00001307 LoadStatement stmt = (LoadStatement) statements.get(0);
laurentlb14c0f402018-11-09 13:59:34 -08001308 ImmutableList<LoadStatement.Binding> actualSymbols = stmt.getBindings();
Florian Weikert9d659ad2015-07-23 14:44:36 +00001309
1310 assertThat(actualSymbols).hasSize(expectedSymbols.length);
1311
1312 List<String> actualSymbolNames = new LinkedList<>();
1313
laurentlb14c0f402018-11-09 13:59:34 -08001314 for (LoadStatement.Binding binding : actualSymbols) {
1315 actualSymbolNames.add(binding.getLocalName().getName());
Florian Weikert9d659ad2015-07-23 14:44:36 +00001316 }
1317
1318 assertThat(actualSymbolNames).containsExactly((Object[]) expectedSymbols);
1319 }
1320
1321 @Test
1322 public void testLoadAliasSyntaxError() throws Exception {
1323 setFailFast(false);
laurentlb940dbc52018-03-01 08:07:14 -08001324 parseFileForSkylark("load('//foo:bzl', test1 = )\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001325 assertContainsError("syntax error at ')': expected string");
Florian Weikert9d659ad2015-07-23 14:44:36 +00001326
laurentlb940dbc52018-03-01 08:07:14 -08001327 parseFileForSkylark("load(':foo.bzl', test2 = 1)\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001328 assertContainsError("syntax error at '1': expected string");
Florian Weikert9d659ad2015-07-23 14:44:36 +00001329
laurentlb940dbc52018-03-01 08:07:14 -08001330 parseFileForSkylark("load(':foo.bzl', test3 = old)\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001331 assertContainsError("syntax error at 'old': expected string");
Florian Weikert9d659ad2015-07-23 14:44:36 +00001332 }
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001333
Florian Weikert9d659ad2015-07-23 14:44:36 +00001334 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001335 public void testParseErrorNotComparison() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001336 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001337 parseFile("2 < not 3");
Ulf Adamsc708f962015-10-22 12:02:28 +00001338 assertContainsError("syntax error at 'not'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001339 }
1340
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001341 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001342 public void testNotWithArithmeticOperatorsBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001343 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001344 parseFile("0 + not 0");
Ulf Adamsc708f962015-10-22 12:02:28 +00001345 assertContainsError("syntax error at 'not'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001346 }
1347
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001348 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001349 public void testOptionalArgBeforeMandatoryArgInFuncDef() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001350 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001351 parseFileForSkylark("def func(a, b = 'a', c):\n return 0\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001352 assertContainsError(
Ulf Adams89f012d2015-02-26 13:39:28 +00001353 "a mandatory positional parameter must not follow an optional parameter");
1354 }
1355
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001356 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001357 public void testKwargBeforePositionalArg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001358 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001359 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001360 "def func(a, b): return a + b",
1361 "func(**{'b': 1}, 'a')");
Ulf Adamsc708f962015-10-22 12:02:28 +00001362 assertContainsError("unexpected tokens after kwarg");
Ulf Adams89f012d2015-02-26 13:39:28 +00001363 }
1364
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001365 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001366 public void testDuplicateKwarg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001367 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001368 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001369 "def func(a, b): return a + b",
1370 "func(**{'b': 1}, **{'a': 2})");
Ulf Adamsc708f962015-10-22 12:02:28 +00001371 assertContainsError("unexpected tokens after kwarg");
Ulf Adams89f012d2015-02-26 13:39:28 +00001372 }
1373
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001374 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001375 public void testUnnamedStar() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001376 setFailFast(false);
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001377 List<Statement> statements = parseFileForSkylark(
1378 "def func(a, b1=2, b2=3, *, c1, d=4, c2): return a + b1 + b2 + c1 + c2 + d\n");
1379 assertThat(statements).hasSize(1);
1380 assertThat(statements.get(0)).isInstanceOf(FunctionDefStatement.class);
1381 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
Laurent Le Brun4baefdc2015-09-04 11:27:46 +00001382 FunctionSignature sig = stmt.getSignature().getSignature();
Francois-Rene Rideau012f7892015-03-31 17:27:01 +00001383 // Note the reordering of optional named-only at the end.
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001384 assertThat(sig.getNames()).isEqualTo(ImmutableList.<String>of(
Francois-Rene Rideau012f7892015-03-31 17:27:01 +00001385 "a", "b1", "b2", "c1", "c2", "d"));
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001386 FunctionSignature.Shape shape = sig.getShape();
1387 assertThat(shape.getMandatoryPositionals()).isEqualTo(1);
1388 assertThat(shape.getOptionalPositionals()).isEqualTo(2);
1389 assertThat(shape.getMandatoryNamedOnly()).isEqualTo(2);
1390 assertThat(shape.getOptionalNamedOnly()).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +00001391 }
1392
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001393 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001394 public void testTopLevelForFails() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001395 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001396 parseFileForSkylark("for i in []: 0\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001397 assertContainsError(
Ulf Adams89f012d2015-02-26 13:39:28 +00001398 "for loops are not allowed on top-level. Put it into a function");
1399 }
1400
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001401 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001402 public void testNestedFunctionFails() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001403 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001404 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001405 "def func(a):",
1406 " def bar(): return 0",
1407 " return bar()",
1408 "");
Ulf Adamsc708f962015-10-22 12:02:28 +00001409 assertContainsError(
Ulf Adams89f012d2015-02-26 13:39:28 +00001410 "nested functions are not allowed. Move the function to top-level");
1411 }
1412
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001413 @Test
Laurent Le Brun3bc8e9a2015-09-10 11:00:37 +00001414 public void testElseWithoutIf() throws Exception {
1415 setFailFast(false);
1416 parseFileForSkylark(
1417 "def func(a):",
1418 // no if
1419 " else: return a");
laurentlbab58a922017-08-22 16:45:28 +02001420 assertContainsError("syntax error at 'else': expected expression");
Yue Gan4866e152016-04-07 13:07:08 +00001421 }
1422
1423 @Test
1424 public void testForElse() throws Exception {
1425 setFailFast(false);
1426 parseFileForSkylark(
1427 "def func(a):",
1428 " for i in range(a):",
1429 " print(i)",
1430 " else: return a");
laurentlbab58a922017-08-22 16:45:28 +02001431 assertContainsError("syntax error at 'else': expected expression");
Laurent Le Brun3bc8e9a2015-09-10 11:00:37 +00001432 }
Florian Weikert1f004e52015-10-16 09:43:48 +00001433
1434 @Test
1435 public void testTryStatementInBuild() throws Exception {
1436 setFailFast(false);
1437 parseFile("try: pass");
laurentlbab58a922017-08-22 16:45:28 +02001438 assertContainsError("'try' not supported, all exceptions are fatal");
Florian Weikert1f004e52015-10-16 09:43:48 +00001439 }
1440
1441 @Test
1442 public void testClassDefinitionInBuild() throws Exception {
1443 setFailFast(false);
laurentlbab58a922017-08-22 16:45:28 +02001444 parseFileWithComments("class test(object): pass");
1445 assertContainsError("keyword 'class' not supported");
Florian Weikert1f004e52015-10-16 09:43:48 +00001446 }
1447
1448 @Test
1449 public void testClassDefinitionInSkylark() throws Exception {
1450 setFailFast(false);
1451 parseFileForSkylark("class test(object): pass");
laurentlbab58a922017-08-22 16:45:28 +02001452 assertContainsError("keyword 'class' not supported");
Florian Weikert1f004e52015-10-16 09:43:48 +00001453 }
1454
1455 @Test
laurentlb2852b362018-11-06 11:36:45 -08001456 public void testArgumentAfterKwargs() throws Exception {
1457 setFailFast(false);
1458 parseFileForSkylark(
1459 "f(",
1460 " 1,",
1461 " *[2],",
1462 " *[3],", // error on this line
1463 ")\n");
laurentlb254a4be2019-03-26 16:35:29 -07001464 assertContainsError(":4:5: *arg argument is misplaced");
laurentlb2852b362018-11-06 11:36:45 -08001465 }
1466
1467 @Test
1468 public void testPositionalArgAfterKeywordArg() throws Exception {
1469 setFailFast(false);
1470 parseFileForSkylark(
1471 "f(",
1472 " 2,",
1473 " a = 4,",
1474 " 3,", // error on this line
1475 ")\n");
laurentlb254a4be2019-03-26 16:35:29 -07001476 assertContainsError(":4:5: positional argument is misplaced (positional arguments come first)");
laurentlb2852b362018-11-06 11:36:45 -08001477 }
nharmata6dbfafe2019-02-05 08:55:07 -08001478
1479 @Test
1480 public void testStringsAreDeduped() throws Exception {
1481 BuildFileAST buildFileAST =
1482 parseFileForSkylarkAsAST("L1 = ['cat', 'dog', 'fish']", "L2 = ['dog', 'fish', 'cat']");
1483 Set<String> uniqueStringInstances = Sets.newIdentityHashSet();
1484 SyntaxTreeVisitor collectAllStringsInStringLiteralsVisitor =
1485 new SyntaxTreeVisitor() {
1486 @Override
1487 public void visit(StringLiteral stringLiteral) {
1488 uniqueStringInstances.add(stringLiteral.getValue());
1489 }
1490 };
1491 collectAllStringsInStringLiteralsVisitor.visit(buildFileAST);
1492 assertThat(uniqueStringInstances).containsExactly("cat", "dog", "fish");
1493 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001494}