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 import java.util.*; 011 import java.util.ArrayList; 012 013 aspect ConstructScope { 014 inh Collection ConstructorAccess.lookupConstructor(); 015 eq Program.getChild().lookupConstructor() = Collections.EMPTY_LIST; 016 eq TypeDecl.getBodyDecl().lookupConstructor() = constructors(); 017 eq AbstractDot.getRight().lookupConstructor() = getLeft().type().constructors(); 018 019 inh Collection SuperConstructorAccess.lookupSuperConstructor(); 020 eq TypeDecl.getBodyDecl().lookupSuperConstructor() = lookupSuperConstructor(); 021 syn Collection TypeDecl.lookupSuperConstructor() = Collections.EMPTY_LIST; 022 eq ClassDecl.lookupSuperConstructor() = hasSuperclass() ? superclass().constructors() : Collections.EMPTY_LIST; 023 eq InterfaceDecl.lookupSuperConstructor() = typeObject().constructors(); 024 eq Program.getChild().lookupSuperConstructor() = Collections.EMPTY_LIST; 025 eq AbstractDot.getRight().lookupSuperConstructor() = getLeft().type().lookupSuperConstructor(); 026 027 inh TypeDecl ClassInstanceExpr.typeObject(); 028 029 // compute the most specific constructor in a collection 030 // the constructor is invoked with the arguments specified in argList 031 // the curent context (this) is used to evaluate the hostType for accessibility 032 syn SimpleSet Expr.mostSpecificConstructor(Collection constructors) { 033 SimpleSet maxSpecific = SimpleSet.emptySet; 034 for(Iterator iter = constructors.iterator(); iter.hasNext(); ) { 035 ConstructorDecl decl = (ConstructorDecl)iter.next(); 036 if(applicableAndAccessible(decl)) { 037 if(maxSpecific.isEmpty()) 038 maxSpecific = maxSpecific.add(decl); 039 else { 040 if(decl.moreSpecificThan((ConstructorDecl)maxSpecific.iterator().next())) 041 maxSpecific = SimpleSet.emptySet.add(decl); 042 else if(!((ConstructorDecl)maxSpecific.iterator().next()).moreSpecificThan(decl)) 043 maxSpecific = maxSpecific.add(decl); 044 } 045 } 046 } 047 return maxSpecific; 048 } 049 050 syn boolean Expr.applicableAndAccessible(ConstructorDecl decl) = false; 051 eq ConstructorAccess.applicableAndAccessible(ConstructorDecl decl) = 052 decl.applicable(getArgList()) && decl.accessibleFrom(hostType()); 053 eq ClassInstanceExpr.applicableAndAccessible(ConstructorDecl decl) = 054 decl.applicable(getArgList()) && decl.accessibleFrom(hostType()) && 055 (!decl.isProtected() || hasTypeDecl() || decl.hostPackage().equals(hostPackage())); 056 057 syn lazy SimpleSet ConstructorAccess.decls() = mostSpecificConstructor(lookupConstructor()); 058 059 syn lazy SimpleSet SuperConstructorAccess.decls() { 060 Collection c = hasPrevExpr() && !prevExpr().isTypeAccess() ? 061 hostType().lookupSuperConstructor() : lookupSuperConstructor(); 062 return mostSpecificConstructor(c); 063 } 064 065 syn lazy ConstructorDecl ConstructorAccess.decl() { 066 SimpleSet decls = decls(); 067 if(decls.size() == 1) 068 return (ConstructorDecl)decls.iterator().next(); 069 return unknownConstructor(); 070 } 071 inh ConstructorDecl ConstructorAccess.unknownConstructor(); 072 073 syn lazy SimpleSet ClassInstanceExpr.decls() { 074 TypeDecl typeDecl = hasTypeDecl() ? getTypeDecl() : getAccess().type(); 075 return mostSpecificConstructor(typeDecl.constructors()); 076 } 077 078 syn lazy ConstructorDecl ClassInstanceExpr.decl() { 079 SimpleSet decls = decls(); 080 if(decls.size() == 1) 081 return (ConstructorDecl)decls.iterator().next(); 082 return unknownConstructor(); 083 } 084 inh ConstructorDecl ClassInstanceExpr.unknownConstructor(); 085 } 086 087 aspect ConstructorLookup { 088 public ConstructorDecl TypeDecl.lookupConstructor(ConstructorDecl signature) { 089 for(Iterator iter = constructors().iterator(); iter.hasNext(); ) { 090 ConstructorDecl decl = (ConstructorDecl)iter.next(); 091 if(decl.sameSignature(signature)) { 092 return decl; 093 } 094 } 095 return null; 096 } 097 098 syn lazy Collection TypeDecl.constructors() { 099 Collection c = new ArrayList(); 100 for(int i = 0; i < getNumBodyDecl(); i++) { 101 if(getBodyDecl(i) instanceof ConstructorDecl) { 102 c.add(getBodyDecl(i)); 103 } 104 } 105 return c; 106 } 107 } 108 109 aspect ConstructorDecl { 110 syn lazy String ConstructorDecl.name() = getID(); 111 // 8.8.2 112 syn lazy String ConstructorDecl.signature() { 113 StringBuffer s = new StringBuffer(); 114 s.append(name() + "("); 115 for(int i = 0; i < getNumParameter(); i++) { 116 s.append(getParameter(i)); 117 if(i != getNumParameter() - 1) 118 s.append(", "); 119 } 120 s.append(")"); 121 return s.toString(); 122 } 123 124 // 8.8.2 125 syn lazy boolean ConstructorDecl.sameSignature(ConstructorDecl c) { 126 if(!name().equals(c.name())) 127 return false; 128 if(c.getNumParameter() != getNumParameter()) 129 return false; 130 for(int i = 0; i < getNumParameter(); i++) 131 if(!c.getParameter(i).type().equals(getParameter(i).type())) 132 return false; 133 return true; 134 } 135 136 syn lazy boolean ConstructorDecl.moreSpecificThan(ConstructorDecl m) { 137 for(int i = 0; i < getNumParameter(); i++) { 138 if(!getParameter(i).type().instanceOf(m.getParameter(i).type())) 139 return false; 140 } 141 return true; 142 } 143 144 public boolean ConstructorDecl.applicable(List argList) { 145 if(getNumParameter() != argList.getNumChild()) 146 return false; 147 for(int i = 0; i < getNumParameter(); i++) { 148 TypeDecl arg = ((Expr)argList.getChild(i)).type(); 149 TypeDecl parameter = getParameter(i).type(); 150 if(!arg.instanceOf(parameter)) { 151 return false; 152 } 153 } 154 return true; 155 } 156 } 157 aspect ImplicitConstructor { 158 syn boolean List.requiresDefaultConstructor() { 159 if(getParent() instanceof ClassDecl) { 160 ClassDecl c = (ClassDecl)getParent(); 161 return c.noConstructor() && c.getBodyDeclListNoTransform() == this && !(c instanceof AnonymousDecl); 162 } 163 return false; 164 } 165 166 /** 167 * Flag to indicate if this constructor is an auto-generated 168 * default constructor. Default constructors are not pretty 169 * printed. 170 */ 171 private boolean ConstructorDecl.isDefaultConstructor = false; 172 /** 173 * Set the default constructor flag. Causes this constructor 174 * to not be pretty printed. 175 */ 176 public void ConstructorDecl.setDefaultConstructor() { 177 isDefaultConstructor = true; 178 } 179 /** 180 * @return true if this is an auto-generated default constructor 181 */ 182 syn boolean ConstructorDecl.isDefaultConstructor() = 183 isDefaultConstructor; 184 185 rewrite List { 186 when(requiresDefaultConstructor()) 187 to List { 188 ClassDecl c = (ClassDecl)getParent(); 189 Modifiers m = new Modifiers(); 190 if(c.isPublic()) m.addModifier(new Modifier("public")); 191 else if(c.isProtected()) m.addModifier(new Modifier("protected")); 192 else if(c.isPrivate()) m.addModifier(new Modifier("private")); 193 ConstructorDecl constructor = new ConstructorDecl( 194 m, 195 c.name(), 196 new List(), 197 new List(), 198 new Opt(), 199 new Block() 200 ); 201 constructor.setDefaultConstructor(); 202 c.addBodyDecl(constructor); 203 return this; 204 } 205 } 206 207 syn boolean ClassDecl.noConstructor() { 208 if(!compilationUnit().fromSource()) 209 return false; 210 for(int i = 0; i < getNumBodyDecl(); i++) 211 if(getBodyDecl(i) instanceof ConstructorDecl) 212 return false; 213 return true; 214 } 215 216 // 8.8.5 217 rewrite ConstructorDecl { 218 when(!hasConstructorInvocation() && !hostType().isObject()) 219 to ConstructorDecl { 220 setConstructorInvocation( 221 new ExprStmt( 222 new SuperConstructorAccess("super", new List()) 223 ) 224 ); 225 return this; 226 } 227 } 228 } 229 230