1 46 package org.codehaus.groovy.syntax.parser; 47 48 import java.util.HashMap ; 49 import java.util.Map ; 50 import java.util.List ; 51 import java.util.ArrayList ; 52 53 import org.codehaus.groovy.ast.ClassNode; 54 import org.codehaus.groovy.ast.InnerClassNode; 55 import org.codehaus.groovy.ast.ConstructorNode; 56 import org.codehaus.groovy.ast.MethodNode; 57 import org.codehaus.groovy.ast.MixinNode; 58 import org.codehaus.groovy.ast.ModuleNode; 59 import org.codehaus.groovy.ast.Parameter; 60 import org.codehaus.groovy.ast.PropertyNode; 61 import org.codehaus.groovy.ast.Type; 62 import org.codehaus.groovy.ast.expr.ArrayExpression; 63 import org.codehaus.groovy.ast.expr.BinaryExpression; 64 import org.codehaus.groovy.ast.expr.BooleanExpression; 65 import org.codehaus.groovy.ast.expr.CastExpression; 66 import org.codehaus.groovy.ast.expr.ClassExpression; 67 import org.codehaus.groovy.ast.expr.ClosureExpression; 68 import org.codehaus.groovy.ast.expr.ConstantExpression; 69 import org.codehaus.groovy.ast.expr.ConstructorCallExpression; 70 import org.codehaus.groovy.ast.expr.Expression; 71 import org.codehaus.groovy.ast.expr.GStringExpression; 72 import org.codehaus.groovy.ast.expr.ListExpression; 73 import org.codehaus.groovy.ast.expr.MapExpression; 74 import org.codehaus.groovy.ast.expr.MethodCallExpression; 75 import org.codehaus.groovy.ast.expr.NegationExpression; 76 import org.codehaus.groovy.ast.expr.NotExpression; 77 import org.codehaus.groovy.ast.expr.PostfixExpression; 78 import org.codehaus.groovy.ast.expr.PrefixExpression; 79 import org.codehaus.groovy.ast.expr.PropertyExpression; 80 import org.codehaus.groovy.ast.expr.RangeExpression; 81 import org.codehaus.groovy.ast.expr.RegexExpression; 82 import org.codehaus.groovy.ast.expr.TernaryExpression; 83 import org.codehaus.groovy.ast.expr.TupleExpression; 84 import org.codehaus.groovy.ast.expr.VariableExpression; 85 import org.codehaus.groovy.ast.stmt.AssertStatement; 86 import org.codehaus.groovy.ast.stmt.BlockStatement; 87 import org.codehaus.groovy.ast.stmt.BreakStatement; 88 import org.codehaus.groovy.ast.stmt.CaseStatement; 89 import org.codehaus.groovy.ast.stmt.CatchStatement; 90 import org.codehaus.groovy.ast.stmt.ContinueStatement; 91 import org.codehaus.groovy.ast.stmt.DoWhileStatement; 92 import org.codehaus.groovy.ast.stmt.EmptyStatement; 93 import org.codehaus.groovy.ast.stmt.ExpressionStatement; 94 import org.codehaus.groovy.ast.stmt.ForStatement; 95 import org.codehaus.groovy.ast.stmt.IfStatement; 96 import org.codehaus.groovy.ast.stmt.ReturnStatement; 97 import org.codehaus.groovy.ast.stmt.Statement; 98 import org.codehaus.groovy.ast.stmt.SwitchStatement; 99 import org.codehaus.groovy.ast.stmt.SynchronizedStatement; 100 import org.codehaus.groovy.ast.stmt.ThrowStatement; 101 import org.codehaus.groovy.ast.stmt.TryCatchStatement; 102 import org.codehaus.groovy.ast.stmt.WhileStatement; 103 import org.codehaus.groovy.control.SourceUnit; 104 import org.codehaus.groovy.syntax.CSTNode; 105 import org.codehaus.groovy.syntax.Token; 106 import org.codehaus.groovy.syntax.Types; 107 import org.codehaus.groovy.syntax.Numbers; 108 import org.codehaus.groovy.GroovyBugError; 109 import org.objectweb.asm.Constants; 110 111 112 113 124 125 public class ASTBuilder 126 { 127 128 private static final String [] EMPTY_STRING_ARRAY = new String [0]; 129 private static final String [] DEFAULT_IMPORTS = { "java.lang.", "groovy.lang.", "groovy.util." }; 130 131 132 133 136 137 private SourceUnit controller; private ClassLoader classLoader; private Map imports; private String packageName; private List newClasses = new ArrayList (); private ModuleNode output; 143 144 145 148 149 public ASTBuilder( SourceUnit sourceUnit, ClassLoader classLoader ) 150 { 151 this.controller = sourceUnit; 152 this.classLoader = classLoader; 153 this.imports = new HashMap (); 154 this.packageName = null; 155 } 156 157 158 159 162 163 public ClassLoader getClassLoader() 164 { 165 return this.classLoader; 166 } 167 168 169 170 171 174 175 178 179 public ModuleNode build( CSTNode input ) throws ParserException 180 { 181 this.newClasses.clear(); 182 this.output = new ModuleNode( controller ); 183 resolutions.clear(); 184 185 191 packageName = packageDeclaration( input.get(1) ); 192 output.setPackageName( packageName ); 193 194 importStatements( output, input.get(2) ); 195 196 for( int i = 3; i < input.size(); ++i ) 197 { 198 topLevelStatement( output, input.get(i) ); 199 } 200 201 if( output.isEmpty() ) 202 { 203 output.addStatement( new BlockStatement() ); 204 } 205 206 return output; 207 } 208 209 210 211 212 215 216 219 220 protected String packageDeclaration( CSTNode reduction ) 221 { 222 if( reduction.hasChildren() ) 223 { 224 return makeName( reduction.get(1) ); 225 } 226 227 return null; 228 229 } 230 231 232 233 236 237 protected void importStatements( ModuleNode module, CSTNode container ) 238 { 239 for( int i = 1; i < container.size(); ++i) 240 { 241 importStatement( module, container.get(i) ); 242 } 243 } 244 245 246 247 250 251 protected void importStatement( ModuleNode module, CSTNode reduction ) 252 { 253 256 String importPackage = makeName( reduction.get(1), null ); 257 258 259 260 263 if( reduction.get(2).isA(Types.STAR) ) 264 { 265 String [] classes = module.addImportPackage( dot(importPackage) ); 266 for( int i = 0; i < classes.length; i++ ) 267 { 268 imports.put( classes[i], dot(importPackage, classes[i]) ); 269 } 270 } 271 272 273 276 else 277 { 278 for( int i = 2; i < reduction.size(); i++ ) 279 { 280 CSTNode clause = reduction.get(i); 281 String name = identifier( clause ); 282 String as = (clause.hasChildren() ? identifier(clause.get(1)) : name); 283 284 293 module.addImport( as, name ); 295 name = dot( importPackage, name ); 296 297 imports.put( as, name ); 299 } 300 } 301 } 302 303 304 305 308 309 protected void topLevelStatement( ModuleNode module, CSTNode reduction ) throws ParserException 310 { 311 int type = reduction.getMeaning(); 312 switch( type ) 313 { 314 case Types.SYNTH_CLASS: 315 module.addClass( classDeclaration(null, reduction) ); 316 break; 317 318 case Types.SYNTH_INTERFACE: 319 module.addClass( interfaceDeclaration(null, reduction) ); 320 break; 321 322 case Types.SYNTH_METHOD: 323 module.addMethod( methodDeclaration(null, reduction) ); 324 break; 325 326 default: 327 module.addStatement( statement(reduction) ); 328 break; 329 } 330 331 } 332 333 334 335 338 339 protected ClassNode classDeclaration( ClassNode context, CSTNode reduction ) throws ParserException 340 { 341 344 String name = identifier( reduction ); 345 this.newClasses.add(name); 346 int modifiers = modifiers( reduction.get(1) ); 347 String parent = resolveName( reduction.get(2).get(1) ); 348 349 350 353 CSTNode interfaceReduction = reduction.get(3); 354 String [] interfaces = new String [interfaceReduction.children()]; 355 for( int i = 1; i < interfaceReduction.size(); i++ ) 356 { 357 interfaces[i-1] = resolveName( interfaceReduction.get(i) ); 358 } 359 360 361 364 ClassNode classNode = ( 365 context == null 366 ? new ClassNode( dot(packageName, name), modifiers, parent, interfaces, MixinNode.EMPTY_ARRAY ) 367 : new InnerClassNode( context, dot(packageName, name), modifiers, parent, interfaces, MixinNode.EMPTY_ARRAY ) 368 ); 369 370 classNode.setCSTNode( reduction.get(0) ); 371 typeBody( classNode, reduction.get(4), 0, 0 ); 372 return classNode; 373 } 374 375 376 377 380 381 protected void typeBody( ClassNode classNode, CSTNode body, int propertyModifiers, int methodModifiers ) throws ParserException 382 { 383 for( int i = 1; i < body.size(); i++ ) 384 { 385 CSTNode statement = body.get(i); 386 switch( statement.getMeaning() ) 387 { 388 case Types.SYNTH_PROPERTY: 389 addPropertyDeclaration( classNode, statement, propertyModifiers ); 390 break; 391 392 case Types.SYNTH_METHOD: 393 methodDeclaration( classNode, statement, methodModifiers ); 394 break; 395 396 case Types.SYNTH_CLASS: 397 classDeclaration( classNode, statement ); 398 break; 399 400 case Types.SYNTH_INTERFACE: 401 interfaceDeclaration( classNode, statement ); 402 break; 403 404 default: 405 throw new GroovyBugError( "unrecognized type body statement [" + statement.toString() + "]" ); 406 } 407 } 408 } 409 410 411 412 416 417 protected void addPropertyDeclaration( ClassNode classNode, CSTNode reduction, int extraModifiers ) throws ParserException 418 { 419 String name = identifier( reduction ); 420 int modifiers = modifiers( reduction.get(1) ) | extraModifiers; 421 String type = resolveName( reduction.get(2) ); 422 423 Expression value = reduction.size() > 3 ? expression(reduction.get(3)) : null; 424 425 PropertyNode propertyNode = classNode.addProperty( name, modifiers, type, value, null, null ); 426 propertyNode.setCSTNode( reduction.get(0) ); 427 428 } 429 430 431 432 435 436 protected void addPropertyDeclaration( ClassNode classNode, CSTNode reduction ) throws ParserException 437 { 438 addPropertyDeclaration( classNode, reduction, 0 ); 439 } 440 441 442 443 447 448 protected MethodNode methodDeclaration( ClassNode classNode, CSTNode reduction, int extraModifiers ) throws ParserException 449 { 450 String className = null; 451 if( classNode != null ) 452 { 453 className = classNode.getNameWithoutPackage(); 454 } 455 456 457 460 String name = identifier( reduction ); 461 int modifiers = modifiers( reduction.get(1) ) | extraModifiers; 462 String type = resolveName( reduction.get(2) ); 463 464 Parameter[] parameters = parameterDeclarations( reduction.get(3) ); 465 BlockStatement body = statementBody( reduction.get(5) ); 466 467 468 471 CSTNode clause = reduction.get(4); 472 String [] throwTypes = new String [clause.children()]; 473 for( int i = 1; i < clause.size(); i++ ) 474 { 475 throwTypes[i-1] = resolveName( clause.get(i) ); 476 } 477 478 if( clause.hasChildren() ) { throw new GroovyBugError( "NOT YET IMPLEMENTED: throws clause" ); } 479 480 481 484 if( name.length() == 0 ) 485 { 486 throw new GroovyBugError( "NOT YET IMPLEMENTED: static initializers" ); 487 488 497 } 498 499 500 503 else if( className != null && name.equals(className) ) 504 { 505 ConstructorNode node = new ConstructorNode( modifiers, parameters, body ); 506 node.setCSTNode( reduction.get(0) ); 507 508 classNode.addConstructor( node ); 509 return null; 510 } 511 512 513 516 else 517 { 518 MethodNode method = new MethodNode( name, modifiers, type, parameters, body ); 519 method.setCSTNode( reduction.get(0) ); 520 521 if( classNode != null ) 522 { 523 classNode.addMethod( method ); 524 } 525 526 return method; 527 } 528 529 } 530 531 532 533 536 537 protected MethodNode methodDeclaration( ClassNode classNode, CSTNode reduction ) throws ParserException 538 { 539 return methodDeclaration( classNode, reduction, 0 ); 540 } 541 542 543 544 547 548 protected Parameter[] parameterDeclarations( CSTNode reduction ) throws ParserException 549 { 550 Parameter[] parameters = new Parameter[ reduction.children() ]; 551 552 for( int i = 1; i < reduction.size(); i++ ) 553 { 554 CSTNode node = reduction.get(i); 555 556 String identifier = identifier( node ); 557 String type = resolveName( node.get(1) ); 558 559 if( node.size() > 2 ) 560 { 561 parameters[i-1] = new Parameter( type, identifier, expression(node.get(2)) ); 562 } 563 else 564 { 565 parameters[i-1] = new Parameter( type, identifier ); 566 } 567 } 568 569 return parameters; 570 571 } 572 573 574 575 578 579 protected ClassNode interfaceDeclaration( ClassNode context, CSTNode reduction ) throws ParserException 580 { 581 throw new GroovyBugError( "NOT YET IMPLEMENTED: interfaces" ); 582 583 624 } 625 626 627 628 629 632 633 636 637 protected BlockStatement statementBody( CSTNode reduction ) throws ParserException 638 { 639 if( reduction.isEmpty() ) 640 { 641 return new BlockStatement(); 642 } 643 else if( reduction.getMeaning() == Types.LEFT_CURLY_BRACE ) 644 { 645 return statementBlock( reduction ); 646 } 647 else 648 { 649 Statement statement = statement( reduction ); 650 statement.setCSTNode( reduction ); 651 652 BlockStatement block = null; 653 if( statement instanceof BlockStatement ) 654 { 655 block = (BlockStatement)statement; 656 } 657 else 658 { 659 block = new BlockStatement(); 660 block.addStatement( statement ); 661 } 662 663 return block; 664 } 665 } 666 667 668 669 673 674 protected BlockStatement statements( CSTNode reduction, int first ) throws ParserException 675 { 676 BlockStatement block = new BlockStatement(); 677 678 for( int i = first; i < reduction.size(); i++ ) 679 { 680 CSTNode statementReduction = reduction.get(i); 681 682 Statement statement = statement( statementReduction ); 683 statement.setCSTNode( statementReduction ); 684 685 block.addStatement( statement ); 686 } 687 688 return block; 689 } 690 691 692 693 696 697 protected BlockStatement statementBlock( CSTNode reduction ) throws ParserException 698 { 699 return statements( reduction, 1 ); 700 } 701 702 703 704 707 708 protected Statement statement( CSTNode reduction ) throws ParserException 709 { 710 Statement statement = null; 711 712 715 switch( reduction.getMeaning() ) 716 { 717 case Types.KEYWORD_ASSERT: 718 { 719 statement = assertStatement( reduction ); 720 break; 721 } 722 723 case Types.KEYWORD_BREAK: 724 { 725 statement = breakStatement( reduction ); 726 break; 727 } 728 729 case Types.KEYWORD_CONTINUE: 730 { 731 statement = continueStatement( reduction ); 732 break; 733 } 734 735 case Types.KEYWORD_IF: 736 { 737 statement = ifStatement( reduction ); 738 break; 739 } 740 741 case Types.KEYWORD_RETURN: 742 { 743 statement = returnStatement( reduction ); 744 break; 745 } 746 747 case Types.KEYWORD_SWITCH: 748 { 749 statement = switchStatement( reduction ); 750 break; 751 } 752 753 case Types.KEYWORD_SYNCHRONIZED: 754 { 755 statement = synchronizedStatement( reduction ); 756 break; 757 } 758 759 case Types.KEYWORD_THROW: 760 { 761 statement = throwStatement( reduction ); 762 break; 763 } 764 765 case Types.KEYWORD_TRY: 766 { 767 statement = tryStatement( reduction ); 768 break; 769 } 770 771 case Types.KEYWORD_FOR: 772 { 773 statement = forStatement( reduction ); 774 break; 775 } 776 777 case Types.KEYWORD_WHILE: 778 { 779 statement = whileStatement( reduction ); 780 break; 781 } 782 783 case Types.KEYWORD_DO: 784 { 785 statement = doWhileStatement( reduction ); 786 break; 787 } 788 789 case Types.SYNTH_BLOCK: 790 case Types.LEFT_CURLY_BRACE: 791 { 792 statement = statementBlock( reduction ); 793 break; 794 } 795 796 case Types.SYNTH_LABEL: 797 { 798 statement = statement( reduction.get(1) ); 799 statement.setStatementLabel( identifier(reduction) ); 800 break; 801 } 802 803 case Types.SYNTH_CLOSURE: 804 default: 805 { 806 statement = expressionStatement( reduction ); 807 break; 808 } 809 810 } 811 812 813 statement.setCSTNode( reduction ); 814 return statement; 815 } 816 817 818 819 822 823 protected AssertStatement assertStatement( CSTNode reduction ) throws ParserException 824 { 825 BooleanExpression expression = new BooleanExpression( expression(reduction.get(1)) ); 826 827 if( reduction.children() > 1 ) 828 { 829 return new AssertStatement( expression, expression(reduction.get(2)) ); 830 } 831 832 return new AssertStatement( expression, ConstantExpression.NULL ); 833 } 834 835 836 837 840 841 protected BreakStatement breakStatement( CSTNode reduction ) throws ParserException 842 { 843 if( reduction.hasChildren() ) 844 { 845 return new BreakStatement( reduction.get(1).getRootText() ); 846 } 847 848 return new BreakStatement(); 849 } 850 851 852 853 856 857 protected ContinueStatement continueStatement( CSTNode reduction ) throws ParserException 858 { 859 860 if( reduction.hasChildren() ) 861 { 862 return new ContinueStatement( reduction.get(1).getRootText() ); 863 } 864 865 return new ContinueStatement(); 866 } 867 868 869 870 873 874 protected IfStatement ifStatement( CSTNode reduction ) throws ParserException 875 { 876 Expression condition = expression( reduction.get(1) ); 877 BlockStatement body = statementBody( reduction.get(2) ); 878 Statement elseBlock = EmptyStatement.INSTANCE; 879 880 if( reduction.size() > 3 ) 881 { 882 CSTNode elseReduction = reduction.get(3); 883 if( elseReduction.getMeaning() == Types.KEYWORD_IF ) 884 { 885 elseBlock = ifStatement( elseReduction ); 886 } 887 else 888 { 889 elseBlock = statementBody( elseReduction.get(1) ); 890 } 891 892 } 893 894 return new IfStatement( new BooleanExpression(condition), body, elseBlock ); 895 } 896 897 898 899 902 903 protected ReturnStatement returnStatement( CSTNode reduction ) throws ParserException 904 { 905 if( reduction.hasChildren() ) 906 { 907 return new ReturnStatement( expression(reduction.get(1)) ); 908 } 909 910 return ReturnStatement.RETURN_NULL_OR_VOID; 911 } 912 913 914 915 918 919 protected SwitchStatement switchStatement( CSTNode reduction ) throws ParserException 920 { 921 SwitchStatement statement = new SwitchStatement( expression(reduction.get(1)) ); 922 923 for( int i = 2; i < reduction.size(); i++ ) 924 { 925 CSTNode child = reduction.get(i); 926 927 switch( child.getMeaning() ) 928 { 929 930 case Types.KEYWORD_CASE: 931 statement.addCase( caseStatement(child) ); 932 break; 933 934 case Types.KEYWORD_DEFAULT: 935 statement.setDefaultStatement( statementBlock(child) ); 936 break; 937 938 default: 939 throw new GroovyBugError( "invalid something in switch [" + child + "]" ); 940 } 941 } 942 943 return statement; 944 } 945 946 947 948 951 952 protected CaseStatement caseStatement( CSTNode reduction ) throws ParserException 953 { 954 return new CaseStatement( expression(reduction.get(1)), statements(reduction, 2) ); 955 } 956 957 958 959 962 963 protected SynchronizedStatement synchronizedStatement( CSTNode reduction ) throws ParserException 964 { 965 return new SynchronizedStatement( expression(reduction.get(1)), statementBody(reduction.get(2)) ); 966 } 967 968 969 970 973 974 protected ThrowStatement throwStatement( CSTNode reduction ) throws ParserException 975 { 976 return new ThrowStatement( expression(reduction.get(1)) ); 977 } 978 979 980 981 984 985 protected TryCatchStatement tryStatement( CSTNode reduction ) throws ParserException 986 { 987 BlockStatement body = statementBody( reduction.get(1) ); 988 BlockStatement finallyBlock = statementBody( reduction.get(3) ); 989 990 TryCatchStatement statement = new TryCatchStatement( body, finallyBlock ); 991 992 CSTNode catches = reduction.get(2); 993 for( int i = 1; i < catches.size(); i++ ) 994 { 995 CSTNode element = catches.get(i); 996 String type = resolveName( element.get(1) ); 997 String identifier = identifier( element.get(2) ); 998 999 statement.addCatch( new CatchStatement(type, identifier, statementBody(element.get(3))) ); 1000 } 1001 1002 return statement; 1003 } 1004 1005 1006 1007 1010 1011 protected ForStatement forStatement( CSTNode reduction ) throws ParserException 1012 { 1013 CSTNode header = reduction.get(1); 1014 Statement body = statementBody( reduction.get(2) ); 1015 1016 1017 1020 if( header.getMeaning() == Types.UNKNOWN ) 1021 { 1022 Expression[] init = expressions( header.get(1) ); 1023 Expression test = expression( header.get(2) ); 1024 Expression[] incr = expressions( header.get(3) ); 1025 1026 throw new GroovyBugError( "NOT YET IMPLEMENTED: standard for loop" ); 1027 } 1028 1029 1030 1033 else 1034 { 1035 1036 Type type = typeExpression( header.get(1) ); 1037 String identifier = identifier( header.get(2) ); 1038 Expression source = expression( header.get(3) ); 1039 1040 return new ForStatement( identifier, type, source, body ); 1041 } 1042 } 1043 1044 1045 1046 1049 1050 protected DoWhileStatement doWhileStatement( CSTNode reduction ) throws ParserException 1051 { 1052 Expression condition = expression( reduction.get(2) ); 1053 BlockStatement body = statementBody( reduction.get(1) ); 1054 1055 return new DoWhileStatement( new BooleanExpression(condition), body ); 1056 } 1057 1058 1059 1060 1063 1064 protected WhileStatement whileStatement( CSTNode reduction ) throws ParserException 1065 { 1066 Expression condition = expression( reduction.get(1) ); 1067 BlockStatement body = statementBody( reduction.get(2) ); 1068 1069 return new WhileStatement( new BooleanExpression(condition), body ); 1070 1071 } 1072 1073 1074 1075 1076 1079 1080 1083 1084 protected Statement expressionStatement( CSTNode node ) throws ParserException 1085 { 1086 return new ExpressionStatement( expression(node) ); 1087 } 1088 1089 1090 1091 1094 1095 protected Expression[] expressions( CSTNode reduction ) throws ParserException 1096 { 1097 Expression[] expressions = new Expression[ reduction.children() ]; 1098 1099 for( int i = 1; i < reduction.size(); i++ ) 1100 { 1101 expressions[i-1] = expression( reduction.get(i) ); 1102 } 1103 1104 return expressions; 1105 } 1106 1107 1108 1109 1112 1113 protected Expression expression( CSTNode reduction ) throws ParserException 1114 { 1115 Expression expression = null; 1116 1117 int type = reduction.getMeaningAs( EXPRESSION_HANDLERS ); 1118 switch( type ) 1119 { 1120 case Types.SYNTHETIC: 1121 { 1122 expression = syntheticExpression( reduction ); 1123 break; 1124 } 1125 1126 case Types.RANGE_OPERATOR: 1127 { 1128 Expression from = expression( reduction.get(1) ); 1129 Expression to = expression( reduction.get(2) ); 1130 1131 expression = new RangeExpression( from, to, reduction.getMeaning() == Types.DOT_DOT ); 1132 break; 1133 } 1134 1135 1136 case Types.LEFT_SQUARE_BRACKET: 1137 case Types.INFIX_OPERATOR: 1138 { 1139 expression = infixExpression( reduction ); 1140 break; 1141 } 1142 1143 1144 case Types.REGEX_PATTERN: 1145 { 1146 expression = new RegexExpression( expression(reduction.get(1)) ); 1147 break; 1148 } 1149 1150 1151 case Types.PREFIX_OPERATOR: 1152 { 1153 expression = prefixExpression( reduction ); 1154 break; 1155 } 1156 1157 1158 case Types.POSTFIX_OPERATOR: 1159 { 1160 Expression body = expression( reduction.get(1) ); 1161 expression = new PostfixExpression( body, reduction.getRoot() ); 1162 break; 1163 } 1164 1165 1166 case Types.SIMPLE_EXPRESSION: 1167 { 1168 expression = simpleExpression( reduction ); 1169 break; 1170 } 1171 1172 1173 case Types.KEYWORD_NEW: 1174 { 1175 expression = newExpression( reduction ); 1176 break; 1177 } 1178 1179 default: 1180 throw new GroovyBugError( "unhandled CST: [" + reduction.toString() + "]" ); 1181 1182 } 1183 1184 if( expression == null ) 1185 { 1186 throw new GroovyBugError( "expression produced null: [" + reduction.toString() + "]" ); 1187 } 1188 1189 expression.setCSTNode( reduction ); 1190 return expression; 1191 } 1192 1193 1194 public static final int[] EXPRESSION_HANDLERS = { 1195 Types.SYNTHETIC 1196 , Types.RANGE_OPERATOR 1197 , Types.LEFT_SQUARE_BRACKET 1198 , Types.INFIX_OPERATOR 1199 , Types.REGEX_PATTERN 1200 , Types.PREFIX_OPERATOR 1201 , Types.POSTFIX_OPERATOR 1202 , Types.SIMPLE_EXPRESSION 1203 , Types.KEYWORD_NEW 1204 }; 1205 1206 1207 1208 1209 1212 1213 public Expression infixExpression( CSTNode reduction ) throws ParserException 1214 { 1215 Expression expression; 1216 1217 int type = reduction.getMeaning(); 1218 switch( type ) 1219 { 1220 case Types.DOT: 1221 case Types.NAVIGATE: 1222 { 1223 String name = reduction.get(2).getRootText(); 1224 1225 Expression context = null; 1226 if( name.equals("class") ) 1227 { 1228 CSTNode node = reduction.get(1); 1229 if( node.isA(Types.LEFT_SQUARE_BRACKET) && node.children() == 1 ) 1230 { 1231 throw new GroovyBugError( "NOT YET IMPLEMENTED: .class for array types" ); 1232 } 1234 } 1235 1236 if( context == null ) 1237 { 1238 context = expression( reduction.get(1) ); 1239 } 1240 1241 expression = new PropertyExpression( context, name, type == Types.NAVIGATE ); 1242 break; 1243 } 1244 1245 1246 case Types.KEYWORD_INSTANCEOF: 1247 { 1248 Expression lhs = expression( reduction.get(1) ); 1249 Expression rhs = classExpression( reduction.get(2) ); 1250 expression = new BinaryExpression( lhs, reduction.getRoot(), rhs ); 1251 break; 1252 } 1253 1254 1255 default: 1256 { 1257 Expression lhs = expression( reduction.get(1) ); 1258 Expression rhs = expression( reduction.get(2) ); 1259 expression = new BinaryExpression( lhs, reduction.getRoot(), rhs ); 1260 break; 1261 } 1262 } 1263 1264 return expression; 1265 } 1266 1267 1268 1269 1272 1273 public Expression prefixExpression( CSTNode reduction ) throws ParserException 1274 { 1275 Expression expression = null; 1276 CSTNode body = reduction.get(1); 1277 1278 int type = reduction.getMeaning(); 1279 switch( type ) 1280 { 1281 case Types.PREFIX_MINUS: 1282 if( body.size() == 1 && body.isA(Types.NUMBER) ) 1283 { 1284 expression = numericExpression( body, true ); 1285 } 1286 else 1287 { 1288 expression = new NegationExpression( expression(body) ); 1289 } 1290 break; 1291 1292 case Types.PREFIX_PLUS: 1293 expression = expression(body); 1294 break; 1295 1296 case Types.NOT: 1297 expression = new NotExpression( expression(body) ); 1298 break; 1299 1300 default: 1301 expression = new PrefixExpression( reduction.getRoot(), expression(body) ); 1302 break; 1303 } 1304 1305 return expression; 1306 } 1307 1308 1309 1310 1313 1314 public Expression simpleExpression( CSTNode reduction ) throws ParserException 1315 { 1316 Expression expression = null; 1317 1318 int type = reduction.getMeaning(); 1319 switch( type ) 1320 { 1321 case Types.KEYWORD_NULL: 1322 expression = ConstantExpression.NULL; 1323 break; 1324 1325 case Types.KEYWORD_TRUE: 1326 expression = ConstantExpression.TRUE; 1327 break; 1328 1329 case Types.KEYWORD_FALSE: 1330 expression = ConstantExpression.FALSE; 1331 break; 1332 1333 case Types.STRING: 1334 expression = new ConstantExpression( reduction.getRootText() ); 1335 break; 1336 1337 case Types.INTEGER_NUMBER: 1338 case Types.DECIMAL_NUMBER: 1339 expression = numericExpression( reduction, false ); 1340 break; 1341 1342 case Types.KEYWORD_SUPER: 1343 case Types.KEYWORD_THIS: 1344 expression = variableExpression( reduction ); 1345 break; 1346 1347 case Types.IDENTIFIER: 1348 expression = variableOrClassExpression( reduction ); 1349 break; 1350 1351 } 1352 1353 return expression; 1354 } 1355 1356 1357 1358 1361 1362 public Expression numericExpression( CSTNode reduction, boolean negate ) throws ParserException 1363 { 1364 Token token = reduction.getRoot(); 1365 String text = reduction.getRootText(); 1366 String signed = negate ? "-" + text : text; 1367 1368 boolean isInteger = (token.getMeaning() == Types.INTEGER_NUMBER); 1369 1370 try 1371 { 1372 Number number = isInteger ? Numbers.parseInteger(signed) : Numbers.parseDecimal(signed); 1373 1374 return new ConstantExpression( number ); 1375 } 1376 catch( NumberFormatException e ) 1377 { 1378 error( "numeric literal [" + signed + "] invalid or out of range for its type", token ); 1379 } 1380 1381 throw new GroovyBugError( "this should never happen" ); 1382 } 1383 1384 1385 1386 1389 1390 public Expression syntheticExpression( CSTNode reduction ) throws ParserException 1391 { 1392 Expression expression = null; 1393 1394 int type = reduction.getMeaning(); 1395 switch( type ) 1396 { 1397 case Types.SYNTH_TERNARY: 1398 { 1399 BooleanExpression condition = new BooleanExpression( expression(reduction.get(1)) ); 1400 Expression trueBranch = expression( reduction.get(2) ); 1401 Expression falseBranch = expression( reduction.get(3) ); 1402 1403 expression = new TernaryExpression( condition, trueBranch, falseBranch ); 1404 break; 1405 } 1406 1407 1408 case Types.SYNTH_CAST: 1409 { 1410 String className = resolveName( reduction.get(1) ); 1411 Expression body = expression( reduction.get(2) ); 1412 1413 expression = new CastExpression( className, body ); 1414 break; 1415 } 1416 1417 1418 case Types.SYNTH_VARIABLE_DECLARATION: 1419 { 1420 expression = variableDeclarationExpression( reduction ); 1421 break; 1422 } 1423 1424 1425 case Types.SYNTH_METHOD_CALL: 1426 { 1427 expression = methodCallExpression( reduction ); 1428 break; 1429 } 1430 1431 1432 case Types.SYNTH_CLOSURE: 1433 { 1434 expression = closureExpression( reduction ); 1435 break; 1436 } 1437 1438 1439 case Types.SYNTH_GSTRING: 1440 { 1441 expression = gstringExpression( reduction ); 1442 break; 1443 } 1444 1445 1446 case Types.SYNTH_LIST: 1447 { 1448 expression = listExpression( reduction ); 1449 break; 1450 } 1451 1452 1453 case Types.SYNTH_MAP: 1454 { 1455 expression = mapExpression( reduction ); 1456 break; 1457 } 1458 } 1459 1460 return expression; 1461 } 1462 1463 1464 1465 1466 1470 1471 protected Expression variableOrClassExpression( CSTNode reduction ) throws ParserException 1472 { 1473 String className = resolveName( reduction, false ); 1474 1475 if( className == null ) 1476 { 1477 return variableExpression( reduction ); 1478 } 1479 else 1480 { 1481 return new ClassExpression( className ); 1482 } 1483 } 1484 1485 1486 1487 1490 1491 protected ClassExpression classExpression( CSTNode reduction ) throws ParserException 1492 { 1493 String name = resolveName( reduction, true ); 1494 return new ClassExpression( name ); 1495 } 1496 1497 1498 1499 1503 1504 protected VariableExpression variableExpression( CSTNode reduction ) 1505 { 1506 return new VariableExpression( reduction.getRootText(), null ); 1507 } 1508 1509 protected VariableExpression variableExpression( CSTNode reduction, String type ) 1510 { 1511 return new VariableExpression( reduction.getRootText(), type ); 1512 } 1513 1514 1515 1516 1519 1520 protected Type typeExpression( CSTNode reduction ) 1521 { 1522 String name = makeName( reduction, null ); 1523 if( name == null ) 1524 { 1525 return Type.DYNAMIC_TYPE; 1526 } 1527 else 1528 { 1529 return new Type( resolveName(name, true) ); 1530 } 1531 } 1532 1533 1534 1535 1539 1540 protected Expression variableDeclarationExpression( CSTNode reduction ) throws ParserException 1541 { 1542 String type = resolveName( reduction.get(1) ); 1543 1544 1545 1548 if( reduction.size() == 3 ) 1549 { 1550 CSTNode node = reduction.get(2); 1551 1552 VariableExpression name = variableExpression( node, type ); 1553 1555 Token symbol = Token.newSymbol( Types.EQUAL, -1, -1 ); 1556 1557 return new BinaryExpression( name, symbol, expression(node.get(1)) ); 1558 } 1559 1560 1561 throw new GroovyBugError( "NOT YET IMPLEMENTED: generalized variable declarations" ); 1562 1563 1576 } 1577 1578 1579 1580 1583 1584 protected MethodCallExpression methodCallExpression( CSTNode reduction ) throws ParserException 1585 { 1586 MethodCallExpression call = null; 1587 1588 1591 CSTNode descriptor = reduction.get(1); 1592 Expression context = null; 1593 boolean implicit = false; 1594 String method = "call"; 1595 boolean safe = false; 1596 1597 int type = descriptor.getMeaning(); 1598 switch( type ) 1599 { 1600 case Types.KEYWORD_SUPER: 1601 { 1602 context = variableExpression( descriptor ); 1603 method = identifier( descriptor ); 1604 break; 1605 } 1606 1607 case Types.KEYWORD_THIS: 1608 { 1609 context = VariableExpression.THIS_EXPRESSION; 1610 method = identifier( descriptor ); 1611 break; 1612 } 1613 1614 case Types.IDENTIFIER: 1615 { 1616 context = VariableExpression.THIS_EXPRESSION; 1617 method = identifier( descriptor ); 1618 implicit = true; 1619 break; 1620 } 1621 1622 case Types.DOT: 1623 case Types.NAVIGATE: 1624 { 1625 context = expression( descriptor.get(1) ); 1626 method = identifier( descriptor.get(2) ); 1627 safe = type == Types.NAVIGATE; 1628 break; 1629 } 1630 1631 default: 1632 { 1633 context = expression( descriptor ); 1634 break; 1635 } 1636 } 1637 1638 1639 1642 Expression parameters = parameterList( reduction.get(2) ); 1643 1644 1646 call = new MethodCallExpression( context, method, parameters ); 1647 call.setImplicitThis( implicit ); 1648 call.setSafe( safe ); 1649 1650 return call; 1651 } 1652 1653 1654 1655 1658 1659 protected ClosureExpression closureExpression( CSTNode reduction ) throws ParserException 1660 { 1661 ClosureExpression expression = null; 1662 1663 Parameter[] parameters = parameterDeclarations( reduction.get(1) ); 1664 expression = new ClosureExpression( parameters, statementBlock(reduction.get(2)) ); 1665 1666 return expression; 1667 } 1668 1669 1670 1671 1674 1675 protected Expression parameterList( CSTNode reduction ) throws ParserException 1676 { 1677 TupleExpression list = new TupleExpression(); 1678 1679 for( int i = 1; i < reduction.size(); i++ ) 1680 { 1681 CSTNode node = reduction.get(i); 1682 list.addExpression( expression(node) ); 1683 } 1684 1685 return list; 1686 } 1687 1688 1689 1690 1693 1694 protected Expression newExpression( CSTNode reduction ) throws ParserException 1695 { 1696 Expression expression = null; 1697 CSTNode typeNode = reduction.get(1); 1698 String type = resolveName( typeNode ); 1699 1700 1701 1704 if( typeNode.getMeaning() == Types.LEFT_SQUARE_BRACKET ) 1705 { 1706 CSTNode dimensions = reduction.get(2); 1707 1708 1715 if( typeNode.get(1).getMeaning() == Types.LEFT_SQUARE_BRACKET ) 1716 { 1717 throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" ); 1718 } 1719 else 1720 { 1721 type = resolveName( typeNode.get(1) ); 1722 } 1723 1724 1725 1728 if( dimensions.isEmpty() ) 1729 { 1730 CSTNode data = reduction.get(3); 1731 1732 if( data.get(1, true).getMeaning() == Types.SYNTH_TUPLE ) 1733 { 1734 throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" ); 1735 } 1736 1737 expression = new ArrayExpression( type, tupleExpression(data).getExpressions() ); 1738 } 1739 1740 1741 1744 else 1745 { 1746 if( dimensions.size() > 2 ) 1747 { 1748 throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" ); 1749 1750 1755 } 1756 else 1757 { 1758 expression = new ArrayExpression( type, expression(dimensions.get(1)) ); 1759 } 1760 } 1761 } 1762 1763 1764 1767 else 1768 { 1769 Expression parameters = parameterList( reduction.get(2) ); 1770 1771 if( reduction.size() > 3 ) 1772 { 1773 throw new GroovyBugError( "NOT YET IMPLEMENTED: anonymous classes" ); 1774 } 1775 1776 expression = new ConstructorCallExpression( type, parameters ); 1777 } 1778 1779 return expression; 1780 } 1781 1782 1783 1784 1787 1788 protected TupleExpression tupleExpression( CSTNode reduction ) throws ParserException 1789 { 1790 TupleExpression tuple = new TupleExpression(); 1791 1792 for( int i = 1; i < reduction.size(); i++ ) 1793 { 1794 CSTNode element = reduction.get(i); 1795 1796 if( element.getMeaning() == Types.SYNTH_TUPLE ) 1797 { 1798 tuple.addExpression( tupleExpression(element) ); 1799 } 1800 else 1801 { 1802 tuple.addExpression( expression(element) ); 1803 } 1804 } 1805 1806 return tuple; 1807 } 1808 1809 1810 1811 1814 1815 protected Expression gstringExpression( CSTNode reduction ) throws ParserException 1816 { 1817 if( !reduction.hasChildren() ) 1818 { 1819 return new ConstantExpression( "" ); 1820 } 1821 1822 if( reduction.children() == 1 && reduction.get(1).getMeaning() == Types.STRING ) 1823 { 1824 return expression( reduction.get(1) ); 1825 } 1826 1827 1828 GStringExpression expression = new GStringExpression( reduction.getRootText() ); 1829 boolean lastWasExpression = false; 1830 1831 for( int i = 1; i < reduction.size(); i++ ) 1832 { 1833 CSTNode element = reduction.get(i); 1834 if( element.getMeaning() == Types.STRING ) 1835 { 1836 ConstantExpression string = new ConstantExpression( element.getRootText() ); 1837 string.setCSTNode( element ); 1838 1839 expression.addString( string ); 1840 1841 lastWasExpression = false; 1842 } 1843 else 1844 { 1845 if( lastWasExpression ) 1846 { 1847 expression.addString( new ConstantExpression("") ); 1848 } 1849 1850 lastWasExpression = true; 1851 expression.addValue( element.isEmpty() ? ConstantExpression.NULL : expression(element) ); 1852 } 1853 } 1854 1855 return expression; 1856 } 1857 1858 1859 1860 1863 1864 protected ListExpression listExpression( CSTNode reduction ) throws ParserException 1865 { 1866 ListExpression list = new ListExpression(); 1867 1868 for( int i = 1; i < reduction.size(); i++ ) 1869 { 1870 list.addExpression( expression(reduction.get(i)) ); 1871 } 1872 1873 return list; 1874 } 1875 1876 1877 1878 1881 1882 protected MapExpression mapExpression( CSTNode reduction ) throws ParserException 1883 { 1884 MapExpression map = new MapExpression(); 1885 1886 for( int i = 1; i < reduction.size(); i++ ) 1887 { 1888 CSTNode element = reduction.get(i); 1889 Expression key = expression( element.get(1) ); 1890 Expression value = expression( element.get(2) ); 1891 1892 map.addMapEntryExpression( key, value ); 1893 } 1894 1895 return map; 1896 } 1897 1898 1899 1900 1901 1902 1905 private static HashMap resolutions = new HashMap (); private static String NOT_RESOLVED = new String (); 1907 1908 1909 1913 1914 protected String makeName( CSTNode root, String defaultName ) 1915 { 1916 if( root == null ) 1917 { 1918 return defaultName; 1919 } 1920 1921 String name = ""; 1922 switch( root.getMeaning() ) 1923 { 1924 case Types.LEFT_SQUARE_BRACKET: 1925 { 1926 name = makeName( root.get(1) ) + "[]"; 1927 break; 1928 } 1929 1930 case Types.DOT: 1931 { 1932 CSTNode node = root; 1933 while( node.isA(Types.DOT) ) 1934 { 1935 name = "." + node.get(2).getRootText() + name; 1936 node = node.get(1); 1937 } 1938 1939 name = node.getRootText() + name; 1940 break; 1941 } 1942 1943 case Types.UNKNOWN: 1944 { 1945 name = defaultName; 1946 break; 1947 } 1948 1949 default: 1950 { 1951 name = root.getRootText(); 1952 break; 1953 } 1954 1955 } 1956 1957 return name; 1958 } 1959 1960 1961 1962 1965 1966 protected String makeName( CSTNode root ) 1967 { 1968 return makeName( root, "" ); } 1970 1971 1972 1973 1976 1977 protected String identifier( CSTNode identifier ) 1978 { 1979 return identifier.getRootText(); 1980 } 1981 1982 1983 1984 1988 1989 protected String resolveName( String name, boolean safe ) 1990 { 1991 1994 String resolution = (String )resolutions.get( name ); 1995 if( resolution == NOT_RESOLVED ) 1996 { 1997 return (safe ? name : null); 1998 } 1999 else if( resolution != null ) 2000 { 2001 return (String )resolution; 2002 } 2003 2004 2005 do 2006 { 2007 2011 if( name.indexOf(".") >= 0 ) 2012 { 2013 resolution = name; 2014 break; } 2016 2017 2018 2022 String scalar = name, postfix = ""; 2023 while( scalar.endsWith("[]") ) 2024 { 2025 scalar = scalar.substring( 0, scalar.length() - 2 ); 2026 postfix += "[]"; 2027 } 2028 2029 2030 2033 if( Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE) ) 2034 { 2035 resolution = name; 2036 break; } 2038 2039 2040 2044 if( this.imports.containsKey(scalar) ) 2045 { 2046 resolution = ((String )this.imports.get(scalar)) + postfix; 2047 break; } 2049 2050 2051 2054 if( packageName != null && packageName.length() > 0 ) 2055 { 2056 try 2057 { 2058 getClassLoader().loadClass( dot(packageName, scalar) ); 2059 resolution = dot(packageName, name); 2060 2061 break; } 2063 catch( Throwable e ) 2064 { 2065 2066 } 2067 } 2068 2069 List packageImports = output.getImportPackages(); 2071 for (int i = 0; i < packageImports.size(); i++) { 2072 String pack = (String ) packageImports.get(i); 2073 String clsName = pack + name; 2074 try { 2075 getClassLoader().loadClass( clsName ); 2076 resolution = clsName; 2077 break; 2078 } catch (Throwable e) { 2079 } 2081 } 2082 if (resolution != null) 2083 break; 2084 2085 2088 for( int i = 0; i < DEFAULT_IMPORTS.length; i++ ) 2089 { 2090 try 2091 { 2092 String qualified = DEFAULT_IMPORTS[i] + scalar; 2093 getClassLoader().loadClass( qualified ); 2094 2095 resolution = qualified + postfix; 2096 break; } 2098 catch( Throwable e ) 2099 { 2100 2101 } 2102 } 2103 2104 } while( false ); 2105 2106 2107 2110 if( resolution == null ) 2111 { 2112 resolutions.put( name, NOT_RESOLVED ); 2113 return (safe ? name : null); 2114 } 2115 else 2116 { 2117 resolutions.put( name, resolution ); 2118 return resolution; 2119 } 2120 } 2121 2122 2123 2124 2132 2133 protected String resolveName( CSTNode root, boolean safe ) 2134 { 2135 String name = makeName( root ); 2136 if (name.length() == 0) 2137 return ""; 2138 if (this.newClasses.contains(name)) { 2139 return dot(packageName, name); 2140 } else { 2141 return resolveName( name, safe ); 2142 } 2143 } 2144 2145 2146 2147 2150 2151 protected String resolveName( CSTNode root ) 2152 { 2153 return resolveName( root, true ); 2154 } 2155 2156 2157 2158 2161 2162 protected boolean isDatatype( String name ) 2163 { 2164 return resolveName( name, false ) != null; 2165 } 2166 2167 2168 2169 2173 2174 protected String dot( String base, String name ) 2175 { 2176 if( base != null && base.length() > 0 ) 2177 { 2178 return base + "." + name; 2179 } 2180 2181 return name; 2182 } 2183 2184 2185 2186 2189 2190 protected String dot( String base ) 2191 { 2192 return dot( base, "" ); 2193 } 2194 2195 2196 2197 2198 2201 2202 2205 2206 protected int modifiers( CSTNode list ) 2207 { 2208 int modifiers = 0; 2209 2210 for( int i = 1; i < list.size(); ++i ) 2211 { 2212 SWITCH: switch( list.get(i).getMeaning() ) 2213 { 2214 case Types.KEYWORD_PUBLIC: 2215 { 2216 modifiers |= Constants.ACC_PUBLIC; 2217 break SWITCH; 2218 } 2219 2220 case Types.KEYWORD_PROTECTED: 2221 { 2222 modifiers |= Constants.ACC_PROTECTED; 2223 break SWITCH; 2224 } 2225 2226 case Types.KEYWORD_PRIVATE: 2227 { 2228 modifiers |= Constants.ACC_PRIVATE; 2229 break SWITCH; 2230 } 2231 2232 2233 case Types.KEYWORD_ABSTRACT: 2234 { 2235 modifiers |= Constants.ACC_ABSTRACT; 2236 break SWITCH; 2237 } 2238 2239 case Types.KEYWORD_FINAL: 2240 { 2241 modifiers |= Constants.ACC_FINAL; 2242 break SWITCH; 2243 } 2244 2245 case Types.KEYWORD_NATIVE: 2246 { 2247 modifiers |= Constants.ACC_NATIVE; 2248 break SWITCH; 2249 } 2250 2251 case Types.KEYWORD_TRANSIENT: 2252 { 2253 modifiers |= Constants.ACC_TRANSIENT; 2254 break SWITCH; 2255 } 2256 2257 case Types.KEYWORD_VOLATILE: 2258 { 2259 modifiers |= Constants.ACC_VOLATILE; 2260 break SWITCH; 2261 } 2262 2263 2264 case Types.KEYWORD_SYNCHRONIZED: 2265 { 2266 modifiers |= Constants.ACC_SYNCHRONIZED; 2267 break SWITCH; 2268 } 2269 case Types.KEYWORD_STATIC: 2270 { 2271 modifiers |= Constants.ACC_STATIC; 2272 break SWITCH; 2273 } 2274 2275 } 2276 } 2277 2278 2279 2282 if( (modifiers & (Constants.ACC_PROTECTED | Constants.ACC_PRIVATE)) == 0 ) 2283 { 2284 modifiers |= Constants.ACC_PUBLIC; 2285 } 2286 2287 return modifiers; 2288 } 2289 2290 2291 2292 2293 2296 2297 2300 2301 protected void error( String description, CSTNode node ) throws ParserException 2302 { 2303 throw new ParserException( description, node.getRoot() ); 2304 } 2305 2306 2307} 2308 | Popular Tags |