001 /* 002 * Copyright (C) 2006-2007 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.codehaus.gmaven.runtime.support.stubgen.model; 018 019 import org.codehaus.gmaven.runtime.support.stubgen.UnexpectedNodeException; 020 import org.codehaus.gmaven.runtime.support.stubgen.parser.Node; 021 import org.codehaus.gmaven.runtime.support.stubgen.parser.Parser; 022 import org.codehaus.gmaven.runtime.support.stubgen.parser.ParserFactory; 023 import org.codehaus.gmaven.runtime.support.stubgen.parser.SourceType; 024 025 import java.io.BufferedReader; 026 import java.io.InputStreamReader; 027 import java.io.Reader; 028 import java.net.URL; 029 import java.util.Iterator; 030 import java.util.LinkedHashSet; 031 import java.util.Set; 032 033 /** 034 * Provides support for {@link ModelFactory} implementations. 035 * 036 * @version $Id: ModelFactorySupport.java 18 2009-07-16 09:39:40Z user57 $ 037 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a> 038 */ 039 public abstract class ModelFactorySupport 040 implements ModelFactory 041 { 042 protected final ParserFactory factory; 043 044 protected Parser parser; 045 046 protected Node lastNode; 047 048 protected SourceDef source; 049 050 protected ClassDef clazz; 051 052 protected ModelFactorySupport(final ParserFactory factory) { 053 assert factory != null; 054 055 this.factory = factory; 056 } 057 058 public SourceDef create(final URL input) throws Exception { 059 assert input != null; 060 061 return create(input, SourceType.forURL(input)); 062 } 063 064 public SourceDef create(final URL input, final SourceType type) throws Exception { 065 assert input != null; 066 assert type != null; 067 068 // Setup the root model element 069 source = createRoot(input, type); 070 071 // Reset internal state 072 lastNode = null; 073 clazz = null; 074 075 // Create a new parser for the source type 076 parser = factory.create(source.getType()); 077 078 // Parse the source 079 Reader reader = new BufferedReader(new InputStreamReader(input.openStream())); 080 Node node; 081 082 try { 083 node = parser.parse(reader, input.toExternalForm()); 084 } 085 finally { 086 reader.close(); 087 } 088 089 // Process the tree 090 process(node); 091 092 return source; 093 } 094 095 protected SourceDef createRoot(final URL input, final SourceType type) { 096 assert input != null; 097 assert type != null; 098 099 SourceDef def = new SourceDef(); 100 def.setUrl(input); 101 def.setType(type); 102 103 addDefaultImports(def); 104 105 return def; 106 } 107 108 protected abstract void addDefaultImports(final SourceDef model); 109 110 // 111 // Processing 112 // 113 114 protected void process(Node node) { 115 assert node != null; 116 117 while (node != null) { 118 if (node.is("PACKAGE_DEF")) { 119 packageDef(node); 120 } 121 else if (node.is(new String[] { "STATIC_IMPORT", "IMPORT" })) { 122 importDef(node); 123 } 124 else if (node.is("CLASS_DEF")) { 125 classDef(node); 126 } 127 else if (node.is("INTERFACE_DEF")) { 128 interfaceDef(node); 129 } 130 else if (node.is("METHOD_DEF")) { 131 methodDef(node); 132 } 133 else if (node.is("ENUM_DEF")) { 134 enumDef(node); 135 } 136 else if (node.is("ANNOTATION_DEF")) { 137 annotationDef(node); 138 } 139 else { 140 // everything else should be some sort of statement 141 source.addStatement(node); 142 } 143 144 node = node.nextSibling(); 145 } 146 } 147 148 protected void packageDef(final Node parent) { 149 assert parent != null; 150 151 PackageDef def = new PackageDef(); 152 153 Node node = parent.firstChild(); 154 155 node = node.skip("ANNOTATIONS"); 156 157 String name = qualifiedName(node); 158 159 def.setName(name); 160 161 source.setPackage(def); 162 } 163 164 protected void importDef(final Node parent) { 165 assert parent != null; 166 167 ImportDef def = new ImportDef(); 168 169 if (parent.is("STATIC_IMPORT")) { 170 // import is like "import static foo" 171 def.setStatic(true); 172 } 173 174 Node node = parent.firstChild(); 175 176 if (node.is("LITERAL_as")) { 177 // import is like "import foo as bar" 178 node = node.firstChild(); 179 Node aliasNode = node.nextSibling(); 180 def.setAlias(identifier(aliasNode)); 181 } 182 183 if (node.isLeaf()) { 184 // import is like "import Foo" 185 def.setType(identifier(node)); 186 } 187 else { 188 Node packageNode = node.firstChild(); 189 String packageName = qualifiedName(packageNode); 190 def.setPackage(packageName); 191 192 Node nameNode = packageNode.nextSibling(); 193 if (nameNode.is("STAR")) { 194 // import is like "import foo.*" 195 def.setWildcard(true); 196 } 197 else { 198 String name = identifier(nameNode); 199 // import is like "import foo.Bar" 200 def.setType(name); 201 } 202 } 203 204 source.addImport(def); 205 } 206 207 protected void interfaceDef(final Node parent) { 208 assert parent != null; 209 210 InterfaceDef def = new InterfaceDef(); 211 212 clazz = def; 213 214 Node node = parent.firstChild(); 215 216 node = modifiers(def, node); 217 218 node = name(def, node); 219 220 if (node.is("EXTENDS_CLAUSE")) { 221 def.getImplements().addAll(interfaces(node)); 222 node = node.nextSibling(); 223 } 224 225 javadocs(def, parent); 226 227 objectBlock(node); 228 229 source.addClass(def); 230 } 231 232 protected void classDef(final Node parent) { 233 assert parent != null; 234 235 ClassDef def = new ClassDef(); 236 def.addImplements("groovy.lang.GroovyObject"); 237 238 clazz = def; 239 240 Node node = parent.firstChild(); 241 242 node = modifiers(def, node); 243 244 node = name(def, node); 245 246 if (node.is("TYPE_PARAMETERS")) { 247 // 248 // FIXME: Support generics 249 // 250 node = node.nextSibling(); 251 } 252 253 if (node.is("EXTENDS_CLAUSE")) { 254 def.setSuperClass(type(node)); 255 node = node.nextSibling(); 256 } 257 258 if (node.is("IMPLEMENTS_CLAUSE")) { 259 def.getImplements().addAll(interfaces(node)); 260 node = node.nextSibling(); 261 } 262 263 javadocs(def, parent); 264 265 objectBlock(node); 266 267 source.addClass(def); 268 } 269 270 protected void enumDef(final Node parent) { 271 assert parent != null; 272 273 parent.ensure("ENUM_DEF"); 274 275 EnumDef def = new EnumDef(); 276 277 clazz = def; 278 279 Node node = parent.firstChild(); 280 281 node = modifiers(def, node); 282 283 node = name(def, node); 284 285 if (node.is("TYPE_PARAMETERS")) { 286 // 287 // FIXME: Support generics 288 // 289 node = node.nextSibling(); 290 } 291 292 if (node.is("EXTENDS_CLAUSE")) { 293 def.setSuperClass(type(node)); 294 node = node.nextSibling(); 295 } 296 297 if (node.is("IMPLEMENTS_CLAUSE")) { 298 def.getImplements().addAll(interfaces(node)); 299 node = node.nextSibling(); 300 } 301 302 javadocs(def, parent); 303 304 objectBlock(node); 305 306 source.addClass(def); 307 } 308 309 protected void annotationDef(final Node parent) { 310 assert parent != null; 311 312 parent.ensure("ANNOTATION_DEF"); 313 314 AnnotationDef def = new AnnotationDef(); 315 316 clazz = def; 317 318 Node node = parent.firstChild(); 319 320 node = modifiers(def, node); 321 322 node = name(def, node); 323 324 if (node.is("TYPE_PARAMETERS")) { 325 // 326 // FIXME: Support generics 327 // 328 node = node.nextSibling(); 329 } 330 331 if (node.is("EXTENDS_CLAUSE")) { 332 def.getImplements().addAll(interfaces(node)); 333 node = node.nextSibling(); 334 } 335 336 javadocs(def, parent); 337 338 objectBlock(node); 339 340 source.addClass(def); 341 } 342 343 protected void objectBlock(final Node parent) { 344 assert parent != null; 345 346 parent.ensure("OBJBLOCK"); 347 348 for (Node node = parent.firstChild(); node != null; node = node.nextSibling()) { 349 if (node.is("OBJBLOCK")) { 350 objectBlock(node); 351 } 352 else if (node.is("METHOD_DEF")) { 353 methodDef(node); 354 } 355 else if (node.is("ANNOTATION_FIELD_DEF")) { 356 annotationFieldDef(node); 357 } 358 else if (node.is("CTOR_IDENT")) { 359 constructorDef(node); 360 } 361 else if (node.is("VARIABLE_DEF")) { 362 fieldDef(node); 363 } 364 else if (node.is("ENUM_DEF")) { 365 enumDef(node); 366 } 367 else if (node.is("ENUM_CONSTANT_DEF")) { 368 enumConstantDef(node); 369 } 370 else if (node.is(new String[] { "STATIC_INIT", "INSTANCE_INIT" })) { 371 // Ignore 372 } 373 else { 374 throw new UnexpectedNodeException(node); 375 } 376 } 377 } 378 379 protected void constructorDef(final Node parent) { 380 assert parent != null; 381 382 ConstructorDef def = new ConstructorDef(); 383 384 Node node = parent.firstChild(); 385 386 node = modifiers(def, node); 387 388 node = parameters(def, node); 389 390 node = throwz(def, node); 391 392 superParameters(def, node); 393 394 javadocs(def, parent); 395 396 clazz.addConstructor(def); 397 } 398 399 protected void superParameters(final ConstructorDef target, final Node parent) { 400 assert target != null; 401 assert parent != null; 402 403 Node node = parent; 404 405 if (node.is("SLIST")) { 406 node = node.firstChild(); 407 408 if (node != null) { 409 if (node.is(new String[] { "SUPER_CTOR_CALL", "CTOR_CALL" })) { 410 if (node.is("SUPER_CTOR_CALL")) { 411 target.setSuperType(ConstructorDef.SUPER); 412 } 413 else { 414 target.setSuperType(ConstructorDef.THIS); 415 } 416 417 node = node.firstChild(); 418 node.ensure("ELIST"); 419 420 if (!node.isLeaf()) { 421 node = node.firstChild(); 422 423 // Pull off EXPR siblings 424 do { 425 superParameter(target, node); 426 node = node.nextSibling(); 427 } 428 while (node != null); 429 } 430 // else we have a super() with-out/params 431 } 432 } 433 } 434 } 435 436 protected void superParameter(final ConstructorDef target, final Node parent) { 437 assert parent != null; 438 439 parent.ensure("EXPR"); 440 441 Node node = parent.firstChild(); 442 443 SuperParameterDef def = new SuperParameterDef(); 444 445 if (node.is("TYPECAST")) { 446 node = node.firstChild(); 447 assert node != null; 448 449 node.ensure("TYPE"); 450 def.setType(type(node)); 451 } 452 else if (node.is("LITERAL_as")) { 453 node = node.firstChild(); 454 assert node != null; 455 456 node = node.nextSibling(); 457 assert node != null; 458 459 node.ensure("TYPE"); 460 def.setType(type(node)); 461 } 462 else if (node.is("LITERAL_new")) { 463 node = node.firstChild(); 464 assert node != null; 465 466 def.setType(type(node)); 467 } 468 else if (node.is(new String[] { "LITERAL_true", "LITERAL_false" })) { 469 def.setType(TypeDef.BOOLEAN); 470 } 471 else if (node.is("STRING_LITERAL")) { 472 def.setType(TypeDef.STRING); 473 } 474 else if (node.is("NUM_INT")) { 475 def.setType(TypeDef.INT); 476 } 477 else if (node.is("NUM_LONG")) { 478 def.setType(TypeDef.LONG); 479 } 480 else if (node.is("NUM_FLOAT")) { 481 def.setType(TypeDef.FLOAT); 482 } 483 else if (node.is("NUM_DOUBLE")) { 484 def.setType(TypeDef.DOUBLE); 485 } 486 else if (node.is("NUM_BIG_INT")) { 487 def.setType(TypeDef.BIG_INT); 488 } 489 else if (node.is("NUM_BIG_DECIMAL")) { 490 def.setType(TypeDef.BIG_DECIMAL); 491 } 492 else if (node.is("STRING_CONSTRUCTOR")) { 493 def.setType(TypeDef.STRING); 494 } 495 else if (node.is("IDENT")) { 496 // Could be a reference to parameters 497 String ident = node.text(); 498 499 Set parameters = target.getParameters(); 500 if (!parameters.isEmpty()) { 501 Iterator iter = parameters.iterator(); 502 503 while (iter.hasNext()) { 504 ParameterDef param = (ParameterDef)iter.next(); 505 String name = param.getName(); 506 507 if (name != null && name.equals(ident)) { 508 def.setType(param.getType()); 509 break; 510 } 511 } 512 } 513 } 514 else { 515 // Lets just assume the parser has done its job, but we don't have type information 516 // so all we can do is use a null value w/o any cast 517 // throw new UnexpectedNodeException(node); 518 } 519 520 target.addSuperParameter(def); 521 } 522 523 protected void methodDef(final Node parent) { 524 assert parent != null; 525 526 MethodDef def = new MethodDef(); 527 528 Node node = parent.firstChild(); 529 530 if (node.is("TYPE_PARAMETERS")) { 531 // 532 // FIXME: Support generics 533 // 534 node = node.nextSibling(); 535 } 536 537 node = modifiers(def, node); 538 539 if (node.is("TYPE")) { 540 def.setReturns(type(node)); 541 node = node.nextSibling(); 542 } 543 else { 544 def.setReturns(new TypeDef()); 545 } 546 547 node = name(def, node); 548 549 node = parameters(def, node); 550 551 node = throwz(def, node); 552 553 // Don't care about the body 554 if (node != null) { 555 node.skip("SLIST"); 556 } 557 558 javadocs(def, parent); 559 560 clazz.addMethod(def); 561 } 562 563 protected void annotationFieldDef(final Node parent) { 564 assert parent != null; 565 566 // methodDef(parent); 567 568 MethodDef def = new MethodDef(); 569 570 Node node = parent.firstChild(); 571 572 if (node.is("TYPE_PARAMETERS")) { 573 // 574 // FIXME: Support generics 575 // 576 node = node.nextSibling(); 577 } 578 579 node = modifiers(def, node); 580 581 if (node.is("TYPE")) { 582 def.setReturns(type(node)); 583 node = node.nextSibling(); 584 } 585 else { 586 def.setReturns(new TypeDef()); 587 } 588 589 // 590 // TODO: Support "default" 591 // 592 593 node = name(def, node); 594 595 javadocs(def, parent); 596 597 clazz.addMethod(def); 598 } 599 600 protected void fieldDef(final Node parent) { 601 assert parent != null; 602 603 FieldDef def = new FieldDef(); 604 605 Node node = parent.firstChild(); 606 607 node = modifiers(def, node); 608 609 if (node.is("TYPE")) { 610 def.setType(type(node)); 611 node = node.nextSibling(); 612 } 613 else { 614 def.setType(new TypeDef()); 615 } 616 617 name(def, node); 618 619 javadocs(def, parent); 620 621 clazz.addField(def); 622 } 623 624 protected void enumConstantDef(final Node parent) { 625 assert parent != null; 626 627 parent.ensure("ENUM_CONSTANT_DEF"); 628 629 assert clazz instanceof EnumDef; 630 EnumDef def = (EnumDef)clazz; 631 632 Node node = parent.firstChild(); 633 634 if (node.is("ANNOTATIONS")) { 635 node = node.nextSibling(); 636 } 637 638 String name = identifier(node); 639 640 // 641 // TODO: Determine initialization expression 642 // 643 644 /* 645 Expression init = null; 646 element = element.getNextSibling(); 647 if (element!=null) { 648 init = expression(element); 649 if (isType(ELIST,element)) { 650 if(init instanceof ListExpression && !((ListExpression)init).isWrapped()) { 651 ListExpression le = new ListExpression(); 652 le.addExpression(init); 653 init = le; 654 } 655 } 656 } 657 */ 658 659 def.addConstant(name); 660 } 661 662 // 663 // Helpers 664 // 665 666 protected Node name(final NameAware target, final Node node) { 667 assert target != null; 668 assert node != null; 669 670 target.setName(identifier(node)); 671 672 return node.nextSibling(); 673 } 674 675 protected Node modifiers(final ModifiersAware target, final Node parent) { 676 assert parent != null; 677 678 // Skip unless this is a modifiers node 679 if (!parent.is("MODIFIERS")) { 680 return parent; 681 } 682 683 ModifiersDef def = new ModifiersDef(); 684 685 for (Node node = parent.firstChild(); node != null; node = node.nextSibling()) { 686 687 if (node.is(new String[] { "STRICTFP", "STATIC_IMPORT" })) { 688 // ignore 689 } 690 if (node.is("ANNOTATION")) { 691 // 692 // FIXME: Add annotation support 693 // 694 } 695 else if (node.is("LITERAL_private")) { 696 def.add(ModifiersDef.PRIVATE); 697 } 698 else if (node.is("LITERAL_protected")) { 699 def.add(ModifiersDef.PROTECTED); 700 } 701 else if (node.is("LITERAL_public")) { 702 def.add(ModifiersDef.PUBLIC); 703 } 704 else if (node.is("ABSTRACT")) { 705 def.add(ModifiersDef.ABSTRACT); 706 } 707 else if (node.is("FINAL")) { 708 def.add(ModifiersDef.FINAL); 709 } 710 else if (node.is("LITERAL_native")) { 711 def.add(ModifiersDef.NATIVE); 712 } 713 else if (node.is("LITERAL_static")) { 714 def.add(ModifiersDef.STATIC); 715 } 716 else if (node.is("LITERAL_synchronized")) { 717 def.add(ModifiersDef.SYNCHRONIZED); 718 } 719 else if (node.is("LITERAL_transient")) { 720 def.add(ModifiersDef.TRANSIENT); 721 } 722 else if (node.is("LITERAL_volatile")) { 723 def.add(ModifiersDef.VOLATILE); 724 } 725 else { 726 throw new UnexpectedNodeException(node); 727 } 728 } 729 730 target.getModifiers().merge(def); 731 732 return parent.nextSibling(); 733 } 734 735 protected Set interfaces(final Node parent) { 736 assert parent != null; 737 738 Set set = new LinkedHashSet(); 739 740 for (Node node = parent.firstChild(); node != null; node = node.nextSibling()) { 741 set.add(type(node)); 742 } 743 744 return set; 745 } 746 747 protected Node throwz(final ThrowsAware target, final Node parent) { 748 assert target != null; 749 // assert parent != null; 750 751 if (parent == null) { 752 return null; 753 } 754 755 // The throw statement is optional, so skip if not present 756 if (!parent.is("LITERAL_throws")) { 757 return parent; 758 } 759 760 Node node = parent.firstChild(); 761 762 if (node != null) { 763 do { 764 target.getThrows().add(type(node)); 765 node = node.nextSibling(); 766 } 767 while (node != null); 768 } 769 770 771 return parent.nextSibling(); 772 } 773 774 protected Node parameters(final ParametersAware target, final Node parent) { 775 assert target != null; 776 assert parent != null; 777 778 parent.ensure("PARAMETERS"); 779 780 Node node = parent.firstChild(); 781 782 if (node != null) { 783 do { 784 target.addParameter(parameter(node)); 785 node = node.nextSibling(); 786 } 787 while (node != null); 788 } 789 790 return parent.nextSibling(); 791 } 792 793 protected ParameterDef parameter(final Node parent) { 794 assert parent != null; 795 796 ParameterDef def = new ParameterDef(); 797 798 Node node = parent.firstChild(); 799 800 node = modifiers(def, node); 801 802 if (node.is("TYPE")) { 803 def.setType(type(node)); 804 node = node.nextSibling(); 805 } 806 else { 807 def.setType(new TypeDef()); 808 } 809 810 def.setName(identifier(node)); 811 812 return def; 813 } 814 815 protected TypeDef type(final Node parent) { 816 assert parent != null; 817 818 TypeDef def = new TypeDef(); 819 820 Node node; 821 822 if (parent.is(new String[] { "IDENT", "DOT" })) { 823 node = parent; 824 } 825 else { 826 node = parent.firstChild(); 827 } 828 829 if (node != null) { 830 int dim = 0; 831 832 // Determine array dimentions if there are any 833 while (node.is("ARRAY_DECLARATOR")) { 834 node = node.firstChild(); 835 dim++; 836 } 837 838 def.setDimensions(dim); 839 def.setName(qualifiedName(node)); 840 } 841 842 return def; 843 } 844 845 private static JavaDocParser javaDocParser = new JavaDocParser(); 846 847 protected void javadocs(final JavaDocAware target, final Node node) { 848 assert target != null; 849 assert node != null; 850 851 // Get the snippet between nodes 852 String text = parser.snippet(lastNode, node); 853 854 // Remember where we last looked 855 lastNode = node; 856 857 // Attempt to parse out the docs 858 JavaDocDef def = javaDocParser.parse(text); 859 860 if (def != null) { 861 target.setJavaDoc(def); 862 } 863 } 864 865 protected String qualifiedName(final Node parent) { 866 assert parent != null; 867 868 if (parent.is("IDENT")) { 869 return parent.text(); 870 } 871 else if (parent.is("DOT")) { 872 Node node = parent.firstChild(); 873 StringBuffer buff = new StringBuffer(); 874 boolean first = true; 875 876 for (; node != null; node = node.nextSibling()) { 877 if (first) { 878 first = false; 879 } 880 else { 881 buff.append("."); 882 } 883 884 buff.append(qualifiedName(node)); 885 } 886 return buff.toString(); 887 } 888 else { 889 return parent.text(); 890 } 891 } 892 893 protected String identifier(final Node node) { 894 assert node != null; 895 896 node.ensure("IDENT"); 897 898 return node.text(); 899 } 900 }