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 Transformations {
011      // generic traversal of the tree
012      public void ASTNode.transformation() {
013        for(int i = 0; i < getNumChild(); i++) {
014            getChild(i).transformation();
015        }
016      }
017      
018      public void CompilationUnit.transformation() {
019        if(fromSource()) {
020          for(int i = 0; i < getNumTypeDecl(); i++) {
021            getTypeDecl(i).transformation();
022          }
023        }
024      }
025      
026      // remote collection
027      public void TypeDecl.transformation() {
028        addEnclosingVariables();
029        super.transformation();
030        if(isNestedType())
031          enclosingType().addNestedType(this);
032      }
033    
034      /*
035      public void Expr.transformation() {
036        if(isConstant() && !(this instanceof Literal))
037          replace(this).with(constant().buildLiteral());
038        else
039          super.transformation();
040      }
041      */
042    
043      // remote collection
044      public void TypeAccess.transformation() {
045        super.transformation();
046        if(type().elementType().isNestedType() && hostType() != null)
047          hostType().addUsedNestedType(type().elementType());
048      }
049      
050      /*
051      public void Dot.transformation() {
052        if(leftSide().isTypeAccess() && rightSide() instanceof ThisAccess) {
053          System.out.println("Replacing " + this);
054          Access a = new ThisAccess("this");
055          TypeDecl targetType = rightSide().type();
056          TypeDecl typeDecl = hostType();
057          while(typeDecl != null && typeDecl != targetType) {
058            a = a.qualifiesAccess(new VarAccess("this$0"));
059            typeDecl = typeDecl.enclosingType();
060          }
061          ASTNode result = replace(this).with(qualifyTailWith(a));
062          result.transformation();
063          return;
064        }
065        super.transformation();
066      }*/
067    
068      // remote collection / demand driven creation of accessor
069      public void MethodAccess.transformation() {
070        MethodDecl m = decl();
071    
072    
073        /*if(!isQualified() && !m.isStatic()) {
074          TypeDecl typeDecl = hostType();
075          while(typeDecl != null && !typeDecl.hasMethod(name()))
076            typeDecl = typeDecl.enclosingType();
077          ASTNode result = replace(this).with(typeDecl.createQualifiedAccess().qualifiesAccess(new ThisAccess("this")).qualifiesAccess(new MethodAccess(name(), getArgList())));
078          result.transformation();
079          return;
080        }*/
081        
082        if(requiresAccessor()) {
083          /* Access to private methods in enclosing types:
084          The original MethodAccess is replaced with an access to an accessor method
085          built by createAccessor(). This method is built lazily and differs from
086          normal MethodDeclarations in the following ways:
087          1) The method in the class file should always be static and the signature
088             is thus changed to include a possible this reference as the first argument. 
089          2) The method is always invoked using INVOKESTATIC
090          3) The flags must indicate that the method is static and package private
091          */
092          super.transformation();
093          replace(this).with(decl().createAccessor(methodQualifierType()).createBoundAccess(getArgList()));
094          return;
095        }
096        else if(!m.isStatic() && isQualified() && prevExpr().isSuperAccess() && !hostType().instanceOf(prevExpr().type())) {
097          decl().createSuperAccessor(superAccessorTarget());
098        }
099        super.transformation();
100      }
101    
102      // remote collection / demand driven creation of accessor
103      public void VarAccess.transformation() {
104        Variable v = decl();
105        if(v instanceof FieldDeclaration) {
106          FieldDeclaration f = (FieldDeclaration)v;
107          if(requiresAccessor()) {
108            TypeDecl typeDecl = fieldQualifierType();
109            if(isSource())
110              f.createAccessor(typeDecl);
111            if(isDest())
112              f.createAccessorWrite(typeDecl);
113          }
114        }
115        super.transformation();
116      }
117    
118    
119      public void ConstructorDecl.transformation() {
120        // this$val as fields and constructor parameters
121        addEnclosingVariables();
122        super.transformation();
123      }
124    
125    
126      // remote collection / demand driven creation of accessor
127      public void ClassInstanceExpr.transformation() {
128        // this$val
129        addEnclosingVariables();
130        // touch accessorIndex go force creation of private constructorAccessor
131        if(decl().isPrivate() && type() != hostType()) {
132          decl().createAccessor();
133        }
134        super.transformation();
135      }
136    
137      // remote collection / demand driven creation of accessor
138      public void ConstructorAccess.transformation() {
139        // this$val
140        addEnclosingVariables();
141        // touch accessorIndex go force creation of private constructorAccessor
142        if(decl().isPrivate() && decl().hostType() != hostType()) {
143          decl().createAccessor();
144        }
145        super.transformation();
146      }
147    
148      // remote collection / demand driven creation of accessor
149      public void SuperConstructorAccess.transformation() {
150        // this$val
151        addEnclosingVariables();
152        // touch accessorIndex to force creation of private constructorAccessor
153        if(decl().isPrivate() && decl().hostType() != hostType()) {
154          decl().createAccessor();
155        }
156        super.transformation();
157      }
158    
159      // remote collection / demand driven creation of accessor
160      public void ClassAccess.transformation() {
161        super.transformation();
162        // touch static class method before any accessors to make it first in method
163        if(isQualified() && qualifier().type().isReferenceType()) {
164          hostType().topLevelType().createStaticClassMethod();
165          FieldDeclaration f = hostType().topLevelType().createStaticClassField(prevExpr().type().referenceClassFieldName());
166        }
167        
168      }
169    
170      public void AssertStmt.transformation() {
171        super.transformation();
172        // add field to hold cached result as a side-effect
173        FieldDeclaration f = hostType().topLevelType().createStaticClassField(hostType().topLevelType().referenceClassFieldName());
174        FieldDeclaration assertionsDisabled = hostType().createAssertionsDisabled();
175        Expr condition = (Expr)getfirst().fullCopy();
176        List args = new List();
177        if(hasExpr())
178          if(getExpr().type().isString())
179            args.add(new CastExpr(new TypeAccess("java.lang", "Object"), (Expr)getExpr().fullCopy()));
180          else
181            args.add(getExpr().fullCopy());
182        Stmt stmt = 
183          new IfStmt(
184            new LogNotExpr(
185              new ParExpr(
186                new OrLogicalExpr(
187                  new BoundFieldAccess(assertionsDisabled),
188                  condition
189                )
190              )
191            ),
192            new ThrowStmt(
193              new ClassInstanceExpr(
194                lookupType("java.lang", "AssertionError").createQualifiedAccess(),
195                args,
196                new Opt()
197              )
198            ),
199            new Opt()
200          );
201         
202        replace(this).with(stmt);
203        stmt.transformation();
204      }
205      
206      // imperative transformation of the AST
207      // syntax ASTNode.replace(sourcenode).with(destnode)
208      // this syntax is used to allow for building the destnode using the sourcenode
209      protected ASTNode ASTNode.replace(ASTNode node) {
210        state().replacePos = node.getParent().getIndexOfChild(node);
211        node.getParent().in$Circle(true);
212        return node.getParent();
213      }
214      protected ASTNode ASTNode.with(ASTNode node) {
215       ((ASTNode)this).setChild(node, state().replacePos);
216       in$Circle(false);
217       return node;
218      }
219      public int ASTNode$State.replacePos = 0;
220    }