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 }