1 46 package org.codehaus.groovy.syntax.parser; 47 48 import org.codehaus.groovy.GroovyBugError; 49 import org.codehaus.groovy.control.CompilationFailedException; 50 import org.codehaus.groovy.control.SourceUnit; 51 import org.codehaus.groovy.control.messages.SimpleMessage; 52 import org.codehaus.groovy.control.messages.SyntaxErrorMessage; 53 import org.codehaus.groovy.syntax.CSTNode; 54 import org.codehaus.groovy.syntax.ReadException; 55 import org.codehaus.groovy.syntax.Reduction; 56 import org.codehaus.groovy.syntax.SyntaxException; 57 import org.codehaus.groovy.syntax.Token; 58 import org.codehaus.groovy.syntax.TokenStream; 59 import org.codehaus.groovy.syntax.Types; 60 61 71 72 public class Parser 73 { 74 private SourceUnit controller = null; private TokenStream tokenStream = null; private int nestCount = 1; 78 79 80 83 87 88 public Parser( SourceUnit controller, TokenStream tokenStream ) 89 { 90 this.controller = controller; 91 this.tokenStream = tokenStream; 92 } 93 94 95 98 99 public Reduction parse() throws CompilationFailedException 100 { 101 try 102 { 103 return module(); 104 } 105 catch( SyntaxException e ) 106 { 107 controller.addFatalError( new SyntaxErrorMessage(e) ); 108 } 109 110 throw new GroovyBugError( "this will never happen" ); 111 } 112 113 114 115 118 119 public TokenStream getTokenStream() 120 { 121 return this.tokenStream; 122 } 123 124 125 126 127 130 131 134 135 public void optionalNewlines() throws SyntaxException, CompilationFailedException 136 { 137 while( lt(false) == Types.NEWLINE) 138 { 139 consume( Types.NEWLINE ); 140 } 141 } 142 143 144 145 149 150 public void endOfStatement( boolean allowRightCurlyBrace ) throws SyntaxException, CompilationFailedException 151 { 152 Token next = la( true ); 153 154 if( next.isA(Types.GENERAL_END_OF_STATEMENT) ) 155 { 156 consume( true ); 157 } 158 else 159 { 160 if( allowRightCurlyBrace ) 161 { 162 if( !next.isA(Types.RIGHT_CURLY_BRACE) ) 163 { 164 error( new int[] { Types.SEMICOLON, Types.NEWLINE, Types.RIGHT_CURLY_BRACE } ); 165 } 166 } 167 else 168 { 169 error( new int[] { Types.SEMICOLON, Types.NEWLINE } ); 170 } 171 } 172 } 173 174 175 176 179 180 public void endOfStatement() throws SyntaxException, CompilationFailedException 181 { 182 endOfStatement( true ); 183 } 184 185 186 187 188 191 192 203 204 public CSTNode dottedIdentifier() throws SyntaxException, CompilationFailedException 205 { 206 CSTNode identifier = consume(Types.IDENTIFIER); 207 208 while (lt() == Types.DOT) 209 { 210 identifier = consume(Types.DOT).asReduction( identifier, consume(Types.IDENTIFIER) ); 211 } 212 213 return identifier; 214 } 215 216 217 218 239 240 public Reduction module() throws SyntaxException, CompilationFailedException 241 { 242 Reduction module = Reduction.newContainer(); 243 244 247 249 Reduction packageDeclaration = null; 250 251 if( lt() == Types.KEYWORD_PACKAGE ) 252 { 253 try 254 { 255 packageDeclaration = packageDeclaration(); 256 } 257 258 catch (SyntaxException e) 259 { 260 controller.addError(e); 261 recover(); 262 } 263 } 264 265 if( packageDeclaration == null ) 266 { 267 packageDeclaration = Reduction.EMPTY; 268 } 269 270 module.add( packageDeclaration ); 271 272 273 276 Reduction imports = (Reduction)module.add( Reduction.newContainer() ); 277 Object collector; 278 279 while( lt() == Types.KEYWORD_IMPORT ) 280 { 281 try 282 { 283 imports.add( importStatement() ); 284 } 285 286 catch( SyntaxException e ) 287 { 288 controller.addError(e); 289 recover(); 290 } 291 } 292 293 294 297 while( lt() != Types.EOF ) 298 { 299 try 300 { 301 module.add( topLevelStatement() ); 302 } 303 catch (SyntaxException e) 304 { 305 controller.addError(e); 306 recover(); 307 } 308 } 309 310 return module; 311 } 312 313 314 315 328 329 public Reduction packageDeclaration() throws SyntaxException, CompilationFailedException 330 { 331 Reduction packageDeclaration = consume(Types.KEYWORD_PACKAGE).asReduction( dottedIdentifier() ); 332 endOfStatement( false ); 333 334 return packageDeclaration; 335 } 336 337 338 339 362 363 public Reduction importStatement() throws SyntaxException, CompilationFailedException 364 { 365 Reduction importStatement = consume(Types.KEYWORD_IMPORT).asReduction(); 366 367 370 CSTNode packageNode = null; 371 if( lt(2) == Types.DOT ) 372 { 373 packageNode = consume(Types.IDENTIFIER).asReduction(); 374 375 while( lt(3) == Types.DOT ) 376 { 377 packageNode = consume(Types.DOT).asReduction( packageNode ); 378 packageNode.add( consume(Types.IDENTIFIER) ); 379 } 380 381 consume( Types.DOT ); 382 } 383 384 if( packageNode == null ) 385 { 386 packageNode = Reduction.EMPTY; 387 } 388 389 importStatement.add( packageNode ); 390 391 392 395 if( !packageNode.isEmpty() && lt() == Types.STAR ) 396 { 397 importStatement.add( consume(Types.STAR) ); 398 } 399 else 400 { 401 boolean done = false; 402 while( !done ) 403 { 404 Reduction clause = consume(Types.IDENTIFIER).asReduction(); 405 if( lt() == Types.KEYWORD_AS ) 406 { 407 consume( Types.KEYWORD_AS ); 408 clause.add( consume(Types.IDENTIFIER) ); 409 } 410 411 importStatement.add( clause ); 412 413 if( lt() == Types.COMMA ) 414 { 415 consume( Types.COMMA ); 416 } 417 else 418 { 419 done = true; 420 } 421 } 422 423 } 424 425 428 endOfStatement( false ); 429 return importStatement; 430 } 431 432 433 434 464 465 public CSTNode topLevelStatement() throws SyntaxException, CompilationFailedException 466 { 467 CSTNode result = null; 468 469 476 if (lt() == Types.KEYWORD_DEF) 477 { 478 consume(); 479 480 Reduction modifiers = modifierList( false, false ); 481 CSTNode type = optionalDatatype( false, true ); 482 Token identifier = nameDeclaration( false ); 483 484 result = methodDeclaration(modifiers, type, identifier, false); 485 } 486 487 else if (lt() == Types.KEYWORD_DEFMACRO) 488 { 489 } 491 492 496 else if( lt() == Types.KEYWORD_SYNCHRONIZED && lt(2) == Types.LEFT_PARENTHESIS ) 497 { 498 result = synchronizedStatement(); 499 } 500 501 505 else if( la().isA(Types.DECLARATION_MODIFIER) || la().isA(Types.TYPE_DECLARATION) ) 506 { 507 Reduction modifiers = modifierList( true, true ); 508 509 switch( lt() ) 510 { 511 case Types.KEYWORD_CLASS: 512 { 513 result = classDeclaration( modifiers ); 514 break; 515 } 516 517 case Types.KEYWORD_INTERFACE: 518 { 519 result = interfaceDeclaration( modifiers ); 520 break; 521 } 522 523 default: 524 { 525 error( new int[] { Types.KEYWORD_CLASS, Types.KEYWORD_INTERFACE } ); 526 break; 527 } 528 } 529 } 530 531 534 else 535 { 536 result = statement(); 537 } 538 539 return result; 540 } 541 542 543 544 547 548 public CSTNode typeDeclaration() throws SyntaxException, CompilationFailedException 549 { 550 return topLevelStatement(); 551 } 552 553 554 555 567 568 public Reduction modifierList(boolean allowStatic, boolean allowAbstract) throws CompilationFailedException, SyntaxException 569 { 570 Reduction modifiers = Reduction.newContainer(); 571 572 while( la().isA(Types.DECLARATION_MODIFIER) ) 573 { 574 if( lt() == Types.KEYWORD_ABSTRACT && !allowAbstract) 575 { 576 controller.addError( "keyword 'abstract' not valid in this setting", la() ); 577 } 578 else if (lt() == Types.KEYWORD_STATIC && !allowStatic) 579 { 580 controller.addError( "keyword 'static' not valid in this setting", la() ); 581 } 582 modifiers.add( consume() ); 583 } 584 585 return modifiers; 586 } 587 588 589 590 611 612 public Reduction classDeclaration( Reduction modifiers ) throws SyntaxException, CompilationFailedException 613 { 614 consume( Types.KEYWORD_CLASS ); 615 616 Reduction classDeclaration = consume(Types.IDENTIFIER).asReduction( modifiers ); 617 classDeclaration.setMeaning( Types.SYNTH_CLASS ); 618 619 620 623 try 624 { 625 classDeclaration.add( typeList(Types.KEYWORD_EXTENDS, true, 1) ); 626 } 627 catch (SyntaxException e) 628 { 629 controller.addError(e); 630 classDeclaration.add( Reduction.EMPTY ); 631 } 632 633 634 637 try 638 { 639 classDeclaration.add( typeList(Types.KEYWORD_IMPLEMENTS, true, 0) ); 640 } 641 catch (SyntaxException e) 642 { 643 controller.addError(e); 644 classDeclaration.add( Reduction.EMPTY ); 645 } 646 647 648 651 classDeclaration.add( typeBody(true, true, false) ); 652 653 return classDeclaration; 654 } 655 656 657 658 677 678 public Reduction interfaceDeclaration( Reduction modifiers ) throws SyntaxException, CompilationFailedException 679 { 680 consume( Types.KEYWORD_INTERFACE ); 681 682 Reduction interfaceDeclaration = consume(Types.IDENTIFIER).asReduction( modifiers, Reduction.EMPTY ); 683 interfaceDeclaration.setMeaning( Types.SYNTH_INTERFACE ); 684 685 686 689 try 690 { 691 interfaceDeclaration.add( typeList(Types.KEYWORD_EXTENDS, true, 0) ); 692 } 693 catch (SyntaxException e) 694 { 695 controller.addError(e); 696 interfaceDeclaration.add( Reduction.EMPTY ); 697 } 698 699 700 704 interfaceDeclaration.add( typeBody(false, true, true) ); 705 return interfaceDeclaration; 706 } 707 708 709 710 725 726 public Reduction typeList(int declarator, boolean optional, int limit) throws SyntaxException, CompilationFailedException 727 { 728 Reduction typeList = null; 729 730 if( lt() == declarator ) 731 { 732 typeList = consume(declarator).asReduction(); 733 734 738 while( limit == 0 || typeList.children() < limit ) 739 { 740 743 try 744 { 745 if( typeList.children() > 0) 746 { 747 consume( Types.COMMA ); 748 } 749 750 typeList.add( datatype(false) ); 751 } 752 catch (SyntaxException e) 753 { 754 controller.addError(e); 755 recover( Types.TYPE_LIST_TERMINATORS ); 756 } 757 758 763 if( !la().isA(Types.COMMA) ) 764 { 765 break; 766 } 767 } 768 } 769 770 else 771 { 772 if (optional) 773 { 774 typeList = Reduction.EMPTY; 775 } 776 else 777 { 778 error( declarator ); 779 } 780 } 781 782 return typeList; 783 } 784 785 786 787 800 801 public Reduction typeBody(boolean allowStatic, boolean allowAbstract, boolean requireAbstract) throws SyntaxException, CompilationFailedException 802 { 803 Reduction body = Reduction.newContainer(); 804 805 consume( Types.LEFT_CURLY_BRACE ); 806 807 while( lt() != Types.EOF && lt() != Types.RIGHT_CURLY_BRACE ) 808 { 809 try 810 { 811 body.add( typeBodyStatement(allowStatic, allowAbstract, requireAbstract) ); 812 } 813 catch( SyntaxException e ) 814 { 815 controller.addError(e); 816 recover(); 817 } 818 } 819 820 consume( Types.RIGHT_CURLY_BRACE ); 821 822 return body; 823 } 824 825 826 827 859 860 public Reduction typeBodyStatement(boolean allowStatic, boolean allowAbstract, boolean requireAbstract) throws SyntaxException, CompilationFailedException 861 { 862 Reduction statement = null; 863 864 868 if( lt() == Types.KEYWORD_STATIC && lt(2) == Types.LEFT_CURLY_BRACE ) 869 { 870 if (!allowStatic) 871 { 872 controller.addError( "static initializers not valid in this context", la() ); 873 } 874 875 Reduction modifiers = modifierList( true, false ); 876 Token identifier = Token.NULL; 877 statement = methodDeclaration( modifiers, Reduction.EMPTY, identifier, false ); 878 } 879 880 883 else 884 { 885 Reduction modifiers = modifierList( allowStatic, allowAbstract ); 886 887 890 if( lt() == Types.KEYWORD_CLASS ) 891 { 892 statement = classDeclaration( modifiers ); 893 } 894 895 else if( lt() == Types.KEYWORD_INTERFACE ) 896 { 897 statement = interfaceDeclaration( modifiers ); 898 } 899 900 903 else 904 { 905 908 if( lt() == Types.KEYWORD_PROPERTY ) 909 { 910 consume(); 911 } 912 913 920 while( lt(true) == Types.NEWLINE) 921 { 922 consume( Types.NEWLINE ); 923 } 924 925 928 CSTNode type = optionalDatatype( true, true ); 929 Token identifier = nameDeclaration( true ); 930 931 switch( lt(true) ) 932 { 933 case Types.LEFT_PARENTHESIS : 934 { 935 939 boolean methodIsAbstract = requireAbstract; 940 941 if( !methodIsAbstract ) 942 { 943 for( int i = 1; i < modifiers.size(); i++ ) 944 { 945 if( modifiers.get(i).getMeaning() == Types.KEYWORD_ABSTRACT ) 946 { 947 methodIsAbstract = true; 948 break; 949 } 950 } 951 } 952 953 statement = methodDeclaration( modifiers, type, identifier, methodIsAbstract ); 954 break; 955 } 956 957 case Types.EQUAL: 958 case Types.SEMICOLON: 959 case Types.NEWLINE: 960 case Types.RIGHT_CURLY_BRACE: 961 case Types.EOF: 962 statement = propertyDeclaration( modifiers, type, identifier ); 963 break; 964 965 default: 966 error( new int[] { Types.LEFT_PARENTHESIS, Types.EQUAL, Types.SEMICOLON, Types.NEWLINE, Types.RIGHT_CURLY_BRACE } ); 967 } 968 } 969 } 970 971 return statement; 972 } 973 974 975 976 979 980 public Reduction bodyStatement() throws SyntaxException, CompilationFailedException 981 { 982 return typeBodyStatement( true, true, false ); 983 } 984 985 986 987 999 1000 protected Token nameDeclaration( boolean significantNewlines ) throws SyntaxException, CompilationFailedException 1001 { 1002 return consume( Types.IDENTIFIER, significantNewlines ); 1003 } 1004 1005 1006 1007 1019 1020 protected Token nameReference( boolean significantNewlines ) throws SyntaxException, CompilationFailedException 1021 { 1022 1023 Token token = la( significantNewlines ); 1024 if( !token.canMean(Types.IDENTIFIER) ) 1025 { 1026 error( Types.IDENTIFIER ); 1027 } 1028 1029 consume(); 1030 token.setMeaning( Types.IDENTIFIER ); 1031 1032 return token; 1033 1034 } 1035 1036 1037 1038 1052 1053 protected CSTNode optionalDatatype( boolean significantNewlines, boolean allowVoid ) throws SyntaxException, CompilationFailedException 1054 { 1055 CSTNode type = Reduction.EMPTY; 1056 Token next = la(significantNewlines); 1057 1058 1064 if( next.isA(Types.IDENTIFIER) ) 1065 { 1066 if( lt(2, significantNewlines) == Types.IDENTIFIER ) 1067 { 1068 type = datatype( allowVoid ); 1069 } 1070 else 1071 { 1072 getTokenStream().checkpoint(); 1073 1074 try 1075 { 1076 type = datatype( allowVoid ); 1077 if( lt(significantNewlines) != Types.IDENTIFIER ) 1078 { 1079 throw new Exception (); 1080 } 1081 } 1082 catch( Exception e ) 1083 { 1084 getTokenStream().restore(); 1085 type = Reduction.EMPTY; 1086 } 1087 } 1088 } 1089 1090 1095 else if( next.isA(Types.PRIMITIVE_TYPE) ) 1096 { 1097 type = datatype( allowVoid ); 1098 } 1099 1100 return type; 1101 } 1102 1103 1104 1105 1106 1123 1124 public Reduction propertyDeclaration( Reduction modifiers, CSTNode type, Token identifier ) throws SyntaxException, CompilationFailedException 1125 { 1126 Reduction property = identifier.asReduction( modifiers, type ); 1127 property.setMeaning( Types.SYNTH_PROPERTY ); 1128 1129 if( lt() == Types.EQUAL ) 1130 { 1131 consume(); 1132 property.add( expression() ); 1133 } 1134 1135 endOfStatement(); 1136 return property; 1137 } 1138 1139 1140 1141 1165 1166 public Reduction methodDeclaration( Reduction modifiers, CSTNode type, Token identifier, boolean emptyOnly) throws SyntaxException, CompilationFailedException 1167 { 1168 Reduction method = identifier.asReduction( modifiers, type ); 1169 method.setMeaning( Types.SYNTH_METHOD ); 1170 1171 1174 consume(Types.LEFT_PARENTHESIS); 1175 method.add( parameterDeclarationList() ); 1176 consume(Types.RIGHT_PARENTHESIS); 1177 1178 1181 try 1182 { 1183 method.add( typeList( Types.KEYWORD_THROWS, true, 0 ) ); 1184 } 1185 catch (SyntaxException e) 1186 { 1187 controller.addError(e); 1188 method.add( Reduction.EMPTY ); 1189 } 1190 1191 1195 CSTNode body = null; 1196 1197 if( emptyOnly ) 1198 { 1199 if( lt() == Types.LEFT_CURLY_BRACE ) 1200 { 1201 controller.addError( "abstract and interface methods cannot have a body", la() ); 1202 } 1203 else 1204 { 1205 body = Reduction.EMPTY; 1206 endOfStatement(); 1207 } 1208 1209 } 1210 1211 if( body == null ) 1212 { 1213 body = statementBody(true); 1214 } 1215 1216 method.add( body ); 1217 1218 1219 return method; 1220 } 1221 1222 1223 1224 1240 1241 protected Reduction parameterDeclarationList() throws SyntaxException, CompilationFailedException 1242 { 1243 Reduction list = Reduction.newContainer(); 1244 1245 boolean expectDefaults = false; 1246 while( la().isA(Types.TYPE_NAME) ) { 1248 1249 1252 Reduction parameter = (Reduction)list.add( parameterDeclaration() ); 1253 1254 1258 if( expectDefaults || lt() == Types.EQUAL ) 1259 { 1260 expectDefaults = true; 1261 consume( Types.EQUAL ); 1262 1263 parameter.add( expression() ); 1264 } 1265 1266 1269 if( lt() == Types.COMMA ) 1270 { 1271 consume( Types.COMMA ); 1272 } 1273 else 1274 { 1275 break; 1276 } 1277 } 1278 1279 return list; 1280 } 1281 1282 1283 1284 1297 1298 protected Reduction parameterDeclaration() throws SyntaxException, CompilationFailedException 1299 { 1300 CSTNode type = optionalDatatype( false, false ); 1301 Reduction parameter = nameDeclaration( false ).asReduction( type ); 1302 parameter.setMeaning( Types.SYNTH_PARAMETER_DECLARATION ); 1303 1304 return parameter; 1305 } 1306 1307 1308 1309 1328 1329 protected CSTNode datatype( boolean allowVoid ) throws SyntaxException, CompilationFailedException 1330 { 1331 CSTNode datatype = scalarDatatype(allowVoid); 1332 1333 while( lt(true) == Types.LEFT_SQUARE_BRACKET ) 1334 { 1335 datatype = consume(Types.LEFT_SQUARE_BRACKET).asReduction( datatype ); 1336 consume( Types.RIGHT_SQUARE_BRACKET ); 1337 } 1338 1339 return datatype; 1340 } 1341 1342 1343 1344 1347 1348 protected CSTNode datatype() throws SyntaxException, CompilationFailedException 1349 { 1350 return datatype(true); 1351 } 1352 1353 1354 1355 1369 1370 protected CSTNode scalarDatatype( boolean allowVoid ) throws SyntaxException, CompilationFailedException 1371 { 1372 CSTNode datatype = null; 1373 1374 if( la().isA(allowVoid ? Types.PRIMITIVE_TYPE : Types.CREATABLE_PRIMITIVE_TYPE) ) 1375 { 1376 datatype = consume(); 1377 } 1378 else 1379 { 1380 datatype = dottedIdentifier(); 1381 } 1382 1383 return datatype; 1384 } 1385 1386 1387 1388 1405 1406 protected CSTNode statementBody( boolean requireBraces ) throws SyntaxException, CompilationFailedException 1407 { 1408 CSTNode body = null; 1409 1410 if (lt() == Types.LEFT_CURLY_BRACE) 1411 { 1412 Token brace = consume( Types.LEFT_CURLY_BRACE ); 1413 brace.setMeaning( Types.SYNTH_BLOCK ); 1414 1415 body = statementsUntilRightCurly(); 1416 body.set( 0, brace ); 1417 1418 consume( Types.RIGHT_CURLY_BRACE ); 1419 } 1420 else 1421 { 1422 if( requireBraces ) 1423 { 1424 error( Types.LEFT_CURLY_BRACE ); 1425 } 1426 else 1427 { 1428 body = statement(); 1429 } 1430 } 1431 1432 return body; 1433 } 1434 1435 1436 1437 1448 1449 protected Reduction statementsUntilRightCurly( ) throws SyntaxException, CompilationFailedException 1450 { 1451 Reduction block = Reduction.newContainer(); 1452 1453 while( lt() != Types.EOF && lt() != Types.RIGHT_CURLY_BRACE ) 1454 { 1455 try 1456 { 1457 block.add( statement() ); 1458 } 1459 catch( SyntaxException e ) 1460 { 1461 controller.addError( e ); 1462 recover(); 1463 } 1464 } 1465 1466 1467 return block; 1468 } 1469 1470 1471 1472 1475 1476 1534 1535 protected CSTNode statement( boolean allowUnlabelledBlocks ) throws SyntaxException, CompilationFailedException 1536 { 1537 CSTNode statement = null; 1538 1539 1542 CSTNode label = null; 1543 if( lt() == Types.IDENTIFIER && lt(2) == Types.COLON ) 1544 { 1545 label = consume( Types.IDENTIFIER ).asReduction(); 1546 label.setMeaning( Types.SYNTH_LABEL ); 1547 1548 consume( Types.COLON ); 1549 } 1550 1551 1554 switch( lt() ) 1555 { 1556 case Types.KEYWORD_ASSERT: 1557 { 1558 statement = assertStatement(); 1559 break; 1560 } 1561 1562 case Types.KEYWORD_BREAK: 1563 { 1564 statement = breakStatement(); 1565 break; 1566 } 1567 1568 case Types.KEYWORD_CONTINUE: 1569 { 1570 statement = continueStatement(); 1571 break; 1572 } 1573 1574 case Types.KEYWORD_IF: 1575 { 1576 statement = ifStatement(); 1577 break; 1578 } 1579 1580 case Types.KEYWORD_RETURN: 1581 { 1582 statement = returnStatement(); 1583 break; 1584 } 1585 1586 case Types.KEYWORD_SWITCH: 1587 { 1588 statement = switchStatement(); 1589 break; 1590 } 1591 1592 case Types.KEYWORD_SYNCHRONIZED: 1593 { 1594 statement = synchronizedStatement(); 1595 break; 1596 } 1597 1598 case Types.KEYWORD_THROW: 1599 { 1600 statement = throwStatement(); 1601 break; 1602 } 1603 1604 case Types.KEYWORD_TRY: 1605 { 1606 statement = tryStatement(); 1607 break; 1608 } 1609 1610 case Types.KEYWORD_FOR: 1611 { 1612 statement = forStatement(); 1613 break; 1614 } 1615 1616 case Types.KEYWORD_DO: 1617 { 1618 statement = doWhileStatement(); 1619 break; 1620 } 1621 1622 case Types.KEYWORD_WHILE: 1623 { 1624 statement = whileStatement(); 1625 break; 1626 } 1627 1628 case Types.SEMICOLON: 1629 { 1630 statement = consume().asReduction(); 1631 statement.setMeaning( Types.SYNTH_BLOCK ); 1632 break; 1633 } 1634 1635 case Types.LEFT_CURLY_BRACE: 1636 { 1637 1638 1645 statement = expression(); 1646 if( statement.isA(Types.SYNTH_CLOSURE) ) 1647 { 1648 if( !statement.get(1).hasChildren() ) 1649 { 1650 Reduction block = statement.getRoot().asReduction(); 1651 block.setMeaning( Types.SYNTH_BLOCK ); 1652 block.addChildrenOf( statement.get(2) ); 1653 1654 if( label == null && !allowUnlabelledBlocks ) 1655 { 1656 controller.addError( "groovy does not support anonymous blocks; please add a label", statement.getRoot() ); 1657 } 1658 1659 statement = block; 1660 } 1661 } 1662 else 1663 { 1664 1667 endOfStatement(); 1668 } 1669 1670 break; 1671 } 1672 1673 default: 1674 { 1675 try 1676 { 1677 statement = expression(); 1678 endOfStatement(); 1679 } 1680 catch (SyntaxException e) 1681 { 1682 controller.addError(e); 1683 recover(); 1684 } 1685 } 1686 } 1687 1688 1689 1692 if( label != null ) 1693 { 1694 label.add( statement ); 1695 statement = label; 1696 } 1697 1698 return statement; 1699 } 1700 1701 1702 1703 1706 1707 protected CSTNode statement( ) throws SyntaxException, CompilationFailedException 1708 { 1709 return statement( false ); 1710 } 1711 1712 1713 1714 1727 1728 protected Reduction assertStatement() throws SyntaxException, CompilationFailedException 1729 { 1730 Reduction statement = consume( Types.KEYWORD_ASSERT ).asReduction( expression() ); 1731 1732 if( lt() == Types.COLON ) 1733 { 1734 consume( Types.COLON ); 1735 statement.add( expression() ); 1736 } 1737 1738 endOfStatement(); 1739 1740 return statement; 1741 } 1742 1743 1744 1745 1759 1760 protected Reduction breakStatement() throws SyntaxException, CompilationFailedException 1761 { 1762 Reduction statement = consume(Types.KEYWORD_BREAK).asReduction(); 1763 if( lt(true) == Types.IDENTIFIER ) 1764 { 1765 statement.add( consume() ); 1766 } 1767 1768 endOfStatement(); 1769 return statement; 1770 1771 } 1772 1773 1774 1775 1789 1790 protected Reduction continueStatement() throws SyntaxException, CompilationFailedException 1791 { 1792 Reduction statement = consume(Types.KEYWORD_CONTINUE).asReduction(); 1793 if( lt(true) == Types.IDENTIFIER ) 1794 { 1795 statement.add( consume() ); 1796 } 1797 1798 endOfStatement(); 1799 return statement; 1800 1801 } 1802 1803 1804 1805 1818 1819 protected Reduction throwStatement() throws SyntaxException, CompilationFailedException 1820 { 1821 Reduction statement = consume(Types.KEYWORD_THROW).asReduction( expression() ); 1822 endOfStatement(); 1823 return statement; 1824 1825 } 1826 1827 1828 1829 1848 1849 protected Reduction ifStatement() throws SyntaxException, CompilationFailedException 1850 { 1851 1854 Reduction statement = consume(Types.KEYWORD_IF).asReduction(); 1855 1856 consume( Types.LEFT_PARENTHESIS ); 1857 1858 try 1859 { 1860 statement.add( expression() ); 1861 } 1862 catch( SyntaxException e ) 1863 { 1864 controller.addError( e ); 1865 recover( Types.RIGHT_PARENTHESIS ); 1866 } 1867 1868 consume( Types.RIGHT_PARENTHESIS ); 1869 1870 statement.add( statementBody(false) ); 1871 1872 1873 1878 if( lt() == Types.KEYWORD_ELSE ) 1879 { 1880 if( lt(2) == Types.KEYWORD_IF ) 1881 { 1882 consume( Types.KEYWORD_ELSE ); 1883 statement.add( ifStatement() ); 1884 } 1885 else 1886 { 1887 Reduction last = (Reduction)statement.add( consume(Types.KEYWORD_ELSE).asReduction() ); 1888 last.add( statementBody(false) ); 1889 } 1890 } 1891 1892 return statement; 1893 } 1894 1895 1896 1897 1911 1912 protected Reduction returnStatement() throws SyntaxException, CompilationFailedException 1913 { 1914 Reduction statement = consume(Types.KEYWORD_RETURN).asReduction(); 1915 1916 if( !la(true).isA(Types.ANY_END_OF_STATEMENT) ) 1917 { 1918 statement.add( expression() ); 1919 } 1920 1921 endOfStatement(); 1922 return statement; 1923 1924 } 1925 1926 1927 1928 1947 1948 protected Reduction switchStatement() throws SyntaxException, CompilationFailedException 1949 { 1950 Reduction statement = consume(Types.KEYWORD_SWITCH).asReduction(); 1951 consume( Types.LEFT_PARENTHESIS ); 1952 statement.add( expression() ); 1953 consume( Types.RIGHT_PARENTHESIS ); 1954 1955 1959 consume( Types.LEFT_CURLY_BRACE ); 1960 1961 boolean defaultFound = false; 1962 while( lt() == Types.KEYWORD_CASE || lt() == Types.KEYWORD_DEFAULT ) 1963 { 1964 1967 Reduction caseBlock = null; 1968 if( lt() == Types.KEYWORD_CASE ) 1969 { 1970 caseBlock = consume( Types.KEYWORD_CASE ).asReduction( expression() ); 1971 } 1972 else if( lt() == Types.KEYWORD_DEFAULT ) 1973 { 1974 if( defaultFound ) 1975 { 1976 controller.addError( "duplicate default entry in switch", la() ); 1977 } 1978 1979 caseBlock = consume( Types.KEYWORD_DEFAULT ).asReduction(); 1980 defaultFound = true; 1981 } 1982 else 1983 { 1984 error( new int[] { Types.KEYWORD_DEFAULT, Types.KEYWORD_CASE } ); 1985 recover( Types.SWITCH_ENTRIES ); 1986 } 1987 1988 consume( Types.COLON ); 1989 1990 1991 1994 boolean first = true; 1995 while( !la().isA(Types.SWITCH_BLOCK_TERMINATORS) ) 1996 { 1997 caseBlock.add( statement(first) ); 1998 first = false; 1999 } 2000 2001 statement.add( caseBlock ); 2002 } 2003 2004 consume( Types.RIGHT_CURLY_BRACE ); 2005 2006 return statement; 2007 } 2008 2009 2010 2011 2025 2026 protected Reduction synchronizedStatement() throws SyntaxException, CompilationFailedException 2027 { 2028 Reduction statement = consume(Types.KEYWORD_SYNCHRONIZED).asReduction(); 2029 2030 consume( Types.LEFT_PARENTHESIS ); 2031 statement.add( expression() ); 2032 consume( Types.RIGHT_PARENTHESIS ); 2033 2034 statement.add( statementBody(true) ); 2035 2036 return statement; 2037 2038 } 2039 2040 2041 2042 2066 2067 protected Reduction tryStatement() throws SyntaxException, CompilationFailedException 2068 { 2069 2070 2073 Reduction statement = consume(Types.KEYWORD_TRY).asReduction(); 2074 statement.add( statementBody(true) ); 2075 2076 2077 2080 Reduction catches = (Reduction)statement.add( Reduction.newContainer() ); 2081 while( lt() == Types.KEYWORD_CATCH ) 2082 { 2083 try 2084 { 2085 Reduction catchBlock = (Reduction)catches.add( consume(Types.KEYWORD_CATCH).asReduction() ); 2086 2087 consume( Types.LEFT_PARENTHESIS ); 2088 try 2089 { 2090 catchBlock.add( datatype(false) ); 2091 catchBlock.add( nameDeclaration(false) ); 2092 } 2093 catch( SyntaxException e ) 2094 { 2095 controller.addError( e ); 2096 recover( Types.RIGHT_PARENTHESIS ); 2097 } 2098 consume( Types.RIGHT_PARENTHESIS ); 2099 2100 catchBlock.add( statementBody(true) ); 2101 } 2102 catch( SyntaxException e ) 2103 { 2104 controller.addError( e ); 2105 recover(); 2106 } 2107 } 2108 2109 2112 if( lt() == Types.KEYWORD_FINALLY ) 2113 { 2114 consume( Types.KEYWORD_FINALLY ); 2115 statement.add( statementBody(true) ); 2116 } 2117 else 2118 { 2119 statement.add( Reduction.EMPTY ); 2120 } 2121 2122 return statement; 2123 } 2124 2125 2126 2127 2130 2131 2159 2160 protected Reduction forStatement() throws SyntaxException, CompilationFailedException 2161 { 2162 Reduction statement = consume( Types.KEYWORD_FOR ).asReduction(); 2163 2164 2175 consume( Types.LEFT_PARENTHESIS ); 2176 2177 getTokenStream().checkpoint(); 2178 2179 Reduction header = null; 2180 CSTNode datatype = optionalDatatype( false, false ); 2181 2182 if( lt(2) == Types.KEYWORD_IN || lt(2) == Types.COLON ) 2183 { 2184 Token name = nameDeclaration( false ); 2185 header = consume().asReduction( datatype, name, expression() ); 2186 } 2187 else 2188 { 2189 getTokenStream().restore(); 2190 header = Reduction.newContainer(); 2191 2192 Reduction init = Reduction.newContainer(); 2193 while( lt() != Types.SEMICOLON && lt() != Types.EOF ) 2194 { 2195 init.add( expression() ); 2196 2197 if( lt() != Types.SEMICOLON ) 2198 { 2199 consume( Types.COMMA ); 2200 } 2201 } 2202 2203 consume( Types.SEMICOLON ); 2204 2205 header.add( init ); 2206 2207 2208 2212 header.add( expression() ); 2213 consume( Types.SEMICOLON ); 2214 2215 2216 2220 Reduction incr = (Reduction)header.add( Reduction.newContainer() ); 2221 2222 while( lt() != Types.RIGHT_PARENTHESIS && lt() != Types.EOF ) 2223 { 2224 incr.add( expression() ); 2225 2226 if( lt() != Types.RIGHT_PARENTHESIS ) 2227 { 2228 consume( Types.COMMA ); 2229 } 2230 } 2231 } 2232 2233 consume( Types.RIGHT_PARENTHESIS ); 2234 2235 statement.add( header ); 2236 statement.add( statementBody(false) ); 2237 2238 return statement; 2239 } 2240 2241 2242 2243 2257 2258 protected Reduction doWhileStatement() throws SyntaxException, CompilationFailedException 2259 { 2260 Reduction statement = consume(Types.KEYWORD_DO).asReduction(); 2261 statement.add( statementBody(false) ); 2262 consume( Types.KEYWORD_WHILE ); 2263 2264 consume( Types.LEFT_PARENTHESIS ); 2265 try 2266 { 2267 statement.add( expression() ); 2268 } 2269 catch( SyntaxException e ) 2270 { 2271 controller.addError( e ); 2272 recover( Types.RIGHT_PARENTHESIS ); 2273 } 2274 consume( Types.RIGHT_PARENTHESIS ); 2275 2276 return statement; 2277 2278 } 2279 2280 2281 2282 2296 2297 protected Reduction whileStatement() throws SyntaxException, CompilationFailedException 2298 { 2299 Reduction statement = consume(Types.KEYWORD_WHILE).asReduction(); 2300 2301 consume( Types.LEFT_PARENTHESIS ); 2302 2303 try 2304 { 2305 statement.add( expression() ); 2306 } 2307 catch( SyntaxException e ) 2308 { 2309 controller.addError( e ); 2310 recover( Types.RIGHT_PARENTHESIS ); 2311 } 2312 consume( Types.RIGHT_PARENTHESIS ); 2313 2314 statement.add( statementBody(false) ); 2315 return statement; 2316 2317 } 2318 2319 2320 2321 2322 2325 2326 2339 2340 protected CSTNode expression( ) throws SyntaxException, CompilationFailedException 2341 { 2342 2345 ExpressionStack stack = new ExpressionStack( this ); 2346 CSTNode expression = null; 2347 2348 boolean bareMode = false; 2349 2350 MAIN_LOOP: do 2351 { 2352 2356 2362 Token next = la(stack); 2363 int type = next.getMeaningAs( EXPRESSION_SHIFT_HANDLERS ); 2364 2365 2371 SHIFT: switch( type ) 2372 { 2373 case Types.GSTRING_START: 2374 { 2375 if( stack.topIsAnExpression() ) 2376 { 2377 error( "gstring cannot directly follow another expression" ); 2378 } 2379 2380 stack.push( gstring() ); 2381 break; 2382 } 2383 2384 2385 case Types.CREATABLE_PRIMITIVE_TYPE: 2386 { 2387 stack.shiftIf( stack.atStartOfExpression(), "type name not valid in this context" ); 2388 break; 2389 } 2390 2391 2392 case Types.SIMPLE_EXPRESSION: 2393 { 2394 2395 2398 stack.shiftUnlessTopIsAnExpression( "literal cannot directly follow another expression" ); 2399 break; 2400 } 2401 2402 2403 case Types.KEYWORD_IDENTIFIER: 2404 { 2405 if( stack.top().isA(Types.DEREFERENCE_OPERATOR) && stack.topIsAnOperator() ) 2406 { 2407 la().setMeaning( Types.IDENTIFIER ); 2408 stack.shift(); 2409 } 2410 else 2411 { 2412 error( "not valid as an identifier in this context" ); 2413 } 2414 break; 2415 } 2416 2417 2418 case Types.ASSIGNMENT_OPERATOR: 2419 { 2420 stack.shiftIf( stack.topIsAModifiableExpression(), "left-hand-side of assignment must be modifiable" ); 2421 break; 2422 } 2423 2424 2425 case Types.PREFIX_OR_INFIX_OPERATOR: 2426 { 2427 if( stack.topIsAnOperator(0, true) ) 2428 { 2429 Types.makePrefix( next, false ); 2430 } 2431 stack.shift( ); 2432 break; 2433 } 2434 2435 2436 case Types.PREFIX_OPERATOR: 2437 { 2438 Types.makePrefix( next, false ); 2439 stack.shift( ); 2440 break; 2441 } 2442 2443 2444 case Types.QUESTION: 2445 case Types.INFIX_OPERATOR: 2446 { 2447 stack.shiftIfTopIsAnExpression( "infix operators may only follow expressions" ); 2448 break; 2449 } 2450 2451 2452 case Types.LEFT_PARENTHESIS: 2453 { 2454 2458 boolean condition = stack.atStartOfExpression() || (stack.topIsAnOperator() && !stack.top().isA(Types.DEREFERENCE_OPERATOR)); 2459 stack.shiftIf( condition, "sub-expression not valid at this position" ); 2460 break; 2461 } 2462 2463 2464 2465 case Types.LEFT_CURLY_BRACE: 2466 { 2467 if( stack.atStartOfExpression() || stack.topIsAnOperator() || stack.top().isA(Types.SYNTH_METHOD_CALL) ) 2468 { 2469 stack.push( closureExpression() ); 2470 } 2471 else 2472 { 2473 error( "closure not valid in this context" ); 2474 } 2475 break; 2476 } 2477 2478 2479 case Types.LEFT_SQUARE_BRACKET: 2480 { 2481 boolean isMap = false, insist = false; 2482 if( stack.topIsAnExpression() ) 2483 { 2484 insist = true; 2485 } 2486 stack.push( listOrMapExpression(isMap, insist) ); 2487 break; 2488 } 2489 2490 2491 case Types.KEYWORD_NEW: 2492 { 2493 if( stack.atStartOfExpression() || stack.topIsAnOperator() ) 2494 { 2495 stack.push( newExpression() ); 2496 } 2497 else 2498 { 2499 error( "new can follow the start of an expression or another operator" ); 2500 } 2501 break; 2502 } 2503 2504 2505 case Types.KEYWORD_INSTANCEOF: 2506 { 2507 stack.shiftIf( stack.topIsAnExpression(), "instanceof may only follow an expression" ); 2508 break; 2509 } 2510 2511 2512 default: 2513 { 2514 2515 2519 if( stack.size() == 1 && stack.topIsAnExpression() ) 2520 { 2521 break MAIN_LOOP; } 2523 else 2524 { 2525 error(); 2526 } 2527 } 2528 2529 2530 } 2531 2532 2533 2534 2540 boolean checkAgain = false, skipPatterns = false; 2541 CSTNode top0 = null, top1 = null, top2 = null; 2542 int nextPrecedence = 0, top1Precedence = 0; 2543 2544 REDUCE: do 2545 { 2546 if( !stack.topIsAnExpression() && !ExpressionSupport.isAPotentialTypeName(stack.top(), false) ) 2547 { 2548 break; 2549 } 2550 2551 2552 2555 checkAgain = false; 2556 skipPatterns = false; 2557 2558 top0 = stack.top(); 2559 top1 = stack.top(1); 2560 top2 = stack.top(2); 2561 2562 next = la( stack ); 2563 2564 2567 nextPrecedence = Types.getPrecedence( next.getMeaning(), false ); 2568 top1Precedence = Types.getPrecedence( top1.getMeaning(), false ); 2569 2570 2571 2572 2575 2576 2581 if( top1.isA(Types.LEFT_PARENTHESIS) ) 2582 { 2583 if( next.isA(Types.RIGHT_PARENTHESIS) ) 2584 { 2585 consume(); 2586 2587 2593 next = la(true); boolean castPrecluded = next.isA(Types.NEWLINE) || next.isA(Types.PRECLUDES_CAST_OPERATOR); 2595 2596 if( ExpressionSupport.isAPotentialTypeName(top0, false) && !castPrecluded ) 2597 { 2598 CSTNode name = stack.pop(); 2599 Reduction cast = ((Token)stack.pop()).asReduction( name ); 2600 cast.setMeaning( Types.SYNTH_CAST ); 2601 stack.push( cast ); 2602 } 2603 else 2604 { 2605 CSTNode subexpression = stack.pop(); 2606 stack.pop(); 2607 stack.push( subexpression ); 2608 } 2609 2610 checkAgain = true; 2611 continue; } 2613 else 2614 { 2615 skipPatterns = true; 2616 } 2617 } 2618 2619 2620 2628 if( top0.isA(Types.KEYWORD_NEW) && !top0.isAnExpression() ) 2629 { 2630 top0.markAsExpression(); 2631 2632 if( top1.isA(Types.DOT) ) 2633 { 2634 CSTNode theNew = stack.pop(); 2635 CSTNode theDot = stack.pop(); 2636 CSTNode context = stack.pop(); 2637 2638 theNew.set( 1, context ); 2639 stack.push( theNew ); 2640 2641 checkAgain = true; 2642 continue; } 2644 } 2645 2646 2647 2651 if( top1.isA(Types.DEREFERENCE_OPERATOR) && !top0.hasChildren() ) 2652 { 2653 stack.reduce( 3, 1, true ); 2654 2655 checkAgain = true; 2656 continue; } 2658 2659 2660 2661 2668 if( top0.isA(Types.SYNTH_LIST) && top1.isAnExpression() || ExpressionSupport.isAPotentialTypeName(top1, false) ) 2669 { 2670 2673 if( !top0.hasChildren() ) 2674 { 2675 boolean typePreceeds = ExpressionSupport.isAPotentialTypeName(top1, false); 2676 boolean potentialCast = top2.isA(Types.LEFT_PARENTHESIS); 2677 boolean potentialDecl = top2.isA(Types.LEFT_PARENTHESIS) || top2.isA(Types.UNKNOWN); 2678 boolean classReference = next.isA(Types.DOT) && la(2).isA(Types.KEYWORD_CLASS); 2679 if( !(typePreceeds && (potentialCast || potentialDecl || classReference)) ) 2680 { 2681 error( "empty square brackets are only valid on type names" ); 2682 } 2683 2684 2689 Reduction array = stack.pop().asReduction(); 2690 array.setMeaning( Types.LEFT_SQUARE_BRACKET ); 2691 array.add( stack.pop() ); 2692 2693 while( lt(true) == Types.LEFT_SQUARE_BRACKET ) 2694 { 2695 array = consume( Types.LEFT_SQUARE_BRACKET ).asReduction( array ); 2696 consume( Types.RIGHT_SQUARE_BRACKET ); 2697 } 2698 2699 2700 2704 if( classReference ) 2705 { 2706 CSTNode reference = consume(Types.DOT).asReduction(array, consume(Types.KEYWORD_CLASS)); 2707 reference.markAsExpression(); 2708 stack.push( reference ); 2709 2710 } 2711 else if( lt(true) == Types.IDENTIFIER && lt(2) == Types.EQUAL ) 2712 { 2713 stack.push( variableDeclarationExpression(array) ); 2714 } 2715 else if( stack.top().isA(Types.LEFT_PARENTHESIS) && la(true).isA(Types.RIGHT_PARENTHESIS) ) 2716 { 2717 CSTNode cast = ((Token)stack.pop()).asReduction( array ); 2718 cast.setMeaning( Types.SYNTH_CAST ); 2719 stack.push( cast ); 2720 consume( Types.RIGHT_PARENTHESIS ); 2721 } 2722 else 2723 { 2724 error( "found array type where none expected" ); 2725 } 2726 } 2727 2728 2729 2732 else 2733 { 2734 CSTNode list = stack.pop(); 2735 CSTNode base = stack.pop(); 2736 2737 Reduction result = ((Token)list.get(0)).dup().asReduction(); 2738 result.setMeaning( Types.LEFT_SQUARE_BRACKET ); 2739 result.add( base ); 2740 2741 if( list.children() == 1 ) 2742 { 2743 result.add( list.get(1) ); 2744 } 2745 else 2746 { 2747 result.add( list ); 2748 } 2749 2750 result.markAsExpression(); 2751 stack.push( result ); 2752 } 2753 2754 checkAgain = true; 2755 continue; 2757 } 2758 2759 2760 2761 2766 if( la(true).isA(Types.IDENTIFIER) && lt(2) == Types.EQUALS && ExpressionSupport.isAPotentialTypeName(top0, false) ) 2767 { 2768 stack.push( variableDeclarationExpression(stack.pop()) ); 2769 2770 checkAgain = true; 2771 continue; } 2773 2774 2775 2781 if( top1.isA(Types.SYNTH_METHOD_CALL) && top0.isA(Types.SYNTH_CLOSURE) ) 2782 { 2783 CSTNode parameters = top1.get(2); 2784 2785 int last = parameters.size() - 1; 2786 if( last > 0 && parameters.get(last).isA(Types.SYNTH_CLOSURE) ) 2787 { 2788 error( "you may only pass one closure to a method implicitly" ); 2789 } 2790 2791 parameters.add( stack.pop() ); 2792 2793 checkAgain = true; 2794 continue; } 2796 2797 2798 2803 if( ExpressionSupport.isInvokable(top0) && (next.isA(Types.LEFT_CURLY_BRACE) || la(true).isA(Types.METHOD_CALL_STARTERS)) ) 2804 { 2805 2807 CSTNode name = stack.pop(); 2808 2809 Reduction method = null; 2810 switch( next.getMeaning() ) 2811 { 2812 case Types.LEFT_PARENTHESIS: 2813 method = consume().asReduction(); 2814 method.add( name ); 2815 method.add( la().isA(Types.RIGHT_PARENTHESIS) ? Reduction.newContainer() : parameterList() ); 2816 consume( Types.RIGHT_PARENTHESIS ); 2817 break; 2818 2819 case Types.LEFT_CURLY_BRACE: 2820 method = Token.newSymbol( Types.LEFT_PARENTHESIS, next.getStartLine(), next.getStartColumn() ).asReduction(); 2821 method.add( name ); 2822 method.add( Reduction.newContainer() ); 2823 break; 2824 2825 default: 2826 method = Token.newSymbol( Types.LEFT_PARENTHESIS, next.getStartLine(), next.getStartColumn() ).asReduction(); 2827 method.add( name ); 2828 method.add( parameterList() ); 2829 break; 2830 } 2831 2832 method.setMeaning( Types.SYNTH_METHOD_CALL ); 2833 method.markAsExpression(); 2834 2835 stack.push( method ); 2836 2837 if( lt() != Types.LEFT_CURLY_BRACE ) 2838 { 2839 checkAgain = true; 2840 } 2841 2842 continue; } 2844 2845 2846 2851 if( next.isA(Types.POSTFIX_OPERATOR) && stack.topIsAnExpression() ) 2852 { 2853 if( !ExpressionSupport.isAVariable(stack.top()) ) 2854 { 2855 error( "increment/decrement operators can only be applied to variables" ); 2856 } 2857 2858 Types.makePostfix( next, true ); 2859 2860 stack.shift(); 2861 stack.reduce( 2, 0, true ); 2862 2863 checkAgain = true; 2864 continue; } 2866 2867 2868 2875 if( top1.isA(Types.QUESTION) ) 2876 { 2877 boolean reduce = false; 2878 2879 if( la().isA(Types.COLON) ) 2880 { 2881 if( top1.hasChildren() ) 2882 { 2883 error( "ternary operator can have only three clauses" ); 2884 } 2885 2886 consume(); 2887 stack.reduce( 3, 1, false ); 2888 checkAgain = true; 2889 } 2890 else if( Types.getPrecedence(next.getMeaning(), false) < 10 ) 2891 { 2892 stack.reduce( 2, 1, false ); 2893 stack.top().setMeaning( Types.SYNTH_TERNARY ); 2894 checkAgain = true; 2895 } 2896 2897 2898 continue; } 2900 2901 2902 2903 2904 2907 2908 2916 if( skipPatterns || !ExpressionSupport.isAnOperator(top1, false) ) 2917 { 2918 break; } 2920 2921 2922 switch( top1.getMeaningAs(EXPRESSION_REDUCE_HANDLERS) ) 2923 { 2924 2928 case Types.PREFIX_PLUS_PLUS: 2929 case Types.PREFIX_MINUS_MINUS: 2930 { 2931 if( nextPrecedence < top1Precedence ) 2932 { 2933 if( !ExpressionSupport.isAVariable(stack.top()) ) 2934 { 2935 error( "increment/decrement operators can only be applied to variables" ); 2936 } 2937 2938 stack.reduce( 2, 1, true ); 2939 checkAgain = true; 2940 } 2941 2942 break; 2943 } 2944 2945 2946 2949 case Types.PURE_PREFIX_OPERATOR: 2950 { 2951 if( nextPrecedence < top1Precedence ) 2952 { 2953 stack.reduce( 2, 1, true ); 2954 checkAgain = true; 2955 } 2956 2957 break; 2958 } 2959 2960 2961 2964 case Types.ASSIGNMENT_OPERATOR: 2965 { 2966 if( nextPrecedence < top1Precedence ) 2967 { 2968 stack.reduce( 3, 1, true ); 2969 checkAgain = true; 2970 } 2971 2972 break; 2973 } 2974 2975 2976 2979 case Types.KEYWORD_INSTANCEOF: 2980 { 2981 if( nextPrecedence < top1Precedence ) 2982 { 2983 if( !ExpressionSupport.isAPotentialTypeName(top0, false) ) 2984 { 2985 error( "instanceof right-hand side must be a valid type name" ); 2986 } 2987 2988 stack.reduce( 3, 1, true ); 2989 checkAgain = true; 2990 } 2991 2992 break; 2993 } 2994 2995 2996 2999 case Types.INFIX_OPERATOR: 3000 { 3001 if( nextPrecedence <= top1Precedence ) 3002 { 3003 stack.reduce( 3, 1, true ); 3004 checkAgain = true; 3005 } 3006 3007 break; 3008 } 3009 3010 3011 3014 default: 3015 { 3016 throw new GroovyBugError( "found unexpected token during REDUCE [" + top1.getMeaning() + "]" ); 3017 } 3018 } 3019 3020 } while( checkAgain ); 3021 3022 } while( true ); 3023 3024 3025 if( stack.size() == 1 && stack.topIsAnExpression() ) 3026 { 3027 expression = stack.pop(); 3028 } 3029 else 3030 { 3031 error( "expression incomplete" ); 3032 } 3033 3034 3035 return expression; 3037 } 3038 3039 3040 private static final int EXPRESSION_SHIFT_HANDLERS[] = { 3041 Types.GSTRING_START 3042 , Types.CREATABLE_PRIMITIVE_TYPE 3043 , Types.SIMPLE_EXPRESSION 3044 , Types.KEYWORD_IDENTIFIER 3045 , Types.ASSIGNMENT_OPERATOR 3046 , Types.PREFIX_OR_INFIX_OPERATOR 3047 , Types.PREFIX_OPERATOR 3048 , Types.QUESTION 3049 , Types.INFIX_OPERATOR 3050 , Types.LEFT_PARENTHESIS 3051 , Types.LEFT_CURLY_BRACE 3052 , Types.LEFT_SQUARE_BRACKET 3053 , Types.KEYWORD_NEW 3054 , Types.KEYWORD_INSTANCEOF 3055 }; 3056 3057 private static final int EXPRESSION_REDUCE_HANDLERS[] = { 3058 Types.PREFIX_PLUS_PLUS 3059 , Types.PREFIX_MINUS_MINUS 3060 , Types.PURE_PREFIX_OPERATOR 3061 , Types.ASSIGNMENT_OPERATOR 3062 , Types.KEYWORD_INSTANCEOF 3063 , Types.INFIX_OPERATOR 3064 }; 3065 3066 3067 3068 3086 3087 protected Reduction variableDeclarationExpression( CSTNode datatype ) throws SyntaxException, CompilationFailedException 3088 { 3089 Reduction expression = ((Token)datatype.get(0)).dup().asReduction( datatype ); expression.setMeaning( Types.SYNTH_VARIABLE_DECLARATION ); 3091 3092 boolean done = false; 3093 do 3094 { 3095 try 3096 { 3097 Reduction declaration = (Reduction)expression.add( nameDeclaration(false).asReduction() ); 3098 consume( Types.EQUAL ); 3099 declaration.add( expression() ); 3100 } 3101 catch( SyntaxException e ) 3102 { 3103 controller.addError( e ); 3104 recover( Types.ANY_END_OF_STATEMENT ); 3105 } 3106 3107 if( lt() == Types.COMMA ) 3108 { 3109 consume( Types.COMMA ); 3110 } 3111 else 3112 { 3113 done = true; 3114 } 3115 3116 } while( !done ); 3117 3118 3119 return expression; 3120 } 3121 3122 3123 3124 3137 3138 protected Reduction gstring() throws SyntaxException, CompilationFailedException 3139 { 3140 3143 Reduction data = Reduction.newContainer(); 3144 3145 consume( Types.GSTRING_START ); 3146 3147 while( lt() != Types.GSTRING_END && lt() != Types.EOF ) 3148 { 3149 switch( lt() ) 3150 { 3151 case Types.STRING: 3152 data.add( consume() ); 3153 break; 3154 3155 case Types.GSTRING_EXPRESSION_START: 3156 consume(); 3157 data.add( expression() ); 3158 consume( Types.GSTRING_EXPRESSION_END ); 3159 break; 3160 3161 default: 3162 throw new GroovyBugError( "gstring found invalid token: " + la() ); 3163 } 3164 } 3165 3166 Reduction complete = consume( Types.GSTRING_END ).asReduction(); 3167 complete.addChildrenOf( data ); 3168 3169 complete.setMeaning( Types.SYNTH_GSTRING ); 3170 3171 return complete; 3173 } 3174 3175 3176 3177 3178 3199 3200 protected Reduction parameterList() throws SyntaxException, CompilationFailedException 3201 { 3202 3205 Reduction list = Reduction.newContainer(); 3206 Reduction named = null; 3207 3208 boolean done = false; 3209 3210 do 3211 { 3212 if( la().canMean(Types.IDENTIFIER) && la(2).isA(Types.COLON) ) 3213 { 3214 if( named == null ) 3215 { 3216 named = Token.newPlaceholder(Types.SYNTH_MAP).asReduction(); 3217 list.add( named ); 3218 } 3219 3220 Token name = nameReference(false); 3221 name.setMeaning( Types.STRING ); 3222 3223 named.add( consume(Types.COLON).asReduction(name, expression()) ); 3224 } 3225 else 3226 { 3227 list.add( expression() ); 3228 } 3229 3230 3231 if( lt() == Types.COMMA ) 3232 { 3233 consume(); 3234 } 3235 else 3236 { 3237 done = true; 3238 } 3239 3240 3241 } while( !done ); 3242 3243 return list; 3245 } 3246 3247 3248 3249 3272 3273 protected Reduction newExpression() throws SyntaxException, CompilationFailedException 3274 { 3275 3278 Reduction expression = consume(Types.KEYWORD_NEW).asReduction(); 3279 CSTNode scalarType = scalarDatatype(false); 3280 3281 if( lt(true) == Types.LEFT_SQUARE_BRACKET ) 3282 { 3283 3287 boolean implicit = (lt(2) == Types.RIGHT_SQUARE_BRACKET); 3288 Reduction dimensions = implicit ? Reduction.EMPTY : Reduction.newContainer(); 3289 int count = 0; 3290 CSTNode arrayType = scalarType; 3291 3292 while( lt(true) == Types.LEFT_SQUARE_BRACKET ) 3293 { 3294 arrayType = consume(Types.LEFT_SQUARE_BRACKET).asReduction( arrayType ); 3295 count++; 3296 3297 if( !implicit ) 3298 { 3299 dimensions.add( expression() ); 3300 } 3301 3302 consume(Types.RIGHT_SQUARE_BRACKET); 3303 } 3304 3305 expression.add( arrayType ); 3306 expression.add( dimensions ); 3307 3308 3311 if( implicit ) 3312 { 3313 expression.add( tupleExpression(0, count) ); 3314 } 3315 3316 } 3317 3318 else 3319 { 3320 expression.add( scalarType ); 3321 3322 3323 3326 Reduction parameters = null; 3327 3328 consume( Types.LEFT_PARENTHESIS ); 3329 parameters = (lt() == Types.RIGHT_PARENTHESIS ? Reduction.newContainer() : parameterList()); 3330 consume( Types.RIGHT_PARENTHESIS ); 3331 3332 expression.add( parameters ); 3333 3334 3335 3338 if( lt() == Types.LEFT_CURLY_BRACE ) 3339 { 3340 if( lt(2) == Types.PIPE || lt(2) == Types.DOUBLE_PIPE ) 3341 { 3342 parameters.add( closureExpression() ); 3343 } 3344 else 3345 { 3346 expression.add( typeBody(true, false, false) ); 3347 } 3348 } 3349 } 3350 3351 return expression; 3353 } 3354 3355 3356 3357 3370 3371 protected Reduction tupleExpression( int level, int depth ) throws SyntaxException, CompilationFailedException 3372 { 3373 Reduction data = consume(Types.LEFT_CURLY_BRACE).asReduction(); 3374 data.setMeaning( Types.SYNTH_TUPLE ); 3375 3376 if( lt() != Types.RIGHT_CURLY_BRACE ) 3377 { 3378 int child = level + 1; 3379 boolean leaf = (child == depth); 3380 3381 do 3382 { 3383 data.add( leaf ? expression() : tupleExpression(child, depth) ); 3384 3385 } while( lt() == Types.COMMA && (consume() != null) ); 3386 } 3387 3388 consume( Types.RIGHT_CURLY_BRACE ); 3389 3390 return data; 3391 } 3392 3393 3394 3395 3412 3413 protected Reduction closureExpression( ) throws SyntaxException, CompilationFailedException 3414 { 3415 3418 Reduction closure = consume(Types.LEFT_CURLY_BRACE).asReduction(); 3419 closure.setMeaning( Types.SYNTH_CLOSURE ); 3420 boolean specified = (lt() == Types.PIPE) || (lt() == Types.DOUBLE_PIPE); 3421 3422 3431 if( !specified ) 3432 { 3433 getTokenStream().checkpoint(); 3434 CSTNode type = optionalDatatype( true, false ); 3435 if( lt() == Types.IDENTIFIER && (lt(2) == Types.PIPE || lt(2) == Types.COMMA) ) 3436 { 3437 specified = true; 3438 } 3439 3440 getTokenStream().restore(); 3441 } 3442 3443 3444 3447 if( specified ) 3448 { 3449 if( lt() == Types.DOUBLE_PIPE ) 3450 { 3451 consume( Types.DOUBLE_PIPE ); 3452 closure.add( Reduction.newContainer() ); 3453 } 3454 else 3455 { 3456 3460 if( lt() == Types.PIPE ) 3461 { 3462 consume(Types.PIPE); 3463 } 3464 3465 closure.add( parameterDeclarationList() ); 3466 consume(Types.PIPE); 3467 } 3468 } 3469 else 3470 { 3471 closure.add( Reduction.newContainer() ); 3472 } 3473 3474 3475 3478 closure.add( statementsUntilRightCurly() ); 3479 consume( Types.RIGHT_CURLY_BRACE ); 3480 3481 return closure; 3483 } 3484 3485 3486 3487 3507 3508 protected Reduction listOrMapExpression( boolean isMap, boolean insist ) throws SyntaxException, CompilationFailedException 3509 { 3510 Reduction expression = consume(Types.LEFT_SQUARE_BRACKET).asReduction(); 3511 expression.setMeaning( Types.SYNTH_LIST ); 3512 3513 if( lt() == Types.COLON ) 3514 { 3515 if( !isMap && insist ) 3516 { 3517 error( "expected list" ); 3518 } 3519 3520 isMap = true; 3521 expression.setMeaning( Types.SYNTH_MAP ); 3522 consume(); 3523 if( lt() != Types.RIGHT_SQUARE_BRACKET ) 3524 { 3525 error( "expected empty map" ); 3526 } 3527 } 3528 3529 3530 3535 boolean done = (lt() == Types.RIGHT_SQUARE_BRACKET); 3536 3537 while( !done ) 3538 { 3539 CSTNode element = expression(); 3540 3541 if( !insist ) 3542 { 3543 insist = true; 3544 if( lt() == Types.COLON ) 3545 { 3546 isMap = true; 3547 expression.setMeaning(Types.SYNTH_MAP); 3548 } 3549 } 3550 3551 if( isMap ) 3552 { 3553 element = consume(Types.COLON).asReduction( element, expression() ); 3554 } 3555 3556 expression.add( element ); 3557 3558 if( lt() == Types.COMMA ) { consume(); } else { done = true; } 3559 } 3560 3561 consume(Types.RIGHT_SQUARE_BRACKET); 3562 3563 return expression; 3564 } 3565 3566 3567 3568 3571 3572 protected Reduction listOrMapExpression( ) throws SyntaxException, CompilationFailedException 3573 { 3574 return listOrMapExpression( false, false ); 3575 } 3576 3577 3578 3579 3580 3581 3582 3585 3586 3589 3590 protected UnexpectedTokenException error( Token found, int[] expectedTypes, boolean throwIt, String comment ) throws SyntaxException 3591 { 3592 UnexpectedTokenException e = new UnexpectedTokenException( found, expectedTypes, comment ); 3593 3594 if( throwIt ) 3595 { 3596 throw e; 3597 } 3598 3599 return e; 3600 } 3601 3602 3603 3607 3608 protected UnexpectedTokenException error( int[] expectedTypes, boolean throwIt, int k, String comment ) throws SyntaxException, CompilationFailedException 3609 { 3610 return error( la(k), expectedTypes, throwIt, comment ); 3611 } 3612 3613 3614 3615 3618 3619 protected UnexpectedTokenException error( int[] expectedTypes, boolean throwIt, int k ) throws SyntaxException, CompilationFailedException 3620 { 3621 return error( expectedTypes, throwIt, k, null ); 3622 } 3623 3624 3625 3626 3629 3630 protected void error( int[] expectedTypes ) throws SyntaxException, CompilationFailedException 3631 { 3632 throw error( expectedTypes, false, 1, null ); 3633 } 3634 3635 3636 3637 3640 3641 protected void error() throws SyntaxException, CompilationFailedException 3642 { 3643 throw error( null, true, 1, null ); 3644 } 3645 3646 3647 3648 3651 3652 protected void error( String comment ) throws SyntaxException, CompilationFailedException 3653 { 3654 throw error( null, true, 1, comment ); 3655 } 3656 3657 3658 3659 3662 3663 protected void error( Token found, String comment ) throws SyntaxException 3664 { 3665 throw error( found, null, true, comment ); 3666 } 3667 3668 3669 3670 3673 3674 protected void error( int expectedType ) throws SyntaxException, CompilationFailedException 3675 { 3676 error( new int[] { expectedType } ); 3677 } 3678 3679 3680 3681 3682 3685 3686 3691 3692 public void recover( int[] safe, boolean ignoreNewlines ) throws SyntaxException, CompilationFailedException 3693 { 3694 Token leading = la( ignoreNewlines ); 3695 3696 while( true ) 3697 { 3698 Token next = la( ignoreNewlines ); 3699 if( next.isA(Types.EOF) || next.isOneOf(safe) ) 3700 { 3701 break; 3702 } 3703 else 3704 { 3705 consume( ignoreNewlines ); 3706 } 3707 } 3708 3709 if( la(ignoreNewlines) == leading ) 3710 { 3711 consume( ignoreNewlines ); 3712 } 3713 } 3714 3715 3716 3717 3720 3721 public void recover( int safe, boolean ignoreNewlines ) throws SyntaxException, CompilationFailedException 3722 { 3723 Token leading = la( ignoreNewlines ); 3724 3725 while( true ) 3726 { 3727 Token next = la( ignoreNewlines ); 3728 if( next.isA(Types.EOF) || next.isA(safe) ) 3729 { 3730 break; 3731 } 3732 else 3733 { 3734 consume( ignoreNewlines ); 3735 } 3736 } 3737 3738 if( la(ignoreNewlines) == leading ) 3739 { 3740 consume( ignoreNewlines ); 3741 } 3742 } 3743 3744 3745 3746 3749 3750 public void recover( int[] safe ) throws SyntaxException, CompilationFailedException 3751 { 3752 recover( safe, false ); 3753 } 3754 3755 3756 3757 3760 3761 public void recover( int safe ) throws SyntaxException, CompilationFailedException 3762 { 3763 recover( safe, false ); 3764 } 3765 3766 3767 3768 3771 3772 public void recover( ) throws SyntaxException, CompilationFailedException 3773 { 3774 recover( Types.ANY_END_OF_STATEMENT, true ); 3775 } 3776 3777 3778 3779 3780 3783 3784 3789 3790 protected Token la( int k, boolean significantNewlines ) throws SyntaxException, CompilationFailedException 3791 { 3792 Token token = Token.NULL; 3793 3794 3800 try 3801 { 3802 int streamK = 1; 3803 while( k > 0 && token.getMeaning() != Types.EOF ) 3804 { 3805 token = getTokenStream().la( streamK ); 3806 streamK += 1; 3807 3808 if( token == null ) 3809 { 3810 token = Token.EOF; 3811 } 3812 else if( token.getMeaning() == Types.NEWLINE ) 3813 { 3814 if( significantNewlines ) 3815 { 3816 k -= 1; 3817 } 3818 } 3819 else 3820 { 3821 k -= 1; 3822 } 3823 } 3824 } 3825 catch( ReadException e ) 3826 { 3827 controller.addFatalError( new SimpleMessage(e.getMessage()) ); 3828 } 3829 3830 return token; 3831 } 3832 3833 3834 3835 3838 3839 protected Token la( int k ) throws SyntaxException, CompilationFailedException 3840 { 3841 return la( k, false ); 3842 } 3843 3844 3845 3846 3849 3850 protected Token la( boolean significantNewlines ) throws SyntaxException, CompilationFailedException 3851 { 3852 return la( 1, significantNewlines ); 3853 } 3854 3855 3856 3857 3860 3861 protected Token la() throws SyntaxException, CompilationFailedException 3862 { 3863 return la( 1, false ); 3864 } 3865 3866 3867 3868 3873 3874 protected Token la( ExpressionStack stack ) throws SyntaxException, CompilationFailedException 3875 { 3876 Token next = la(); 3877 3878 if( stack.canComplete() && next.isA(Types.UNSAFE_OVER_NEWLINES) ) 3879 { 3880 if( la(true).getMeaning() == Types.NEWLINE ) 3881 { 3882 next = la(true); 3883 } 3884 } 3885 3886 return next; 3887 } 3888 3889 3890 3891 3892 3895 3896 protected int lt( int k, boolean significantNewlines ) throws SyntaxException, CompilationFailedException 3897 { 3898 return la(k, significantNewlines).getMeaning(); 3899 } 3900 3901 3902 3903 3906 3907 protected int lt( int k ) throws SyntaxException, CompilationFailedException 3908 { 3909 return la(k).getMeaning(); 3910 } 3911 3912 3913 3914 3917 3918 protected int lt( boolean significantNewlines ) throws SyntaxException, CompilationFailedException 3919 { 3920 return la(significantNewlines).getMeaning(); 3921 } 3922 3923 3924 3925 3928 3929 protected int lt() throws SyntaxException, CompilationFailedException 3930 { 3931 return la().getMeaning(); 3932 } 3933 3934 3935 3936 3937 3940 3941 3947 3948 protected Token consume( int type, boolean significantNewlines ) throws SyntaxException, CompilationFailedException 3949 { 3950 try 3951 { 3952 if( !la(significantNewlines).isA(type) ) 3953 { 3954 error( type ); 3955 } 3956 3957 if( !significantNewlines ) 3958 { 3959 while( lt(true) == Types.NEWLINE ) 3960 { 3961 getTokenStream().consume(Types.NEWLINE); 3962 } 3963 } 3964 3965 return getTokenStream().consume(type); 3966 } 3967 catch( ReadException e ) 3968 { 3969 controller.addFatalError( new SimpleMessage(e.getMessage()) ); 3970 } 3971 3972 throw new GroovyBugError( "this should never happen" ); 3973 } 3974 3975 3976 3977 3981 3982 protected Token consume( int type ) throws SyntaxException, CompilationFailedException 3983 { 3984 return consume( type, type == Types.NEWLINE ); 3985 } 3986 3987 3988 3989 3992 3993 protected Token consume() throws SyntaxException, CompilationFailedException 3994 { 3995 return consume( lt(), false ); 3996 } 3997 3998 3999 4000 4005 4006 protected Token consume( boolean significantNewlines ) throws SyntaxException, CompilationFailedException 4007 { 4008 return consume( lt(significantNewlines), significantNewlines ); 4009 } 4010 4011} 4012 | Popular Tags |