001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     * All rights reserved.
008     */
009    
010    aspect Java2Rewrites {
011      int TypeDecl.uniqueIndexCounter = 1;
012      syn lazy int TypeDecl.uniqueIndex() = topLevelType().uniqueIndexCounter++;
013    
014    
015      syn lazy String TypeDecl.jvmName() {
016        throw new Error("Jvm name only supported for reference types and not " + getClass().getName());
017      }
018      eq ReferenceType.jvmName() {
019        if(!isNestedType())
020          return fullName();
021        else if(isAnonymous() || isLocalClass())
022          return enclosingType().jvmName() + "$" + uniqueIndex() + name();
023        else
024          return enclosingType().jvmName() + "$" + name();
025      }
026      eq ArrayDecl.jvmName() {
027        StringBuffer dim = new StringBuffer();
028        for(int i = 0; i < dimension(); i++)
029          dim.append("[");
030        if(elementType().isReferenceType())
031          return dim.toString() + "L" + elementType().jvmName() + ";";
032        else
033          return dim.toString() + elementType().jvmName(); 
034      }
035      eq ByteType.jvmName() = "B";
036      eq CharType.jvmName() = "C";
037      eq ShortType.jvmName() = "S";
038      eq IntType.jvmName() = "I";
039      eq LongType.jvmName() = "J";
040      eq FloatType.jvmName() = "F";
041      eq DoubleType.jvmName() = "D";
042      eq BooleanType.jvmName() = "Z";
043    
044      syn String TypeDecl.primitiveClassName() {
045        throw new Error("primitiveClassName not supported for " + name() + " of type " + getClass().getName());
046      }
047      eq ByteType.primitiveClassName() = "Byte";
048      eq CharType.primitiveClassName() = "Character";
049      eq ShortType.primitiveClassName() = "Short";
050      eq IntType.primitiveClassName() = "Integer";
051      eq LongType.primitiveClassName() = "Long";
052      eq FloatType.primitiveClassName() = "Float";
053      eq DoubleType.primitiveClassName() = "Double";
054      eq BooleanType.primitiveClassName() = "Boolean";
055      eq VoidType.primitiveClassName() = "Void";
056      
057      syn String TypeDecl.referenceClassFieldName() {
058        throw new Error("referenceClassFieldName not supported for " + name() + " of type " + getClass().getName());
059      }
060      eq ReferenceType.referenceClassFieldName() = "class$" + jvmName().replace('[', '$').replace('.', '$').replace(';', ' ').trim();
061      eq ArrayDecl.referenceClassFieldName() = "array" + jvmName().replace('[', '$').replace('.', '$').replace(';', ' ').trim();
062      
063    
064      // lazily build a static field for assertionsDisabled 
065      private FieldDeclaration TypeDecl.createAssertionsDisabled = null;
066      public FieldDeclaration TypeDecl.createAssertionsDisabled() {
067        if(createAssertionsDisabled != null)
068          return createAssertionsDisabled;
069        // static final boolean $assertionsDisabled = !TypeName.class.desiredAssertionStatus();
070        createAssertionsDisabled = new FieldDeclaration(
071          new Modifiers(new List().add(new Modifier("public")).add(new Modifier("static")).add(new Modifier("final"))),
072          new PrimitiveTypeAccess("boolean"),
073          "$assertionsDisabled",
074          new Opt(
075              new LogNotExpr(
076                topLevelType().createQualifiedAccess().qualifiesAccess(
077                  new ClassAccess().qualifiesAccess(
078                    new MethodAccess(
079                      "desiredAssertionStatus",
080                      new List()
081                    )
082                  )
083                )
084              )
085          )
086        );
087        getBodyDeclList().insertChild(createAssertionsDisabled, 0);
088        // explicit read to trigger possible rewrites
089        createAssertionsDisabled = (FieldDeclaration)getBodyDeclList().getChild(0);
090        // transform the generated initalization, e.g., the ClassAccess construct
091        createAssertionsDisabled.transformation();
092        return createAssertionsDisabled;
093      }
094    
095      public FieldDeclaration InterfaceDecl.createStaticClassField(String name) {
096        return methodHolder().createStaticClassField(name);
097      }
098      public MethodDecl InterfaceDecl.createStaticClassMethod() {
099        return methodHolder().createStaticClassMethod();
100      }
101      // create anonymous class to delegate to
102      private TypeDecl InterfaceDecl.methodHolder = null;
103      public TypeDecl InterfaceDecl.methodHolder() {
104        if(methodHolder != null)
105          return methodHolder;
106        String name = "$" + nextAnonymousIndex();
107        ClassDecl c = addMemberClass(new ClassDecl(
108          new Modifiers(new List()),
109          name,
110          new Opt(),
111          new List(),
112          new List()
113        ));
114        methodHolder = c;
115        return c;
116      }
117    
118      // lazily build a static field for each typename used in a .class expression
119      private HashMap TypeDecl.createStaticClassField = null;
120      public FieldDeclaration TypeDecl.createStaticClassField(String name) {
121        if(createStaticClassField == null)
122          createStaticClassField = new HashMap();
123        if(createStaticClassField.containsKey(name))
124          return (FieldDeclaration)createStaticClassField.get(name);
125        // static synthetic Class class$java$lang$String;
126        FieldDeclaration f = new FieldDeclaration(
127          new Modifiers(new List().add(new Modifier("public")).add(new Modifier("static"))),
128          lookupType("java.lang", "Class").createQualifiedAccess(),
129          name,
130          new Opt()
131        ) {
132          public boolean isConstant() {
133            return true;
134          }
135        };
136        createStaticClassField.put(name, f);
137        return addMemberField(f);
138      }
139    
140      // lazily build a static class$ method in this type declaration
141      private MethodDecl TypeDecl.createStaticClassMethod = null;
142      public MethodDecl TypeDecl.createStaticClassMethod() {
143        if(createStaticClassMethod != null)
144          return createStaticClassMethod;
145        // static synthetic Class class$(String name) {
146        //   try {
147        //     return java.lang.Class.forName(name);
148        //   } catch(java.lang.ClassNotFoundException e) {
149        //     throw new java.lang.NoClassDefFoundError(e.getMessage());
150        //   }
151        // }
152        createStaticClassMethod = new MethodDecl(
153          new Modifiers(new List().add(new Modifier("public")).add(new Modifier("static"))),
154          lookupType("java.lang", "Class").createQualifiedAccess(),
155          "class$",
156          new List().add(
157            new ParameterDeclaration(
158              new Modifiers(new List()),
159              lookupType("java.lang", "String").createQualifiedAccess(),
160              "name"
161            )
162          ),
163          new List(),
164          new Opt(
165            new Block(
166              new List().add(
167                new TryStmt(
168                  new Block(
169                    new List().add(
170                      new ReturnStmt(
171                        new Opt(
172                          lookupType("java.lang", "Class").createQualifiedAccess().qualifiesAccess(
173                            new MethodAccess(
174                              "forName",
175                              new List().add(
176                                new VarAccess("name")
177                              )
178                            )
179                          )
180                        )
181                      )
182                    )
183                  ),
184                  new List().add(
185                    new BasicCatch(
186                      new ParameterDeclaration(
187                        new Modifiers(new List()),
188                        lookupType("java.lang", "ClassNotFoundException").createQualifiedAccess(),
189                        "e"
190                      ),
191                      new Block(
192                        new List().add(
193                          new ThrowStmt(
194                            new ClassInstanceExpr(
195                              lookupType("java.lang", "NoClassDefFoundError").createQualifiedAccess(),
196                              new List().add(
197                                new VarAccess("e").qualifiesAccess(
198                                  new MethodAccess(
199                                    "getMessage",
200                                    new List()
201                                  )
202                                )
203                              ),
204                              new Opt()
205                            )
206                          )
207                        )
208                      )
209                    )
210                  ),
211                  new Opt()
212                )
213              )
214            )
215          )
216        ) {
217          public boolean isConstant() {
218            return true;
219          }
220        };
221        return addMemberMethod(createStaticClassMethod);
222      }
223      
224    }