1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package org.codehaus.groovy.syntax.parser;
35
36 import java.util.Iterator;
37 import java.util.List;
38
39 import org.codehaus.groovy.ast.ClassNode;
40 import org.codehaus.groovy.ast.MethodNode;
41 import org.codehaus.groovy.ast.ModuleNode;
42 import org.codehaus.groovy.ast.expr.BinaryExpression;
43 import org.codehaus.groovy.ast.expr.ClassExpression;
44 import org.codehaus.groovy.ast.expr.ClosureExpression;
45 import org.codehaus.groovy.ast.expr.ConstantExpression;
46 import org.codehaus.groovy.ast.expr.Expression;
47 import org.codehaus.groovy.ast.expr.MapEntryExpression;
48 import org.codehaus.groovy.ast.expr.MapExpression;
49 import org.codehaus.groovy.ast.expr.VariableExpression;
50 import org.codehaus.groovy.ast.stmt.BlockStatement;
51 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
52 import org.codehaus.groovy.ast.stmt.ForStatement;
53 import org.codehaus.groovy.ast.stmt.IfStatement;
54 import org.codehaus.groovy.ast.stmt.ReturnStatement;
55 import org.codehaus.groovy.control.CompilationFailedException;
56 import org.codehaus.groovy.runtime.InvokerHelper;
57 import org.codehaus.groovy.syntax.SyntaxException;
58 import org.codehaus.groovy.syntax.Types;
59 import org.codehaus.groovy.syntax.lexer.UnexpectedCharacterException;
60
61 /***
62 * Test case for the AST builder
63 *
64 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
65 * @version $Revision: 1.30 $
66 */
67 public class ASTBuilderTest extends TestParserSupport {
68
69 public void testStatementParsing() throws Exception {
70 ModuleNode module =
71 parse("import cheddar.cheese.Toast as Bread\n x = [1, 2, 3]; System.out.println(x)", "foo/Cheese.groovy");
72
73 BlockStatement block = module.getStatementBlock();
74 assertTrue("Contains some statements", !block.getStatements().isEmpty());
75
76
77 }
78
79 public void testBlock() throws Exception {
80 ModuleNode module =
81 parse("class Foo { void testMethod() { x = someMethod(); callMethod(x) } }", "Dummy.groovy");
82 BlockStatement statement = getCode(module, "testMethod");
83
84 assertEquals("Statements size: " + statement.getStatements(), 2, statement.getStatements().size());
85
86 System.out.println(statement.getStatements());
87 }
88
89 public void testSubscript() throws Exception {
90 ModuleNode module =
91 parse("class Foo { void testMethod() { x = 1\n [1].each { println(it) }} }", "Dummy.groovy");
92 BlockStatement statement = getCode(module, "testMethod");
93
94 assertEquals("Statements size: " + statement.getStatements(), 2, statement.getStatements().size());
95
96 for (Iterator iter = statement.getStatements().iterator(); iter.hasNext();) {
97 System.out.println(iter.next());
98 }
99 }
100
101 public void testNewlinesInsideExpresssions() throws Exception {
102 ModuleNode module = parse("class Foo { void testMethod() { x = 1 +\n 5 * \n 2 / \n 5 } }", "Dummy.groovy");
103 BlockStatement statement = getCode(module, "testMethod");
104
105 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
106
107 for (Iterator iter = statement.getStatements().iterator(); iter.hasNext();) {
108 System.out.println(iter.next());
109 }
110 }
111
112 public void testMethodCalls() throws Exception {
113 ModuleNode module =
114 parse(
115 "class Foo { void testMethod() { array = getMockArguments()\n \n dummyMethod(array) } }",
116 "Dummy.groovy");
117 BlockStatement statement = getCode(module, "testMethod");
118
119 assertEquals("Statements size: " + statement.getStatements(), 2, statement.getStatements().size());
120
121 for (Iterator iter = statement.getStatements().iterator(); iter.hasNext();) {
122 System.out.println(iter.next());
123 }
124 }
125
126 public void testJdk15ForLoop() throws Exception {
127 ModuleNode module = parse("class Foo { void testMethod() { for (x : foo) { println x } } }", "Dummy.groovy");
128 BlockStatement statement = getCode(module, "testMethod");
129
130 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
131
132 ForStatement stmt = (ForStatement) statement.getStatements().get(0);
133 assertEquals("x", stmt.getVariable());
134 assertTrue(stmt.getVariableType().isDynamic());
135 System.out.println(stmt);
136 }
137
138 public void testJdk15ForLoopWithType() throws Exception {
139 ModuleNode module = parse("class Foo { void testMethod() { for (Integer x : foo) { println x } } }", "Dummy.groovy");
140 BlockStatement statement = getCode(module, "testMethod");
141
142 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
143
144 ForStatement stmt = (ForStatement) statement.getStatements().get(0);
145 assertEquals("x", stmt.getVariable());
146 System.out.println( stmt.getVariableType().getName() );
147 assertEquals("java.lang.Integer", stmt.getVariableType().getName());
148 assertFalse(stmt.getVariableType().isDynamic());
149 System.out.println(stmt);
150 }
151
152 public void testForLoopWithType() throws Exception {
153 ModuleNode module = parse("class Foo { void testMethod() { for (Foo x in foo) { println x } } }", "Dummy.groovy");
154 BlockStatement statement = getCode(module, "testMethod");
155
156 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
157
158 ForStatement stmt = (ForStatement) statement.getStatements().get(0);
159 assertEquals("x", stmt.getVariable());
160 assertEquals("Foo", stmt.getVariableType().getName());
161 assertFalse(stmt.getVariableType().isDynamic());
162 System.out.println(stmt);
163 }
164
165 public void testSubscriptAssignment() throws Exception {
166 ModuleNode module = parse("class Foo { void testMethod() { x[12] = 'abc' } }", "Dummy.groovy");
167 BlockStatement statement = getCode(module, "testMethod");
168
169 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
170
171 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
172 Expression exp = exprStmt.getExpression();
173 System.out.println(exp);
174
175 assertTrue(exp instanceof BinaryExpression);
176 BinaryExpression binExpr = (BinaryExpression) exp;
177 assertTrue("RHS is constant", binExpr.getRightExpression() instanceof ConstantExpression);
178
179 Expression lhs = binExpr.getLeftExpression();
180 assertTrue("LHS is binary expression", lhs instanceof BinaryExpression);
181
182 BinaryExpression lhsBinExpr = (BinaryExpression) lhs;
183 assertEquals(Types.LEFT_SQUARE_BRACKET, lhsBinExpr.getOperation().getType());
184
185 assertTrue("Left of LHS is a variable", lhsBinExpr.getLeftExpression() instanceof VariableExpression);
186 assertTrue("Right of LHS is a constant", lhsBinExpr.getRightExpression() instanceof ConstantExpression);
187
188 }
189
190 public void testNoReturn() throws Exception {
191 ModuleNode module = parse("class Foo { void testMethod() { x += 5 } }", "Dummy.groovy");
192 BlockStatement statement = getCode(module, "testMethod");
193
194 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
195
196 System.out.println(statement.getStatements());
197
198 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
199 Expression exp = exprStmt.getExpression();
200
201 System.out.println("expr: " + exp);
202 }
203
204 public void testCastExpression() throws Exception {
205 ModuleNode module = parse("class Foo { void testMethod() { x = (Short) 5 } }", "Dummy.groovy");
206 BlockStatement statement = getCode(module, "testMethod");
207
208 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
209
210 System.out.println(statement.getStatements());
211
212 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
213 Expression exp = exprStmt.getExpression();
214
215 System.out.println("expr: " + exp);
216 }
217
218 public void testTernaryExpression() throws Exception {
219 ModuleNode module = parse("class Foo { void testMethod() { foo() ? 'a' : 'b' } }", "Dummy.groovy");
220 BlockStatement statement = getCode(module, "testMethod");
221
222 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
223
224 System.out.println(statement.getStatements());
225
226 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
227 Expression exp = exprStmt.getExpression();
228
229 System.out.println("expr: " + exp);
230 }
231
232 public void testClosureWithJustIdentifierBug() throws Exception {
233 ModuleNode module = parse("class Foo { void testMethod() { return {a} } }", "Dummy.groovy");
234 BlockStatement statement = getCode(module, "testMethod");
235
236 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
237
238 System.out.println(statement.getStatements());
239
240 ReturnStatement returnStmt = (ReturnStatement)statement.getStatements().get(0);
241 Expression exp = returnStmt.getExpression();
242
243 System.out.println("expr: " + exp);
244 }
245
246 public void testClosureWithJustIdentifierInMapBug() throws Exception {
247 ModuleNode module = parse("class Foo { void testMethod() { ['x':{a}, 'd':123] } }", "Dummy.groovy");
248 BlockStatement statement = getCode(module, "testMethod");
249
250 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
251
252 System.out.println(statement.getStatements());
253
254 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
255
256 MapExpression mapExp = (MapExpression) exprStmt.getExpression();
257 MapEntryExpression entryExp = (MapEntryExpression) mapExp.getMapEntryExpressions().get(0);
258 ClosureExpression closureExp = (ClosureExpression) entryExp.getValueExpression();
259 assertEquals("Parameters on closure", 0, closureExp.getParameters().length);
260 System.out.println("expr: " + closureExp);
261 }
262
263 public void testArrayExpression() throws Exception {
264 ModuleNode module = parse("class Foo { void testMethod() { foo = new String[] { 'a', 'b', 'c' }\n assert foo != null } }", "Dummy.groovy");
265 BlockStatement statement = getCode(module, "testMethod");
266
267 assertEquals("Statements size: " + statement.getStatements(), 2, statement.getStatements().size());
268
269 System.out.println(statement.getStatements());
270
271 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
272 Expression exp = exprStmt.getExpression();
273
274 System.out.println("expr: " + exp);
275 }
276
277 public void testTypedVariableExpression() throws Exception {
278 ModuleNode module = parse("class Foo { void testMethod() { Short x = 5 } }", "Dummy.groovy");
279 BlockStatement statement = getCode(module, "testMethod");
280
281 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
282
283 System.out.println(statement.getStatements());
284
285 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
286 Expression exp = exprStmt.getExpression();
287
288 System.out.println("expr: " + exp);
289 }
290
291 public void testFullyQualifiedType() throws Exception {
292 ModuleNode module = parse("class Foo { void testMethod() { com.acme.Foo } }", "Dummy.groovy");
293 BlockStatement statement = getCode(module, "testMethod");
294
295 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
296
297 System.out.println(statement.getStatements());
298
299 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
300 Expression exp = exprStmt.getExpression();
301
302 System.out.println("expr: " + exp);
303
304 System.out.println("text: " + exp.getText());
305 }
306
307 public void testDoubleSubscript() throws Exception {
308 ModuleNode module = parse("class Foo { void testMethod() { x = foo[0][0] } }", "Dummy.groovy");
309 BlockStatement statement = getCode(module, "testMethod");
310
311 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
312
313 System.out.println(statement.getStatements());
314
315 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
316 Expression exp = exprStmt.getExpression();
317
318 System.out.println("expr: " + exp);
319
320 System.out.println("text: " + exp.getText());
321 }
322
323 public void testMethodCallWithDotAndNoParenthesis() throws Exception {
324 ModuleNode module = parse("class Foo { void testMethod() { foo.someMethod 1 } }", "Dummy.groovy");
325 BlockStatement statement = getCode(module, "testMethod");
326
327 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
328
329 System.out.println(statement.getStatements());
330
331 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
332 Expression exp = exprStmt.getExpression();
333
334 System.out.println("expr: " + exp);
335
336 System.out.println("text: " + exp.getText());
337 }
338
339 public void testMethodCallWithNoParenthesis() throws Exception {
340 ModuleNode module = parse("class Foo { void testMethod() { someMethod 1 } }", "Dummy.groovy");
341 BlockStatement statement = getCode(module, "testMethod");
342
343 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
344
345 System.out.println(statement.getStatements());
346
347 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
348 Expression exp = exprStmt.getExpression();
349
350 System.out.println("expr: " + exp);
351
352 System.out.println("text: " + exp.getText());
353 }
354
355 public void testScriptMethodCallWithNoParenthesis() throws Exception {
356 ModuleNode module = parse("someMethod 1", "Dummy.groovy");
357 BlockStatement statement = getCode(module, "run");
358
359 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
360
361 System.out.println(statement.getStatements());
362
363 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
364 Expression exp = exprStmt.getExpression();
365
366 System.out.println("expr: " + exp);
367
368 System.out.println("text: " + exp.getText());
369 }
370
371 public void testScriptWithMethodDeclaration() throws Exception {
372 ModuleNode module = parse("def foo(a) { return a + 1}\n foo(123)", "Dummy.groovy");
373 BlockStatement statement = getCode(module, "run");
374
375 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
376
377 System.out.println(statement.getStatements());
378
379 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
380 Expression exp = exprStmt.getExpression();
381
382 System.out.println("expr: " + exp);
383
384 System.out.println("text: " + exp.getText());
385 }
386
387 public void testSubscriptThenMethod() throws Exception {
388 ModuleNode module = parse("class Foo { void testMethod() { x = foo[0].foo() } }", "Dummy.groovy");
389 BlockStatement statement = getCode(module, "testMethod");
390
391 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
392
393 System.out.println(statement.getStatements());
394
395 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
396 Expression exp = exprStmt.getExpression();
397
398 System.out.println("expr: " + exp);
399
400 System.out.println("text: " + exp.getText());
401 }
402
403 public void testSubscriptThenOperation() throws Exception {
404 ModuleNode module = parse("class Foo { void testMethod() { foo[0] += 5 } }", "Dummy.groovy");
405 BlockStatement statement = getCode(module, "testMethod");
406
407 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
408
409 System.out.println(statement.getStatements());
410
411 ExpressionStatement exprStmt = (ExpressionStatement) statement.getStatements().get(0);
412 Expression exp = exprStmt.getExpression();
413
414 System.out.println("expr: " + exp);
415
416 System.out.println("text: " + exp.getText());
417 }
418
419
420 public void testRodsBug() throws Exception {
421 ModuleNode module = parse("class Foo { void testMethod() { if (x) { String n = 'foo' } } }", "Dummy.groovy");
422 BlockStatement statement = getCode(module, "testMethod");
423
424 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
425
426 System.out.println(statement.getStatements());
427
428 IfStatement ifStmt = (IfStatement) statement.getStatements().get(0);
429 BlockStatement trueStmt = (BlockStatement) ifStmt.getIfBlock();
430
431 System.out.println("trueStmt: " + trueStmt);
432
433
434 assertEquals(1, trueStmt.getStatements().size());
435 }
436
437 public void testStaticMethodCallBug() throws Exception {
438 ModuleNode module =
439 parse("class Foo { void testMethod() { ASTBuilderTest.mockHelperMethod() } }", "Dummy.groovy");
440 BlockStatement statement = getCode(module, "testMethod");
441
442 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
443
444 System.out.println(statement.getStatements());
445 }
446
447 public void testInstanceofBug() throws Exception {
448 ModuleNode module =
449 parse("class Foo { void testMethod() { if (foo instanceof java.util.List) { println('hello') } } }", "Dummy.groovy");
450 BlockStatement statement = getCode(module, "testMethod");
451
452 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
453
454 System.out.println(statement.getStatements());
455
456 IfStatement ifStmt = (IfStatement) statement.getStatements().get(0);
457 BinaryExpression exp = (BinaryExpression) ifStmt.getBooleanExpression().getExpression();
458
459 System.out.println("exp: " + exp);
460
461 Expression rhs = exp.getRightExpression();
462 assertTrue("RHS should be a class expression", rhs instanceof ClassExpression);
463
464 ClassExpression classExp = (ClassExpression) rhs;
465 assertEquals("java.util.List", classExp.getType());
466 }
467
468 public void testMethodCallWithoutParensBug() throws Exception {
469 ModuleNode module = parse("class Foo { void testMethod() { println 3, 5 } }", "Dummy.groovy");
470 BlockStatement statement = getCode(module, "testMethod");
471
472 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
473
474 System.out.println(statement.getStatements());
475 }
476
477 public void testReturnMethodClosure() throws Exception {
478 ModuleNode module = parse("class Foo { void testMethod() { System.out.println\n}}", "Dummy.groovy");
479 BlockStatement statement = getCode(module, "testMethod");
480
481 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
482
483 System.out.println(statement.getStatements());
484 }
485
486 public void testDionsTypo() throws Exception {
487 ModuleNode module = parse("class Foo { void testMethod() { println ${foo}\n}}", "Dummy.groovy");
488 BlockStatement statement = getCode(module, "testMethod");
489
490 assertEquals("Statements size: " + statement.getStatements(), 1, statement.getStatements().size());
491
492 System.out.println(statement.getStatements());
493 }
494
495 public void testMethodWithArrayTypeParam() throws Exception {
496 ModuleNode module = parse("class Foo { void main(String[] args) { println(args) } }", "Dummy.groovy");
497
498 MethodNode method = getMethod(module, "main");
499
500 System.out.println("Parameters: " + InvokerHelper.toString(method.getParameters()));
501 }
502
503 private void ensureOutOfRange(String script) throws Exception {
504 try {
505 ModuleNode module = parse(script, "Dummy.groovy");
506 } catch (CompilationFailedException e) {
507 SyntaxException cause = e.getUnit().getSyntaxError(0);
508 if( cause != null && cause instanceof ParserException && cause.getMessage().indexOf("out of range") >= 0) {
509 return;
510 }
511 fail (script+" should fail with a ParserException: "+e.getMessage());
512 }
513 fail(script+" should fail because the number is out of range.");
514 }
515
516 private void ensureInRange(String script) throws Exception {
517 ModuleNode module = parse(script, "Dummy.groovy");
518 }
519
520 public void testLiteralIntegerRange() throws Exception {
521 ensureInRange( "x = 2147483647I;");
522 ensureOutOfRange("x = 2147483648I;");
523
524 ensureInRange( "x = -2147483648I;");
525 ensureOutOfRange("x = -2147483649I;");
526 }
527
528 public void testLiteralLongRange() throws Exception {
529 ensureInRange( "x = 9223372036854775807L;");
530 ensureOutOfRange("x = 9223372036854775808L;");
531
532 ensureInRange( "x = -9223372036854775808L;");
533 ensureOutOfRange("x = -9223372036854775809L;");
534 }
535
536 public void testLiteralDoubleRange() throws Exception {
537 ensureInRange( "x = 1.7976931348623157E308D;");
538 ensureOutOfRange("x = 1.7976931348623167E308D;");
539
540 ensureInRange( "x = -1.7976931348623157E308D;");
541 ensureOutOfRange("x = -1.7976931348623167E308D;");
542 }
543
544 public void testLiteralFloatRange() throws Exception {
545 ensureInRange( "x = 3.4028235e+38f;");
546 ensureOutOfRange("x = 3.4028236e+38f;");
547
548 ensureInRange( "x = -3.4028235e+38f;");
549 ensureOutOfRange("x = -3.4028236e+38f;");
550 }
551
552 public void testLiteralIntegerBadSuffix() throws Exception {
553 try {
554 ModuleNode module = parse("x = 2147483648J;", "Dummy.groovy");
555 } catch (CompilationFailedException e) {
556 SyntaxException cause = e.getUnit().getSyntaxError(0);
557 if (cause instanceof UnexpectedCharacterException) {
558 return;
559 }
560 fail ("x = 2147483648J should fail with an UnexpectedCharacterException");
561 }
562 fail("x = 2147483648J, should fail because J is an invalid numeric literal suffix.");
563 }
564
565 public void testLiteralBadExponent() throws Exception {
566 try {
567 ModuleNode module = parse("x = 2.3e;", "Dummy.groovy");
568 } catch (CompilationFailedException e) {
569 SyntaxException cause = e.getUnit().getSyntaxError(0);
570 if (cause instanceof UnexpectedCharacterException) {
571 return;
572 }
573 fail ("x = 2.3e should fail with an UnexpectedCharacterException");
574 }
575 fail("x = 2.3e, should fail because no exponent is specified.");
576 }
577
578 public static Object mockHelperMethod() {
579 return "cheese";
580 }
581
582 protected BlockStatement getCode(ModuleNode module, String name) {
583 MethodNode method = getMethod(module, name);
584
585 BlockStatement statement = (BlockStatement) method.getCode();
586 assertNotNull(statement);
587 return statement;
588 }
589
590 protected MethodNode getMethod(ModuleNode module, String name) {
591 assertEquals("class count", 1, module.getClasses().size());
592
593 ClassNode node = (ClassNode) module.getClasses().get(0);
594
595 assertNotNull(node);
596
597 List methods = node.getDeclaredMethods(name);
598 assertTrue(methods.size() > 0);
599 return (MethodNode) methods.get(0);
600 }
601 }