blob: e107d1b6bded1966641fc558ae7caa9c29fb9946 [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.assertEquals;
19import static org.junit.Assert.assertFalse;
20import static org.junit.Assert.assertTrue;
21import static org.junit.Assert.fail;
Ulf Adams89f012d2015-02-26 13:39:28 +000022
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +000023import com.google.common.collect.ImmutableList;
John Field1ea7fc32015-12-22 19:37:19 +000024import com.google.devtools.build.lib.cmdline.Label;
Ulf Adams89f012d2015-02-26 13:39:28 +000025import com.google.devtools.build.lib.events.Location;
26import com.google.devtools.build.lib.syntax.DictionaryLiteral.DictionaryEntryLiteral;
Miguel Alcon Pinto927f3b22016-08-22 14:21:30 +000027import com.google.devtools.build.lib.syntax.SkylarkImports.SkylarkImportSyntaxException;
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +000028import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
John Field1ea7fc32015-12-22 19:37:19 +000029import com.google.devtools.build.lib.vfs.PathFragment;
Vladimir Moskva8d610c62016-09-15 14:36:41 +000030import java.util.LinkedList;
31import java.util.List;
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) {
Laurent Le Brun2c52dab2016-11-23 16:50:23 +000043 return BuildFileAST.parseBuildString(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
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000052 /** Parses Skylark code */
53 private List<Statement> parseFileForSkylark(String... input) {
Laurent Le Brun2c52dab2016-11-23 16:50:23 +000054 BuildFileAST ast = BuildFileAST.parseSkylarkString(getEventHandler(), input);
55 ast = ast.validate(new ValidationEnvironment(env), getEventHandler());
56 return ast.getStatements();
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +000057 }
Ulf Adams89f012d2015-02-26 13:39:28 +000058
59 private static String getText(String text, ASTNode node) {
60 return text.substring(node.getLocation().getStartOffset(),
61 node.getLocation().getEndOffset());
62 }
63
64 // helper func for testListLiterals:
65 private static int getIntElem(DictionaryEntryLiteral entry, boolean key) {
66 return ((IntegerLiteral) (key ? entry.getKey() : entry.getValue())).getValue();
67 }
68
69 // helper func for testListLiterals:
70 private static DictionaryEntryLiteral getElem(DictionaryLiteral list, int index) {
71 return list.getEntries().get(index);
72 }
73
74 // helper func for testListLiterals:
75 private static int getIntElem(ListLiteral list, int index) {
76 return ((IntegerLiteral) list.getElements().get(index)).getValue();
77 }
78
79 // helper func for testListLiterals:
80 private static Expression getElem(ListLiteral list, int index) {
81 return list.getElements().get(index);
82 }
83
84 // helper func for testing arguments:
85 private static Expression getArg(FuncallExpression f, int index) {
86 return f.getArguments().get(index).getValue();
87 }
88
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000089 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000090 public void testPrecedence1() throws Exception {
91 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +000092 (BinaryOperatorExpression) parseExpression("'%sx' % 'foo' + 'bar'");
Ulf Adams89f012d2015-02-26 13:39:28 +000093
94 assertEquals(Operator.PLUS, e.getOperator());
95 }
96
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +000097 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +000098 public void testPrecedence2() throws Exception {
99 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000100 (BinaryOperatorExpression) parseExpression("('%sx' % 'foo') + 'bar'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000101 assertEquals(Operator.PLUS, e.getOperator());
102 }
103
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000104 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000105 public void testPrecedence3() throws Exception {
106 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000107 (BinaryOperatorExpression) parseExpression("'%sx' % ('foo' + 'bar')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000108 assertEquals(Operator.PERCENT, e.getOperator());
109 }
110
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000111 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000112 public void testPrecedence4() throws Exception {
113 BinaryOperatorExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000114 (BinaryOperatorExpression) parseExpression("1 + - (2 - 3)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000115 assertEquals(Operator.PLUS, e.getOperator());
116 }
117
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000118 @Test
Laurent Le Brun7bda87e2015-08-24 15:13:53 +0000119 public void testPrecedence5() throws Exception {
120 BinaryOperatorExpression e =
121 (BinaryOperatorExpression) parseExpression("2 * x | y + 1");
122 assertEquals(Operator.PIPE, e.getOperator());
123 }
124
125 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000126 public void testUnaryMinusExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000127 FuncallExpression e = (FuncallExpression) parseExpression("-5");
128 FuncallExpression e2 = (FuncallExpression) parseExpression("- 5");
Ulf Adams89f012d2015-02-26 13:39:28 +0000129
130 assertEquals("-", e.getFunction().getName());
131 assertEquals("-", e2.getFunction().getName());
132
133 assertThat(e.getArguments()).hasSize(1);
134 assertEquals(1, e.getNumPositionalArguments());
135
136 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
137 assertEquals(5, (int) arg0.getValue());
138 }
139
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000140 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000141 public void testFuncallExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000142 FuncallExpression e = (FuncallExpression) parseExpression("foo(1, 2, bar=wiz)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000143
Florian Weikert6f864c32015-07-23 11:26:39 +0000144 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000145 assertEquals("foo", ident.getName());
146
147 assertThat(e.getArguments()).hasSize(3);
148 assertEquals(2, e.getNumPositionalArguments());
149
150 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
151 assertEquals(1, (int) arg0.getValue());
152
153 IntegerLiteral arg1 = (IntegerLiteral) e.getArguments().get(1).getValue();
154 assertEquals(2, (int) arg1.getValue());
155
156 Argument.Passed arg2 = e.getArguments().get(2);
157 assertEquals("bar", arg2.getName());
Florian Weikert6f864c32015-07-23 11:26:39 +0000158 Identifier arg2val = (Identifier) arg2.getValue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000159 assertEquals("wiz", arg2val.getName());
160 }
161
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000162 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000163 public void testMethCallExpr() throws Exception {
164 FuncallExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000165 (FuncallExpression) parseExpression("foo.foo(1, 2, bar=wiz)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000166
Florian Weikert6f864c32015-07-23 11:26:39 +0000167 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000168 assertEquals("foo", ident.getName());
169
170 assertThat(e.getArguments()).hasSize(3);
171 assertEquals(2, e.getNumPositionalArguments());
172
173 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
174 assertEquals(1, (int) arg0.getValue());
175
176 IntegerLiteral arg1 = (IntegerLiteral) e.getArguments().get(1).getValue();
177 assertEquals(2, (int) arg1.getValue());
178
179 Argument.Passed arg2 = e.getArguments().get(2);
180 assertEquals("bar", arg2.getName());
Florian Weikert6f864c32015-07-23 11:26:39 +0000181 Identifier arg2val = (Identifier) arg2.getValue();
Ulf Adams89f012d2015-02-26 13:39:28 +0000182 assertEquals("wiz", arg2val.getName());
183 }
184
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000185 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000186 public void testChainedMethCallExpr() throws Exception {
187 FuncallExpression e =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000188 (FuncallExpression) parseExpression("foo.replace().split(1)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000189
Florian Weikert6f864c32015-07-23 11:26:39 +0000190 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000191 assertEquals("split", ident.getName());
192
193 assertThat(e.getArguments()).hasSize(1);
194 assertEquals(1, e.getNumPositionalArguments());
195
196 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
197 assertEquals(1, (int) arg0.getValue());
198 }
199
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000200 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000201 public void testPropRefExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000202 DotExpression e = (DotExpression) parseExpression("foo.foo");
Ulf Adams89f012d2015-02-26 13:39:28 +0000203
Florian Weikert6f864c32015-07-23 11:26:39 +0000204 Identifier ident = e.getField();
Ulf Adams89f012d2015-02-26 13:39:28 +0000205 assertEquals("foo", ident.getName());
206 }
207
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000208 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000209 public void testStringMethExpr() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000210 FuncallExpression e = (FuncallExpression) parseExpression("'foo'.foo()");
Ulf Adams89f012d2015-02-26 13:39:28 +0000211
Florian Weikert6f864c32015-07-23 11:26:39 +0000212 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000213 assertEquals("foo", ident.getName());
214
215 assertThat(e.getArguments()).isEmpty();
216 }
217
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000218 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000219 public void testStringLiteralOptimizationValue() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000220 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000221 assertEquals("abcdef", l.value);
222 }
223
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000224 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000225 public void testStringLiteralOptimizationToString() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000226 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Michajlo Matijkiw8c539ea2017-02-22 23:02:46 +0000227 assertEquals("\"abcdef\"", l.toString());
Ulf Adams89f012d2015-02-26 13:39:28 +0000228 }
229
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000230 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000231 public void testStringLiteralOptimizationLocation() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000232 StringLiteral l = (StringLiteral) parseExpression("'abc' + 'def'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000233 assertEquals(0, l.getLocation().getStartOffset());
234 assertEquals(13, l.getLocation().getEndOffset());
235 }
236
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000237 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000238 public void testStringLiteralOptimizationDifferentQuote() throws Exception {
Michajlo Matijkiw8c539ea2017-02-22 23:02:46 +0000239 StringLiteral l = (StringLiteral) parseExpression("'abc' + \"def\"");
240 assertEquals(0, l.getLocation().getStartOffset());
241 assertEquals(13, l.getLocation().getEndOffset());
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 testSubstring() throws Exception {
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000246 SliceExpression s = (SliceExpression) parseExpression("'FOO.CC'[:].lower()[1:]");
247 assertThat(((IntegerLiteral) s.getStart()).value).isEqualTo(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000248
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000249 FuncallExpression e = (FuncallExpression) parseExpression(
250 "'FOO.CC'.lower()[1:].startswith('oo')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000251 assertEquals("startswith", e.getFunction().getName());
252 assertThat(e.getArguments()).hasSize(1);
253
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000254 s = (SliceExpression) parseExpression("'FOO.CC'[1:][:2]");
255 assertThat(((IntegerLiteral) s.getEnd()).value).isEqualTo(2);
Florian Weikerte3421962015-12-17 12:46:08 +0000256 }
257
258 @Test
259 public void testSlice() throws Exception {
260 evalSlice("'0123'[:]", Runtime.NONE, Runtime.NONE, 1);
261 evalSlice("'0123'[1:]", 1, Runtime.NONE, 1);
262 evalSlice("'0123'[:3]", Runtime.NONE, 3, 1);
263 evalSlice("'0123'[::]", Runtime.NONE, Runtime.NONE, 1);
264 evalSlice("'0123'[1::]", 1, Runtime.NONE, 1);
265 evalSlice("'0123'[:3:]", Runtime.NONE, 3, 1);
266 evalSlice("'0123'[::-1]", Runtime.NONE, Runtime.NONE, -1);
267 evalSlice("'0123'[1:3:]", 1, 3, 1);
268 evalSlice("'0123'[1::-1]", 1, Runtime.NONE, -1);
269 evalSlice("'0123'[:3:-1]", Runtime.NONE, 3, -1);
270 evalSlice("'0123'[1:3:-1]", 1, 3, -1);
271 }
272
273 private void evalSlice(String statement, Object... expectedArgs) {
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000274 SliceExpression e = (SliceExpression) parseExpression(statement);
275
276 // There is no way to evaluate the expression here, so we rely on string comparison.
277 assertThat(e.getStart().toString()).isEqualTo(printSliceArg(expectedArgs[0]));
278 assertThat(e.getEnd().toString()).isEqualTo(printSliceArg(expectedArgs[1]));
279 assertThat(e.getStep().toString()).isEqualTo(printSliceArg(expectedArgs[2]));
Florian Weikerte3421962015-12-17 12:46:08 +0000280 }
281
282 private String printSliceArg(Object arg) {
283 // The parser sees negative integer constants as FuncallExpressions instead of negative
284 // IntegerLiterals.
285 // Consequently, the string representation of -1 is "-(1)", not "-1".
286 if (arg instanceof Integer) {
287 int value = (int) arg;
288 return value < 0 ? String.format("-(%d)", -value) : String.valueOf(value);
289 }
290 return arg.toString();
Ulf Adams89f012d2015-02-26 13:39:28 +0000291 }
292
293 private void assertLocation(int start, int end, Location location)
294 throws Exception {
295 int actualStart = location.getStartOffset();
296 int actualEnd = location.getEndOffset();
297
298 if (actualStart != start || actualEnd != end) {
299 fail("Expected location = [" + start + ", " + end + "), found ["
300 + actualStart + ", " + actualEnd + ")");
301 }
302 }
303
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000304 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000305 public void testErrorRecovery() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000306 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000307
Laurent Le Brun443aaae2015-04-21 19:49:49 +0000308 String expr = "f(1, [x for foo foo foo foo], 3)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000309 FuncallExpression e = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000310
Ulf Adamsc708f962015-10-22 12:02:28 +0000311 assertContainsError("syntax error at 'foo'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000312
313 // Test that the actual parameters are: (1, $error$, 3):
314
Florian Weikert6f864c32015-07-23 11:26:39 +0000315 Identifier ident = e.getFunction();
Ulf Adams89f012d2015-02-26 13:39:28 +0000316 assertEquals("f", ident.getName());
317
318 assertThat(e.getArguments()).hasSize(3);
319 assertEquals(3, e.getNumPositionalArguments());
320
321 IntegerLiteral arg0 = (IntegerLiteral) e.getArguments().get(0).getValue();
322 assertEquals(1, (int) arg0.getValue());
323
324 Argument.Passed arg1 = e.getArguments().get(1);
Florian Weikert6f864c32015-07-23 11:26:39 +0000325 Identifier arg1val = ((Identifier) arg1.getValue());
Ulf Adams89f012d2015-02-26 13:39:28 +0000326 assertEquals("$error$", arg1val.getName());
327
Laurent Le Brun443aaae2015-04-21 19:49:49 +0000328 assertLocation(5, 29, arg1val.getLocation());
329 assertEquals("[x for foo foo foo foo]", expr.substring(5, 28));
330 assertEquals(30, arg1val.getLocation().getEndLineAndColumn().getColumn());
Ulf Adams89f012d2015-02-26 13:39:28 +0000331
332 IntegerLiteral arg2 = (IntegerLiteral) e.getArguments().get(2).getValue();
333 assertEquals(3, (int) arg2.getValue());
334 }
335
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000336 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000337 public void testDoesntGetStuck() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000338 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000339
340 // Make sure the parser does not get stuck when trying
341 // to parse an expression containing a syntax error.
342 // This usually results in OutOfMemoryError because the
343 // parser keeps filling up the error log.
344 // We need to make sure that we will always advance
345 // in the token stream.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000346 parseExpression("f(1, ], 3)");
347 parseExpression("f(1, ), 3)");
348 parseExpression("[ ) for v in 3)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000349
Ulf Adamsc708f962015-10-22 12:02:28 +0000350 assertContainsError(""); // "" matches any, i.e., there were some events
Ulf Adams89f012d2015-02-26 13:39:28 +0000351 }
352
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000353 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000354 public void testSecondaryLocation() {
355 String expr = "f(1 % 2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000356 FuncallExpression call = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000357 Argument.Passed arg = call.getArguments().get(0);
Francois-Rene Rideauc673a822015-03-02 19:52:39 +0000358 assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
Ulf Adams89f012d2015-02-26 13:39:28 +0000359 }
360
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000361 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000362 public void testPrimaryLocation() {
363 String expr = "f(1 + 2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000364 FuncallExpression call = (FuncallExpression) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000365 Argument.Passed arg = call.getArguments().get(0);
Francois-Rene Rideauc673a822015-03-02 19:52:39 +0000366 assertThat(arg.getLocation().getEndOffset()).isLessThan(call.getLocation().getEndOffset());
Ulf Adams89f012d2015-02-26 13:39:28 +0000367 }
368
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000369 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000370 public void testAssignLocation() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000371 List<Statement> statements = parseFile("a = b;c = d\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000372 Statement statement = statements.get(0);
373 assertEquals(5, statement.getLocation().getEndOffset());
374 }
375
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000376 @Test
Laurent Le Brunc9041bf2015-03-23 15:34:12 +0000377 public void testAssignKeyword() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000378 setFailFast(false);
379 parseExpression("with = 4");
Ulf Adamsc708f962015-10-22 12:02:28 +0000380 assertContainsError("keyword 'with' not supported");
381 assertContainsError("syntax error at 'with': expected expression");
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000382 }
383
384 @Test
Laurent Le Brunee991a12015-06-16 10:56:46 +0000385 public void testBreak() {
386 setFailFast(false);
387 parseExpression("break");
Ulf Adamsc708f962015-10-22 12:02:28 +0000388 assertContainsError("syntax error at 'break': expected expression");
Laurent Le Brunee991a12015-06-16 10:56:46 +0000389 }
390
391 @Test
Laurent Le Brun0ddcba22015-03-23 16:48:01 +0000392 public void testTry() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000393 setFailFast(false);
394 parseExpression("try: 1 + 1");
Ulf Adamsc708f962015-10-22 12:02:28 +0000395 assertContainsError("'try' not supported, all exceptions are fatal");
396 assertContainsError("syntax error at 'try': expected expression");
Laurent Le Brunc9041bf2015-03-23 15:34:12 +0000397 }
398
399 @Test
Laurent Le Brun44ad7fa2016-10-11 12:09:05 +0000400 public void testDel() {
401 setFailFast(false);
402 parseExpression("del d['a']");
403 assertContainsError("'del' not supported, use '.pop()' to delete");
404 }
405
406 @Test
Laurent Le Brun56093892015-03-20 13:01:58 +0000407 public void testTupleAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000408 List<Statement> statements = parseFile("list[0] = 5; dict['key'] = value\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000409 assertThat(statements).hasSize(2);
Laurent Le Brun56093892015-03-20 13:01:58 +0000410 assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
411 assertThat(statements.get(1)).isInstanceOf(AssignmentStatement.class);
412 }
413
414 @Test
415 public void testAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000416 List<Statement> statements = parseFile("a, b = 5\n");
Laurent Le Brun56093892015-03-20 13:01:58 +0000417 assertThat(statements).hasSize(1);
418 assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class);
419 AssignmentStatement assign = (AssignmentStatement) statements.get(0);
420 assertThat(assign.getLValue().getExpression()).isInstanceOf(ListLiteral.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000421 }
422
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000423 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000424 public void testInvalidAssign() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000425 setFailFast(false);
426 parseExpression("1 + (b = c)");
Ulf Adamsc708f962015-10-22 12:02:28 +0000427 assertContainsError("syntax error");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000428 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000429 }
430
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000431 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000432 public void testAugmentedAssign() throws Exception {
Vladimir Moskva71536642016-12-19 13:51:57 +0000433 assertEquals("[x += 1\n]", parseFile("x += 1").toString());
434 assertEquals("[x -= 1\n]", parseFile("x -= 1").toString());
435 assertEquals("[x *= 1\n]", parseFile("x *= 1").toString());
436 assertEquals("[x /= 1\n]", parseFile("x /= 1").toString());
437 assertEquals("[x %= 1\n]", parseFile("x %= 1").toString());
Ulf Adams89f012d2015-02-26 13:39:28 +0000438 }
439
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000440 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000441 public void testPrettyPrintFunctions() throws Exception {
442 assertEquals("[x[1:3]\n]", parseFile("x[1:3]").toString());
Vladimir Moskva8d610c62016-09-15 14:36:41 +0000443 assertEquals("[x[1:3]\n]", parseFile("x[1:3:1]").toString());
444 assertEquals("[x[1:3:2]\n]", parseFile("x[1:3:2]").toString());
445 assertEquals("[x[1::2]\n]", parseFile("x[1::2]").toString());
446 assertEquals("[x[1:]\n]", parseFile("x[1:]").toString());
Ulf Adams89f012d2015-02-26 13:39:28 +0000447 assertEquals("[str[42]\n]", parseFile("str[42]").toString());
Michajlo Matijkiw8c539ea2017-02-22 23:02:46 +0000448 assertEquals("[ctx.new_file(\"hello\")\n]", parseFile("ctx.new_file('hello')").toString());
449 assertEquals("[new_file(\"hello\")\n]", parseFile("new_file(\"hello\")").toString());
Ulf Adams89f012d2015-02-26 13:39:28 +0000450 }
451
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000452 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000453 public void testFuncallLocation() {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000454 List<Statement> statements = parseFile("a(b);c = d\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000455 Statement statement = statements.get(0);
456 assertEquals(4, statement.getLocation().getEndOffset());
457 }
458
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000459 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000460 public void testSpecialFuncallLocation() throws Exception {
461 List<Statement> statements = parseFile("-x\n");
462 assertLocation(0, 3, statements.get(0).getLocation());
463
464 statements = parseFile("arr[15]\n");
465 assertLocation(0, 8, statements.get(0).getLocation());
466
467 statements = parseFile("str[1:12]\n");
468 assertLocation(0, 10, statements.get(0).getLocation());
469 }
470
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000471 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000472 public void testListPositions() throws Exception {
473 String expr = "[0,f(1),2]";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000474 ListLiteral list = (ListLiteral) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000475 assertEquals("[0,f(1),2]", getText(expr, list));
476 assertEquals("0", getText(expr, getElem(list, 0)));
477 assertEquals("f(1)", getText(expr, getElem(list, 1)));
478 assertEquals("2", getText(expr, getElem(list, 2)));
479 }
480
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000481 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000482 public void testDictPositions() throws Exception {
483 String expr = "{1:2,2:f(1),3:4}";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000484 DictionaryLiteral list = (DictionaryLiteral) parseExpression(expr);
Ulf Adams89f012d2015-02-26 13:39:28 +0000485 assertEquals("{1:2,2:f(1),3:4}", getText(expr, list));
486 assertEquals("1:2", getText(expr, getElem(list, 0)));
487 assertEquals("2:f(1)", getText(expr, getElem(list, 1)));
488 assertEquals("3:4", getText(expr, getElem(list, 2)));
489 }
490
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000491 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000492 public void testArgumentPositions() throws Exception {
493 String stmt = "f(0,g(1,2),2)";
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000494 FuncallExpression f = (FuncallExpression) parseExpression(stmt);
Ulf Adams89f012d2015-02-26 13:39:28 +0000495 assertEquals(stmt, getText(stmt, f));
496 assertEquals("0", getText(stmt, getArg(f, 0)));
497 assertEquals("g(1,2)", getText(stmt, getArg(f, 1)));
498 assertEquals("2", getText(stmt, getArg(f, 2)));
499 }
500
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000501 @Test
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000502 public void testForBreakContinue() throws Exception {
503 List<Statement> file = parseFileForSkylark(
504 "def foo():",
505 " for i in [1, 2]:",
506 " break",
Laurent Le Brun7d6a3812015-10-26 12:07:12 +0000507 " continue",
508 " break");
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000509 assertThat(file).hasSize(1);
510 List<Statement> body = ((FunctionDefStatement) file.get(0)).getStatements();
511 assertThat(body).hasSize(1);
512
513 List<Statement> loop = ((ForStatement) body.get(0)).block();
Laurent Le Brun7d6a3812015-10-26 12:07:12 +0000514 assertThat(loop).hasSize(3);
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000515
Laurent Le Brun7d6a3812015-10-26 12:07:12 +0000516 assertThat(((FlowStatement) loop.get(0)).getKind()).isEqualTo(FlowStatement.Kind.BREAK);
Laurent Le Bruna3c25a62016-10-26 10:59:09 +0000517 assertLocation(34, 39, loop.get(0).getLocation());
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000518
Laurent Le Brun7d6a3812015-10-26 12:07:12 +0000519 assertThat(((FlowStatement) loop.get(1)).getKind()).isEqualTo(FlowStatement.Kind.CONTINUE);
Laurent Le Bruna3c25a62016-10-26 10:59:09 +0000520 assertLocation(44, 52, loop.get(1).getLocation());
Laurent Le Brun7d6a3812015-10-26 12:07:12 +0000521
522 assertThat(((FlowStatement) loop.get(2)).getKind()).isEqualTo(FlowStatement.Kind.BREAK);
523 assertLocation(57, 62, loop.get(2).getLocation());
Laurent Le Brund412c8f2015-06-16 11:12:54 +0000524 }
525
526 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000527 public void testListLiterals1() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000528 ListLiteral list = (ListLiteral) parseExpression("[0,1,2]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000529 assertFalse(list.isTuple());
530 assertThat(list.getElements()).hasSize(3);
531 assertFalse(list.isTuple());
532 for (int i = 0; i < 3; ++i) {
533 assertEquals(i, getIntElem(list, i));
534 }
535 }
536
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000537 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000538 public void testTupleLiterals2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000539 ListLiteral tuple = (ListLiteral) parseExpression("(0,1,2)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000540 assertTrue(tuple.isTuple());
541 assertThat(tuple.getElements()).hasSize(3);
542 assertTrue(tuple.isTuple());
543 for (int i = 0; i < 3; ++i) {
544 assertEquals(i, getIntElem(tuple, i));
545 }
546 }
547
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000548 @Test
Laurent Le Brun56093892015-03-20 13:01:58 +0000549 public void testTupleWithoutParens() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000550 ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2");
Laurent Le Brun56093892015-03-20 13:01:58 +0000551 assertTrue(tuple.isTuple());
552 assertThat(tuple.getElements()).hasSize(3);
553 assertTrue(tuple.isTuple());
554 for (int i = 0; i < 3; ++i) {
555 assertEquals(i, getIntElem(tuple, i));
556 }
557 }
558
559 @Test
Laurent Le Brunb639ca82017-01-17 11:18:23 +0000560 public void testTupleWithTrailingComma() throws Exception {
561 setFailFast(false);
562
563 // Unlike Python, we require parens here.
564 parseExpression("0, 1, 2, 3,");
565 assertContainsError("Trailing comma");
566 clearEvents();
567
568 parseExpression("1 + 2,");
569 assertContainsError("Trailing comma");
570 clearEvents();
571
572 ListLiteral tuple = (ListLiteral) parseExpression("(0, 1, 2, 3,)");
Laurent Le Brun56093892015-03-20 13:01:58 +0000573 assertTrue(tuple.isTuple());
574 assertThat(tuple.getElements()).hasSize(4);
575 assertTrue(tuple.isTuple());
576 for (int i = 0; i < 4; ++i) {
577 assertEquals(i, getIntElem(tuple, i));
578 }
579 }
580
581 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000582 public void testTupleLiterals3() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000583 ListLiteral emptyTuple = (ListLiteral) parseExpression("()");
Ulf Adams89f012d2015-02-26 13:39:28 +0000584 assertTrue(emptyTuple.isTuple());
585 assertThat(emptyTuple.getElements()).isEmpty();
586 }
587
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000588 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000589 public void testTupleLiterals4() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000590 ListLiteral singletonTuple = (ListLiteral) parseExpression("(42,)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000591 assertTrue(singletonTuple.isTuple());
592 assertThat(singletonTuple.getElements()).hasSize(1);
593 assertEquals(42, getIntElem(singletonTuple, 0));
594 }
595
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000596 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000597 public void testTupleLiterals5() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000598 IntegerLiteral intLit = (IntegerLiteral) parseExpression("(42)"); // not a tuple!
Ulf Adams89f012d2015-02-26 13:39:28 +0000599 assertEquals(42, (int) intLit.getValue());
600 }
601
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000602 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000603 public void testListLiterals6() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000604 ListLiteral emptyList = (ListLiteral) parseExpression("[]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000605 assertFalse(emptyList.isTuple());
606 assertThat(emptyList.getElements()).isEmpty();
607 }
608
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000609 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000610 public void testListLiterals7() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000611 ListLiteral singletonList = (ListLiteral) parseExpression("[42,]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000612 assertFalse(singletonList.isTuple());
613 assertThat(singletonList.getElements()).hasSize(1);
614 assertEquals(42, getIntElem(singletonList, 0));
615 }
616
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000617 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000618 public void testListLiterals8() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000619 ListLiteral singletonList = (ListLiteral) parseExpression("[42]"); // a singleton
Ulf Adams89f012d2015-02-26 13:39:28 +0000620 assertFalse(singletonList.isTuple());
621 assertThat(singletonList.getElements()).hasSize(1);
622 assertEquals(42, getIntElem(singletonList, 0));
623 }
624
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000625 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000626 public void testDictionaryLiterals() throws Exception {
627 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000628 (DictionaryLiteral) parseExpression("{1:42}"); // a singleton dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000629 assertThat(dictionaryList.getEntries()).hasSize(1);
630 DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
631 assertEquals(1, getIntElem(tuple, true));
632 assertEquals(42, getIntElem(tuple, false));
633 }
634
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000635 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000636 public void testDictionaryLiterals1() throws Exception {
637 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000638 (DictionaryLiteral) parseExpression("{}"); // an empty dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000639 assertThat(dictionaryList.getEntries()).isEmpty();
640 }
641
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000642 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000643 public void testDictionaryLiterals2() throws Exception {
644 DictionaryLiteral dictionaryList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000645 (DictionaryLiteral) parseExpression("{1:42,}"); // a singleton dictionary
Ulf Adams89f012d2015-02-26 13:39:28 +0000646 assertThat(dictionaryList.getEntries()).hasSize(1);
647 DictionaryEntryLiteral tuple = getElem(dictionaryList, 0);
648 assertEquals(1, getIntElem(tuple, true));
649 assertEquals(42, getIntElem(tuple, false));
650 }
651
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000652 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000653 public void testDictionaryLiterals3() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000654 DictionaryLiteral dictionaryList = (DictionaryLiteral) parseExpression("{1:42,2:43,3:44}");
Ulf Adams89f012d2015-02-26 13:39:28 +0000655 assertThat(dictionaryList.getEntries()).hasSize(3);
656 for (int i = 0; i < 3; i++) {
657 DictionaryEntryLiteral tuple = getElem(dictionaryList, i);
658 assertEquals(i + 1, getIntElem(tuple, true));
659 assertEquals(i + 42, getIntElem(tuple, false));
660 }
661 }
662
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000663 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000664 public void testListLiterals9() throws Exception {
665 ListLiteral singletonList =
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000666 (ListLiteral) parseExpression("[ abi + opt_level + \'/include\' ]");
Ulf Adams89f012d2015-02-26 13:39:28 +0000667 assertFalse(singletonList.isTuple());
668 assertThat(singletonList.getElements()).hasSize(1);
669 }
670
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000671 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000672 public void testListComprehensionSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000673 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000674
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000675 parseExpression("[x for");
Ulf Adamsc708f962015-10-22 12:02:28 +0000676 assertContainsError("syntax error at 'newline'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000677 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000678
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000679 parseExpression("[x for x");
Ulf Adamsc708f962015-10-22 12:02:28 +0000680 assertContainsError("syntax error at 'newline'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000681 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000682
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000683 parseExpression("[x for x in");
Ulf Adamsc708f962015-10-22 12:02:28 +0000684 assertContainsError("syntax error at 'newline'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000685 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000686
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000687 parseExpression("[x for x in []");
Ulf Adamsc708f962015-10-22 12:02:28 +0000688 assertContainsError("syntax error at 'newline'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000689 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000690
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000691 parseExpression("[x for x for y in ['a']]");
Ulf Adamsc708f962015-10-22 12:02:28 +0000692 assertContainsError("syntax error at 'for'");
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000693 clearEvents();
Ulf Adams89f012d2015-02-26 13:39:28 +0000694 }
695
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000696 @Test
Laurent Le Brun52021662015-05-18 09:28:26 +0000697 public void testListComprehensionEmptyList() throws Exception {
698 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
699 "['foo/%s.java' % x for x in []]")).getClauses();
700 assertThat(clauses).hasSize(1);
701 assertThat(clauses.get(0).getExpression().toString()).isEqualTo("[]");
702 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
703 }
704
705 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000706 public void testListComprehension() throws Exception {
Laurent Le Brun52021662015-05-18 09:28:26 +0000707 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
708 "['foo/%s.java' % x for x in ['bar', 'wiz', 'quux']]")).getClauses();
709 assertThat(clauses).hasSize(1);
710 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
711 assertThat(clauses.get(0).getExpression()).isInstanceOf(ListLiteral.class);
712 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000713
Laurent Le Brun52021662015-05-18 09:28:26 +0000714 @Test
715 public void testForForListComprehension() throws Exception {
716 List<ListComprehension.Clause> clauses = ((ListComprehension) parseExpression(
717 "['%s/%s.java' % (x, y) for x in ['foo', 'bar'] for y in list]")).getClauses();
718 assertThat(clauses).hasSize(2);
719 assertThat(clauses.get(0).getLValue().getExpression().toString()).isEqualTo("x");
720 assertThat(clauses.get(0).getExpression()).isInstanceOf(ListLiteral.class);
721 assertThat(clauses.get(1).getLValue().getExpression().toString()).isEqualTo("y");
Florian Weikert6f864c32015-07-23 11:26:39 +0000722 assertThat(clauses.get(1).getExpression()).isInstanceOf(Identifier.class);
Ulf Adams89f012d2015-02-26 13:39:28 +0000723 }
724
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000725 @Test
Laurent Le Brun9060e162015-04-02 10:07:28 +0000726 public void testParserRecovery() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000727 setFailFast(false);
728 List<Statement> statements = parseFileForSkylark(
Laurent Le Brun9060e162015-04-02 10:07:28 +0000729 "def foo():",
Laurent Le Brune3f4ed72015-05-08 14:47:26 +0000730 " a = 2 for 4", // parse error
Laurent Le Brun9060e162015-04-02 10:07:28 +0000731 " b = [3, 4]",
732 "",
733 "d = 4 ada", // parse error
734 "",
735 "def bar():",
736 " a = [3, 4]",
737 " b = 2 + + 5", // parse error
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000738 "");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000739
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000740 assertThat(getEventCollector()).hasSize(3);
Ulf Adamsc708f962015-10-22 12:02:28 +0000741 assertContainsError("syntax error at 'for': expected newline");
742 assertContainsError("syntax error at 'ada': expected newline");
743 assertContainsError("syntax error at '+': expected expression");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000744 assertThat(statements).hasSize(3);
745 }
746
747 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000748 public void testParserContainsErrorsIfSyntaxException() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000749 setFailFast(false);
750 parseExpression("'foo' %%");
Ulf Adamsc708f962015-10-22 12:02:28 +0000751 assertContainsError("syntax error at '%'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000752 }
753
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000754 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000755 public void testParserDoesNotContainErrorsIfSuccess() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000756 parseExpression("'foo'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000757 }
758
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000759 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000760 public void testParserContainsErrors() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000761 setFailFast(false);
Francois-Rene Rideau89312fb2015-09-10 18:53:03 +0000762 parseFile("+");
Ulf Adamsc708f962015-10-22 12:02:28 +0000763 assertContainsError("syntax error at '+'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000764 }
765
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000766 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000767 public void testSemicolonAndNewline() throws Exception {
768 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000769 "foo='bar'; foo(bar)",
770 "",
771 "foo='bar'; foo(bar)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000772 assertThat(stmts).hasSize(4);
773 }
774
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000775 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000776 public void testSemicolonAndNewline2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000777 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000778 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000779 "foo='foo' error(bar)",
780 "",
781 "");
Ulf Adamsc708f962015-10-22 12:02:28 +0000782 assertContainsError("syntax error at 'error'");
Laurent Le Brun9060e162015-04-02 10:07:28 +0000783 assertThat(stmts).hasSize(1);
Ulf Adams89f012d2015-02-26 13:39:28 +0000784 }
785
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000786 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000787 public void testExprAsStatement() throws Exception {
788 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000789 "li = []",
790 "li.append('a.c')",
791 "\"\"\" string comment \"\"\"",
792 "foo(bar)");
Ulf Adams89f012d2015-02-26 13:39:28 +0000793 assertThat(stmts).hasSize(4);
794 }
795
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000796 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000797 public void testParseBuildFileWithSingeRule() throws Exception {
798 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000799 "genrule(name = 'foo',",
800 " srcs = ['input.csv'],",
801 " outs = [ 'result.txt',",
802 " 'result.log'],",
803 " cmd = 'touch result.txt result.log')",
804 "");
Ulf Adams89f012d2015-02-26 13:39:28 +0000805 assertThat(stmts).hasSize(1);
806 }
807
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000808 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000809 public void testParseBuildFileWithMultipleRules() throws Exception {
810 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000811 "genrule(name = 'foo',",
812 " srcs = ['input.csv'],",
813 " outs = [ 'result.txt',",
814 " 'result.log'],",
815 " cmd = 'touch result.txt result.log')",
816 "",
817 "genrule(name = 'bar',",
818 " srcs = ['input.csv'],",
819 " outs = [ 'graph.svg'],",
820 " cmd = 'touch graph.svg')");
Ulf Adams89f012d2015-02-26 13:39:28 +0000821 assertThat(stmts).hasSize(2);
822 }
823
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000824 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000825 public void testParseBuildFileWithComments() throws Exception {
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000826 BuildFileAST result = parseFileWithComments(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000827 "# Test BUILD file",
828 "# with multi-line comment",
829 "",
830 "genrule(name = 'foo',",
831 " srcs = ['input.csv'],",
832 " outs = [ 'result.txt',",
833 " 'result.log'],",
834 " cmd = 'touch result.txt result.log')");
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000835 assertThat(result.getStatements()).hasSize(1);
836 assertThat(result.getComments()).hasSize(2);
Ulf Adams89f012d2015-02-26 13:39:28 +0000837 }
838
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000839 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000840 public void testParseBuildFileWithManyComments() throws Exception {
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000841 BuildFileAST result = parseFileWithComments(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000842 "# 1",
843 "# 2",
844 "",
845 "# 4 ",
846 "# 5",
847 "#", // 6 - find empty comment for syntax highlighting
848 "# 7 ",
849 "# 8",
850 "genrule(name = 'foo',",
851 " srcs = ['input.csv'],",
852 " # 11",
853 " outs = [ 'result.txt',",
854 " 'result.log'], # 13",
855 " cmd = 'touch result.txt result.log')",
856 "# 15");
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000857 assertThat(result.getStatements()).hasSize(1); // Single genrule
Ulf Adams89f012d2015-02-26 13:39:28 +0000858 StringBuilder commentLines = new StringBuilder();
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000859 for (Comment comment : result.getComments()) {
Ulf Adams89f012d2015-02-26 13:39:28 +0000860 // Comments start and end on the same line
861 assertEquals(comment.getLocation().getStartLineAndColumn().getLine() + " ends on "
862 + comment.getLocation().getEndLineAndColumn().getLine(),
863 comment.getLocation().getStartLineAndColumn().getLine(),
864 comment.getLocation().getEndLineAndColumn().getLine());
865 commentLines.append('(');
866 commentLines.append(comment.getLocation().getStartLineAndColumn().getLine());
867 commentLines.append(',');
868 commentLines.append(comment.getLocation().getStartLineAndColumn().getColumn());
869 commentLines.append(") ");
870 }
871 assertWithMessage("Found: " + commentLines)
Laurent Le Brun8e965b82016-08-03 11:50:24 +0000872 .that(result.getComments().size()).isEqualTo(10); // One per '#'
Ulf Adams89f012d2015-02-26 13:39:28 +0000873 }
874
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000875 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000876 public void testMissingComma() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000877 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000878 // Regression test.
879 // Note: missing comma after name='foo'
880 parseFile("genrule(name = 'foo'\n"
881 + " srcs = ['in'])");
Ulf Adamsc708f962015-10-22 12:02:28 +0000882 assertContainsError("syntax error at 'srcs'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000883 }
884
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000885 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000886 public void testDoubleSemicolon() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000887 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000888 // Regression test.
889 parseFile("x = 1; ; x = 2;");
Ulf Adamsc708f962015-10-22 12:02:28 +0000890 assertContainsError("syntax error at ';'");
Ulf Adams89f012d2015-02-26 13:39:28 +0000891 }
892
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000893 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000894 public void testFunctionDefinitionErrorRecovery() throws Exception {
895 // Parser skips over entire function definitions, and reports a meaningful
896 // error.
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000897 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000898 List<Statement> stmts = parseFile(
899 "x = 1;\n"
900 + "def foo(x, y, **z):\n"
901 + " # a comment\n"
902 + " x = 2\n"
903 + " foo(bar)\n"
904 + " return z\n"
905 + "x = 3");
906 assertThat(stmts).hasSize(2);
907 }
908
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000909 @Test
Laurent Le Brun5f674452015-03-17 19:29:13 +0000910 public void testDefSingleLine() throws Exception {
911 List<Statement> statements = parseFileForSkylark(
912 "def foo(): x = 1; y = 2\n");
913 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
914 assertThat(stmt.getStatements()).hasSize(2);
915 }
916
917 @Test
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000918 public void testPass() throws Exception {
919 List<Statement> statements = parseFileForSkylark("pass\n");
920 assertThat(statements).isEmpty();
921 }
922
923 @Test
924 public void testForPass() throws Exception {
925 List<Statement> statements = parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000926 "def foo():",
927 " pass\n");
Laurent Le Brun0942ee92015-03-17 20:22:16 +0000928
929 assertThat(statements).hasSize(1);
930 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
931 assertThat(stmt.getStatements()).isEmpty();
932 }
933
934 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000935 public void testSkipIfBlockFail() throws Exception {
936 // Do not parse 'if' blocks, when parsePython is not set
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000937 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +0000938 List<Statement> stmts = parseFile(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000939 "x = 1;",
940 "if x == 1:",
941 " x = 2",
942 "x = 3;\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000943 assertThat(stmts).hasSize(2);
Ulf Adamsc708f962015-10-22 12:02:28 +0000944 assertContainsError("This is not supported in BUILD files");
Ulf Adams89f012d2015-02-26 13:39:28 +0000945 }
946
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000947 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000948 public void testForLoopMultipleVariables() throws Exception {
Laurent Le Brun185392d2015-03-20 14:41:25 +0000949 List<Statement> stmts1 = parseFile("[ i for i, j, k in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000950 assertThat(stmts1).hasSize(1);
951
Laurent Le Brun185392d2015-03-20 14:41:25 +0000952 List<Statement> stmts2 = parseFile("[ i for i, j in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000953 assertThat(stmts2).hasSize(1);
954
Laurent Le Brun185392d2015-03-20 14:41:25 +0000955 List<Statement> stmts3 = parseFile("[ i for (i, j, k) in [(1, 2, 3)] ]\n");
Ulf Adams89f012d2015-02-26 13:39:28 +0000956 assertThat(stmts3).hasSize(1);
957 }
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000958
Googlercc0d9952015-08-10 12:01:34 +0000959 @Test
960 public void testReturnNone() throws Exception {
961 List<Statement> defNone = parseFileForSkylark("def foo():", " return None\n");
962 assertThat(defNone).hasSize(1);
963
964 List<Statement> bodyNone = ((FunctionDefStatement) defNone.get(0)).getStatements();
965 assertThat(bodyNone).hasSize(1);
966
967 ReturnStatement returnNone = (ReturnStatement) bodyNone.get(0);
968 assertEquals("None", ((Identifier) returnNone.getReturnExpression()).getName());
969
970 int i = 0;
971 for (String end : new String[]{";", "\n"}) {
972 List<Statement> defNoExpr = parseFileForSkylark("def bar" + i + "():", " return" + end);
973 i++;
974 assertThat(defNoExpr).hasSize(1);
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000975
Googlercc0d9952015-08-10 12:01:34 +0000976 List<Statement> bodyNoExpr = ((FunctionDefStatement) defNoExpr.get(0)).getStatements();
977 assertThat(bodyNoExpr).hasSize(1);
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +0000978
Googlercc0d9952015-08-10 12:01:34 +0000979 ReturnStatement returnNoExpr = (ReturnStatement) bodyNoExpr.get(0);
980 Identifier none = (Identifier) returnNoExpr.getReturnExpression();
981 assertEquals("None", none.getName());
982 assertLocation(
983 returnNoExpr.getLocation().getStartOffset(),
984 returnNoExpr.getLocation().getEndOffset(),
985 none.getLocation());
986 }
987 }
Ulf Adams89f012d2015-02-26 13:39:28 +0000988
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000989 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000990 public void testForLoopBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000991 setFailFast(false);
Laurent Le Brun185392d2015-03-20 14:41:25 +0000992 parseFile("[1 for (a, b, c in var]\n");
Ulf Adamsc708f962015-10-22 12:02:28 +0000993 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +0000994 }
995
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +0000996 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +0000997 public void testForLoopBadSyntax2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +0000998 setFailFast(false);
Laurent Le Brun185392d2015-03-20 14:41:25 +0000999 parseFile("[1 for in var]\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001000 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001001 }
1002
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001003 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001004 public void testFunCallBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001005 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001006 parseFile("f(1,\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001007 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001008 }
1009
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001010 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001011 public void testFunCallBadSyntax2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001012 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001013 parseFile("f(1, 5, ,)\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001014 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001015 }
1016
Florian Weikert308c0bf2015-07-10 10:46:56 +00001017 @Test
Miguel Alcon Pinto927f3b22016-08-22 14:21:30 +00001018 public void testValidAbsoluteImportPath() throws SkylarkImportSyntaxException {
John Field9201fda2015-12-30 19:30:34 +00001019 String importString = "/some/skylark/file";
John Field1ea7fc32015-12-22 19:37:19 +00001020 List<Statement> statements =
John Field9201fda2015-12-30 19:30:34 +00001021 parseFileForSkylark("load('" + importString + "', 'fun_test')\n");
John Field1ea7fc32015-12-22 19:37:19 +00001022 LoadStatement stmt = (LoadStatement) statements.get(0);
Laurent Le Brun7b1708c2016-10-13 10:05:12 +00001023 SkylarkImport imp = SkylarkImports.create(stmt.getImport().getValue());
John Field9201fda2015-12-30 19:30:34 +00001024
1025 assertThat(imp.getImportString()).named("getImportString()").isEqualTo("/some/skylark/file");
1026 assertThat(imp.hasAbsolutePath()).named("hasAbsolutePath()").isTrue();
1027 assertThat(imp.getAbsolutePath()).named("getAbsolutePath()")
nharmatab4060b62017-04-04 17:11:39 +00001028 .isEqualTo(PathFragment.create("/some/skylark/file.bzl"));
John Field9201fda2015-12-30 19:30:34 +00001029
Laurent Le Brun7b1708c2016-10-13 10:05:12 +00001030 int startOffset = stmt.getImport().getLocation().getStartOffset();
1031 int endOffset = stmt.getImport().getLocation().getEndOffset();
John Field9201fda2015-12-30 19:30:34 +00001032 assertThat(startOffset).named("getStartOffset()").isEqualTo(5);
1033 assertThat(endOffset).named("getEndOffset()")
1034 .isEqualTo(startOffset + importString.length() + 2);
John Field1ea7fc32015-12-22 19:37:19 +00001035 }
1036
1037 private void validNonAbsoluteImportTest(String importString, String containingFileLabelString,
Miguel Alcon Pinto927f3b22016-08-22 14:21:30 +00001038 String expectedLabelString) throws SkylarkImportSyntaxException {
John Field1ea7fc32015-12-22 19:37:19 +00001039 List<Statement> statements =
1040 parseFileForSkylark("load('" + importString + "', 'fun_test')\n");
1041 LoadStatement stmt = (LoadStatement) statements.get(0);
Laurent Le Brun7b1708c2016-10-13 10:05:12 +00001042 SkylarkImport imp = SkylarkImports.create(stmt.getImport().getValue());
John Field9201fda2015-12-30 19:30:34 +00001043
1044 assertThat(imp.getImportString()).named("getImportString()").isEqualTo(importString);
1045 assertThat(imp.hasAbsolutePath()).named("hasAbsolutePath()").isFalse();
1046
John Field1ea7fc32015-12-22 19:37:19 +00001047 Label containingFileLabel = Label.parseAbsoluteUnchecked(containingFileLabelString);
John Field9201fda2015-12-30 19:30:34 +00001048 assertThat(imp.getLabel(containingFileLabel)).named("containingFileLabel()")
Michajlo Matijkiw8c539ea2017-02-22 23:02:46 +00001049 .isEqualTo(Label.parseAbsoluteUnchecked(expectedLabelString));
John Field9201fda2015-12-30 19:30:34 +00001050
Laurent Le Brun7b1708c2016-10-13 10:05:12 +00001051 int startOffset = stmt.getImport().getLocation().getStartOffset();
1052 int endOffset = stmt.getImport().getLocation().getEndOffset();
John Field9201fda2015-12-30 19:30:34 +00001053 assertThat(startOffset).named("getStartOffset()").isEqualTo(5);
1054 assertThat(endOffset).named("getEndOffset()")
1055 .isEqualTo(startOffset + importString.length() + 2);
John Field1ea7fc32015-12-22 19:37:19 +00001056 }
1057
1058 private void invalidImportTest(String importString, String expectedMsg) {
Florian Weikert308c0bf2015-07-10 10:46:56 +00001059 setFailFast(false);
Michajlo Matijkiw8c539ea2017-02-22 23:02:46 +00001060 parseFileForSkylark("load('" + importString + "', 'fun_test')\n");
Jon Brandveinee8b7aa2016-07-28 15:01:26 +00001061 assertContainsError(expectedMsg);
Florian Weikert308c0bf2015-07-10 10:46:56 +00001062 }
1063
1064 @Test
John Field1ea7fc32015-12-22 19:37:19 +00001065 public void testValidRelativeImportPathInPackageDir() throws Exception {
1066 validNonAbsoluteImportTest("file", /*containing*/ "//some/skylark:BUILD",
1067 /*expected*/ "//some/skylark:file.bzl");
Florian Weikert308c0bf2015-07-10 10:46:56 +00001068 }
1069
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001070 @Test
John Field1ea7fc32015-12-22 19:37:19 +00001071 public void testValidRelativeImportPathInPackageSubdir() throws Exception {
1072 validNonAbsoluteImportTest("file", /*containing*/ "//some/path/to:skylark/parent.bzl",
1073 /*expected*/ "//some/path/to:skylark/file.bzl");
1074 }
1075
1076 @Test
1077 public void testInvalidRelativePathBzlExtImplicit() throws Exception {
Laurent Le Brun226321c2016-03-31 09:56:49 +00001078 invalidImportTest("file.bzl", SkylarkImports.INVALID_PATH_SYNTAX);
John Field1ea7fc32015-12-22 19:37:19 +00001079 }
1080
1081 @Test
1082 public void testInvalidRelativePathNoSubdirs() throws Exception {
Laurent Le Brun226321c2016-03-31 09:56:49 +00001083 invalidImportTest("path/to/file", SkylarkImports.INVALID_PATH_SYNTAX);
John Field1ea7fc32015-12-22 19:37:19 +00001084 }
1085
1086 @Test
1087 public void testInvalidRelativePathInvalidFilename() throws Exception {
1088 invalidImportTest("\tfile", SkylarkImports.INVALID_FILENAME_PREFIX);
1089 }
1090
Miguel Alcon Pinto927f3b22016-08-22 14:21:30 +00001091 private void validAbsoluteImportLabelTest(String importString)
1092 throws SkylarkImportSyntaxException {
John Field1ea7fc32015-12-22 19:37:19 +00001093 validNonAbsoluteImportTest(importString, /*irrelevant*/ "//another/path:BUILD",
1094 /*expected*/ importString);
1095 }
1096
1097 @Test
1098 public void testValidAbsoluteImportLabel() throws Exception {
1099 validAbsoluteImportLabelTest("//some/skylark:file.bzl");
1100 }
1101
1102 @Test
1103 public void testValidAbsoluteImportLabelWithRepo() throws Exception {
1104 validAbsoluteImportLabelTest("@my_repo//some/skylark:file.bzl");
1105 }
1106
1107 @Test
1108 public void testInvalidAbsoluteImportLabel() throws Exception {
1109 invalidImportTest("//some/skylark/:file.bzl", SkylarkImports.INVALID_LABEL_PREFIX);
1110 }
1111
1112 @Test
1113 public void testInvalidAbsoluteImportLabelWithRepo() throws Exception {
1114 invalidImportTest("@my_repo//some/skylark/:file.bzl",
1115 SkylarkImports.INVALID_LABEL_PREFIX);
1116 }
1117
1118 @Test
1119 public void testInvalidAbsoluteImportLabelMissingBzlExt() throws Exception {
1120 invalidImportTest("//some/skylark:file", SkylarkImports.MUST_HAVE_BZL_EXT_MSG);
1121 }
1122
1123 @Test
1124 public void testInvalidAbsoluteImportReferencesExternalPkg() throws Exception {
1125 invalidImportTest("//external:file.bzl", SkylarkImports.EXTERNAL_PKG_NOT_ALLOWED_MSG);
1126 }
1127
1128 @Test
1129 public void testValidRelativeImportSimpleLabelInPackageDir() throws Exception {
1130 validNonAbsoluteImportTest(":file.bzl", /*containing*/ "//some/skylark:BUILD",
1131 /*expected*/ "//some/skylark:file.bzl");
1132 }
1133
1134 @Test
1135 public void testValidRelativeImportSimpleLabelInPackageSubdir() throws Exception {
1136 validNonAbsoluteImportTest(":file.bzl", /*containing*/ "//some/path/to:skylark/parent.bzl",
1137 /*expected*/ "//some/path/to:file.bzl");
1138 }
1139
1140 @Test
1141 public void testValidRelativeImportComplexLabelInPackageDir() throws Exception {
1142 validNonAbsoluteImportTest(":subdir/containing/file.bzl", /*containing*/ "//some/skylark:BUILD",
1143 /*expected*/ "//some/skylark:subdir/containing/file.bzl");
1144 }
1145
1146 @Test
1147 public void testValidRelativeImportComplexLabelInPackageSubdir() throws Exception {
1148 validNonAbsoluteImportTest(":subdir/containing/file.bzl",
1149 /*containing*/ "//some/path/to:skylark/parent.bzl",
1150 /*expected*/ "//some/path/to:subdir/containing/file.bzl");
1151 }
1152
1153 @Test
1154 public void testInvalidRelativeImportLabelMissingBzlExt() throws Exception {
1155 invalidImportTest(":file", SkylarkImports.MUST_HAVE_BZL_EXT_MSG);
1156 }
1157
1158 @Test
1159 public void testInvalidRelativeImportLabelSyntax() throws Exception {
1160 invalidImportTest("::file.bzl", SkylarkImports.INVALID_TARGET_PREFIX);
1161 }
1162
1163 @Test
Laurent Le Brun73a98492015-03-17 15:46:19 +00001164 public void testLoadNoSymbol() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001165 setFailFast(false);
Laurent Le Brun73a98492015-03-17 15:46:19 +00001166 parseFileForSkylark("load('/foo/bar/file')\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001167 assertContainsError("syntax error");
Laurent Le Brun73a98492015-03-17 15:46:19 +00001168 }
1169
1170 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001171 public void testLoadOneSymbol() throws Exception {
1172 List<Statement> statements = parseFileForSkylark(
1173 "load('/foo/bar/file', 'fun_test')\n");
1174 LoadStatement stmt = (LoadStatement) statements.get(0);
Laurent Le Brun7b1708c2016-10-13 10:05:12 +00001175 assertEquals("/foo/bar/file", stmt.getImport().getValue());
Ulf Adams89f012d2015-02-26 13:39:28 +00001176 assertThat(stmt.getSymbols()).hasSize(1);
Jon Brandveinee8b7aa2016-07-28 15:01:26 +00001177 Identifier sym = stmt.getSymbols().get(0);
1178 int startOffset = sym.getLocation().getStartOffset();
1179 int endOffset = sym.getLocation().getEndOffset();
1180 assertThat(startOffset).named("getStartOffset()").isEqualTo(22);
1181 assertThat(endOffset).named("getEndOffset()").isEqualTo(startOffset + 10);
Ulf Adams89f012d2015-02-26 13:39:28 +00001182 }
1183
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001184 @Test
Laurent Le Brun59f587a2015-03-16 14:51:36 +00001185 public void testLoadOneSymbolWithTrailingComma() throws Exception {
1186 List<Statement> statements = parseFileForSkylark(
1187 "load('/foo/bar/file', 'fun_test',)\n");
1188 LoadStatement stmt = (LoadStatement) statements.get(0);
Laurent Le Brun7b1708c2016-10-13 10:05:12 +00001189 assertEquals("/foo/bar/file", stmt.getImport().getValue());
Laurent Le Brun59f587a2015-03-16 14:51:36 +00001190 assertThat(stmt.getSymbols()).hasSize(1);
1191 }
1192
1193 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001194 public void testLoadMultipleSymbols() throws Exception {
1195 List<Statement> statements = parseFileForSkylark(
1196 "load('file', 'foo', 'bar')\n");
1197 LoadStatement stmt = (LoadStatement) statements.get(0);
Laurent Le Brun7b1708c2016-10-13 10:05:12 +00001198 assertEquals("file", stmt.getImport().getValue());
Ulf Adams89f012d2015-02-26 13:39:28 +00001199 assertThat(stmt.getSymbols()).hasSize(2);
1200 }
1201
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001202 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001203 public void testLoadSyntaxError() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001204 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001205 parseFileForSkylark("load(non_quoted, 'a')\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001206 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001207 }
1208
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001209 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001210 public void testLoadSyntaxError2() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001211 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001212 parseFileForSkylark("load('non_quoted', a)\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001213 assertContainsError("syntax error");
Ulf Adams89f012d2015-02-26 13:39:28 +00001214 }
1215
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001216 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001217 public void testLoadNotAtTopLevel() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001218 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001219 parseFileForSkylark("if 1: load(8)\n");
Laurent Le Brune102a2d2017-01-02 12:06:18 +00001220 assertContainsError("name 'load' is not defined");
Ulf Adams89f012d2015-02-26 13:39:28 +00001221 }
1222
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001223 @Test
Florian Weikert9d659ad2015-07-23 14:44:36 +00001224 public void testLoadAlias() throws Exception {
Jon Brandveinee8b7aa2016-07-28 15:01:26 +00001225 List<Statement> statements = parseFileForSkylark(
1226 "load('/foo/bar/file', my_alias = 'lawl')\n");
1227 LoadStatement stmt = (LoadStatement) statements.get(0);
1228 ImmutableList<Identifier> actualSymbols = stmt.getSymbols();
1229
1230 assertThat(actualSymbols).hasSize(1);
1231 Identifier sym = actualSymbols.get(0);
1232 assertThat(sym.getName()).isEqualTo("my_alias");
1233 int startOffset = sym.getLocation().getStartOffset();
1234 int endOffset = sym.getLocation().getEndOffset();
1235 assertThat(startOffset).named("getStartOffset()").isEqualTo(22);
1236 assertThat(endOffset).named("getEndOffset()").isEqualTo(startOffset + 8);
Florian Weikert9d659ad2015-07-23 14:44:36 +00001237 }
1238
1239 @Test
1240 public void testLoadAliasMultiple() throws Exception {
1241 runLoadAliasTestForSymbols(
1242 "my_alias = 'lawl', 'lol', next_alias = 'rofl'", "my_alias", "lol", "next_alias");
1243 }
1244
1245 private void runLoadAliasTestForSymbols(String loadSymbolString, String... expectedSymbols) {
1246 List<Statement> statements =
1247 parseFileForSkylark(String.format("load('/foo/bar/file', %s)\n", loadSymbolString));
1248 LoadStatement stmt = (LoadStatement) statements.get(0);
1249 ImmutableList<Identifier> actualSymbols = stmt.getSymbols();
1250
1251 assertThat(actualSymbols).hasSize(expectedSymbols.length);
1252
1253 List<String> actualSymbolNames = new LinkedList<>();
1254
1255 for (Identifier identifier : actualSymbols) {
1256 actualSymbolNames.add(identifier.getName());
1257 }
1258
1259 assertThat(actualSymbolNames).containsExactly((Object[]) expectedSymbols);
1260 }
1261
1262 @Test
1263 public void testLoadAliasSyntaxError() throws Exception {
1264 setFailFast(false);
1265 parseFileForSkylark("load('/foo', test1 = )\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001266 assertContainsError("syntax error at ')': expected string");
Florian Weikert9d659ad2015-07-23 14:44:36 +00001267
1268 parseFileForSkylark("load('/foo', test2 = 1)\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001269 assertContainsError("syntax error at '1': expected string");
Florian Weikert9d659ad2015-07-23 14:44:36 +00001270
1271 parseFileForSkylark("load('/foo', test3 = old)\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001272 assertContainsError("syntax error at 'old': expected string");
Florian Weikert9d659ad2015-07-23 14:44:36 +00001273 }
Han-Wen Nienhuysceae8c52015-09-22 16:24:45 +00001274
Florian Weikert9d659ad2015-07-23 14:44:36 +00001275 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001276 public void testParseErrorNotComparison() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001277 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001278 parseFile("2 < not 3");
Ulf Adamsc708f962015-10-22 12:02:28 +00001279 assertContainsError("syntax error at 'not'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001280 }
1281
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001282 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001283 public void testNotWithArithmeticOperatorsBadSyntax() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001284 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001285 parseFile("0 + not 0");
Ulf Adamsc708f962015-10-22 12:02:28 +00001286 assertContainsError("syntax error at 'not'");
Ulf Adams89f012d2015-02-26 13:39:28 +00001287 }
1288
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001289 @Test
Laurent Le Brunb3266382015-05-27 16:14:43 +00001290 public void testKwargsForbidden() throws Exception {
1291 setFailFast(false);
1292 parseFile("func(**dict)");
Ulf Adamsc708f962015-10-22 12:02:28 +00001293 assertContainsError("**kwargs arguments are not allowed in BUILD files");
Laurent Le Brunb3266382015-05-27 16:14:43 +00001294 }
1295
1296 @Test
1297 public void testArgsForbidden() throws Exception {
1298 setFailFast(false);
1299 parseFile("func(*array)");
Ulf Adamsc708f962015-10-22 12:02:28 +00001300 assertContainsError("*args arguments are not allowed in BUILD files");
Laurent Le Brunb3266382015-05-27 16:14:43 +00001301 }
1302
1303 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001304 public void testOptionalArgBeforeMandatoryArgInFuncDef() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001305 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001306 parseFileForSkylark("def func(a, b = 'a', c):\n return 0\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001307 assertContainsError(
Ulf Adams89f012d2015-02-26 13:39:28 +00001308 "a mandatory positional parameter must not follow an optional parameter");
1309 }
1310
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001311 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001312 public void testKwargBeforePositionalArg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001313 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001314 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001315 "def func(a, b): return a + b",
1316 "func(**{'b': 1}, 'a')");
Ulf Adamsc708f962015-10-22 12:02:28 +00001317 assertContainsError("unexpected tokens after kwarg");
Ulf Adams89f012d2015-02-26 13:39:28 +00001318 }
1319
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001320 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001321 public void testDuplicateKwarg() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001322 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001323 parseFileForSkylark(
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001324 "def func(a, b): return a + b",
1325 "func(**{'b': 1}, **{'a': 2})");
Ulf Adamsc708f962015-10-22 12:02:28 +00001326 assertContainsError("unexpected tokens after kwarg");
Ulf Adams89f012d2015-02-26 13:39:28 +00001327 }
1328
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001329 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001330 public void testUnnamedStar() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001331 setFailFast(false);
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001332 List<Statement> statements = parseFileForSkylark(
1333 "def func(a, b1=2, b2=3, *, c1, d=4, c2): return a + b1 + b2 + c1 + c2 + d\n");
1334 assertThat(statements).hasSize(1);
1335 assertThat(statements.get(0)).isInstanceOf(FunctionDefStatement.class);
1336 FunctionDefStatement stmt = (FunctionDefStatement) statements.get(0);
Laurent Le Brun4baefdc2015-09-04 11:27:46 +00001337 FunctionSignature sig = stmt.getSignature().getSignature();
Francois-Rene Rideau012f7892015-03-31 17:27:01 +00001338 // Note the reordering of optional named-only at the end.
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001339 assertThat(sig.getNames()).isEqualTo(ImmutableList.<String>of(
Francois-Rene Rideau012f7892015-03-31 17:27:01 +00001340 "a", "b1", "b2", "c1", "c2", "d"));
Francois-Rene Rideau4feb1602015-03-18 19:49:13 +00001341 FunctionSignature.Shape shape = sig.getShape();
1342 assertThat(shape.getMandatoryPositionals()).isEqualTo(1);
1343 assertThat(shape.getOptionalPositionals()).isEqualTo(2);
1344 assertThat(shape.getMandatoryNamedOnly()).isEqualTo(2);
1345 assertThat(shape.getOptionalNamedOnly()).isEqualTo(1);
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 testTopLevelForFails() throws Exception {
Francois-Rene Rideau5f3e30c2015-04-10 19:08:39 +00001350 setFailFast(false);
Ulf Adams89f012d2015-02-26 13:39:28 +00001351 parseFileForSkylark("for i in []: 0\n");
Ulf Adamsc708f962015-10-22 12:02:28 +00001352 assertContainsError(
Ulf Adams89f012d2015-02-26 13:39:28 +00001353 "for loops are not allowed on top-level. Put it into a function");
1354 }
1355
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001356 @Test
Ulf Adams89f012d2015-02-26 13:39:28 +00001357 public void testNestedFunctionFails() 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):",
1361 " def bar(): return 0",
1362 " return bar()",
1363 "");
Ulf Adamsc708f962015-10-22 12:02:28 +00001364 assertContainsError(
Ulf Adams89f012d2015-02-26 13:39:28 +00001365 "nested functions are not allowed. Move the function to top-level");
1366 }
1367
Han-Wen Nienhuysccf19ea2015-02-27 15:53:24 +00001368 @Test
Laurent Le Brun3bc8e9a2015-09-10 11:00:37 +00001369 public void testElseWithoutIf() throws Exception {
1370 setFailFast(false);
1371 parseFileForSkylark(
1372 "def func(a):",
1373 // no if
1374 " else: return a");
Yue Gan4866e152016-04-07 13:07:08 +00001375 assertContainsError("syntax error at 'else': not allowed here.");
1376 }
1377
1378 @Test
1379 public void testForElse() throws Exception {
1380 setFailFast(false);
1381 parseFileForSkylark(
1382 "def func(a):",
1383 " for i in range(a):",
1384 " print(i)",
1385 " else: return a");
1386 assertContainsError("syntax error at 'else': not allowed here.");
Laurent Le Brun3bc8e9a2015-09-10 11:00:37 +00001387 }
Florian Weikert1f004e52015-10-16 09:43:48 +00001388
1389 @Test
1390 public void testTryStatementInBuild() throws Exception {
1391 setFailFast(false);
1392 parseFile("try: pass");
Ulf Adamsc708f962015-10-22 12:02:28 +00001393 assertContainsError("syntax error at 'try': Try statements are not supported.");
Florian Weikert1f004e52015-10-16 09:43:48 +00001394 }
1395
1396 @Test
1397 public void testTryStatementInSkylark() throws Exception {
1398 setFailFast(false);
1399 parseFileForSkylark("try: pass");
Ulf Adamsc708f962015-10-22 12:02:28 +00001400 assertContainsError("syntax error at 'try': Try statements are not supported.");
Florian Weikert1f004e52015-10-16 09:43:48 +00001401 }
1402
1403 @Test
1404 public void testClassDefinitionInBuild() throws Exception {
1405 setFailFast(false);
1406 parseFile("class test(object): pass");
Ulf Adamsc708f962015-10-22 12:02:28 +00001407 assertContainsError("syntax error at 'class': Class definitions are not supported.");
Florian Weikert1f004e52015-10-16 09:43:48 +00001408 }
1409
1410 @Test
1411 public void testClassDefinitionInSkylark() throws Exception {
1412 setFailFast(false);
1413 parseFileForSkylark("class test(object): pass");
Ulf Adamsc708f962015-10-22 12:02:28 +00001414 assertContainsError("syntax error at 'class': Class definitions are not supported.");
Florian Weikert1f004e52015-10-16 09:43:48 +00001415 }
1416
1417 @Test
1418 public void testDefInBuild() throws Exception {
1419 setFailFast(false);
1420 parseFile("def func(): pass");
Ulf Adamsc708f962015-10-22 12:02:28 +00001421 assertContainsError("syntax error at 'def': This is not supported in BUILD files. "
Florian Weikert1f004e52015-10-16 09:43:48 +00001422 + "Move the block to a .bzl file and load it");
1423 }
Ulf Adams89f012d2015-02-26 13:39:28 +00001424}