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.io.File; 011 import java.util.*; 012 import beaver.*; 013 014 aspect ClassPath { 015 interface BytecodeReader { 016 CompilationUnit read(InputStream is, String fullName, Program p) throws FileNotFoundException, IOException; 017 } 018 interface JavaParser { 019 CompilationUnit parse(InputStream is, String fileName) throws IOException, beaver.Parser.Exception; 020 } 021 022 protected BytecodeReader Program.bytecodeReader; 023 public void Program.initBytecodeReader(BytecodeReader r) { bytecodeReader = r; } 024 protected JavaParser Program.javaParser; 025 public void Program.initJavaParser(JavaParser p) { javaParser = p; } 026 027 syn String CompilationUnit.relativeName() = relativeName; 028 syn String CompilationUnit.pathName() = pathName; 029 syn boolean CompilationUnit.fromSource() = fromSource; 030 031 inh CompilationUnit TypeDecl.compilationUnit(); 032 eq CompilationUnit.getChild().compilationUnit() = this; 033 034 /** 035 * Add a filename to the list of source files to process. 036 * @return The CompilationUnit representing the source file, 037 * or <code>null</code> if no such file exists 038 */ 039 public CompilationUnit Program.addSourceFile(String name) { 040 return sourceFiles.addSourceFile(name); 041 } 042 043 // iterate over all source files and demand-loaded compilation units 044 public Iterator Program.compilationUnitIterator() { 045 initPaths(); 046 return new Iterator() { 047 int index = 0; 048 public boolean hasNext() { 049 return index < getNumCompilationUnit() || !sourceFiles.isEmpty(); 050 } 051 public Object next() { 052 if(getNumCompilationUnit() == index) { 053 String typename = (String)sourceFiles.keySet().iterator().next(); 054 CompilationUnit u = getCompilationUnit(typename); 055 if(u != null) { 056 addCompilationUnit(u); 057 getCompilationUnit(getNumCompilationUnit()-1); 058 } 059 else 060 throw new Error("File " + typename + " not found"); 061 } 062 return getCompilationUnit(index++); 063 } 064 public void remove() { 065 throw new UnsupportedOperationException(); 066 } 067 }; 068 } 069 070 // get the input stream for a compilation unit specified using 071 // a canonical name. This is used by the bytecode reader to load 072 // nested types 073 public InputStream Program.getInputStream(String name) { 074 initPaths(); 075 try { 076 for(Iterator iter = classPath.iterator(); iter.hasNext(); ) { 077 PathPart part = (PathPart)iter.next(); 078 if(part.selectCompilationUnit(name)) 079 return part.is; 080 } 081 } 082 catch(IOException e) { 083 } 084 throw new Error("Could not find nested type " + name); 085 } 086 087 refine public List Program.getCompilationUnitList() { 088 initPaths(); 089 return refined(); 090 } 091 092 // load a compilation unit from disc using the following rules: 093 // 1) specified on the command line 094 // 2) class file not older than source file 095 // 3) source file 096 public CompilationUnit Program.getCompilationUnit(String name) { 097 initPaths(); 098 try { 099 if(sourceFiles.selectCompilationUnit(name)) 100 return sourceFiles.getCompilationUnit(); 101 PathPart sourcePart = null; 102 PathPart classPart = null; 103 for(Iterator iter = sourcePath.iterator(); iter.hasNext() && sourcePart == null; ) { 104 PathPart part = (PathPart)iter.next(); 105 if(part.selectCompilationUnit(name)) 106 sourcePart = part; 107 } 108 for(Iterator iter = classPath.iterator(); iter.hasNext() && classPart == null; ) { 109 PathPart part = (PathPart)iter.next(); 110 if(part.selectCompilationUnit(name)) 111 classPart = part; 112 } 113 114 if(sourcePart != null && (classPart == null || classPart.age < sourcePart.age)) { 115 CompilationUnit unit = sourcePart.getCompilationUnit(); 116 int index = name.lastIndexOf('.'); 117 if(index == -1) 118 return unit; 119 String pkgName = name.substring(0, index); 120 if(pkgName.equals(unit.getPackageDecl())) 121 return unit; 122 } 123 if(classPart != null) { 124 CompilationUnit unit = classPart.getCompilationUnit(); 125 int index = name.lastIndexOf('.'); 126 if(index == -1) 127 return unit; 128 String pkgName = name.substring(0, index); 129 if(pkgName.equals(unit.getPackageDecl())) 130 return unit; 131 } 132 return null; 133 } 134 catch(IOException e) { 135 } 136 return null; 137 } 138 139 /** 140 * @return <code>true</code> if there is a package with the given name on 141 * the path 142 */ 143 public boolean Program.isPackage(String name) { 144 if(sourceFiles.hasPackage(name)) 145 return true; 146 for(Iterator iter = classPath.iterator(); iter.hasNext(); ) { 147 PathPart part = (PathPart)iter.next(); 148 if(part.hasPackage(name)) 149 return true; 150 } 151 for(Iterator iter = sourcePath.iterator(); iter.hasNext(); ) { 152 PathPart part = (PathPart)iter.next(); 153 if(part.hasPackage(name)) 154 return true; 155 } 156 return false; 157 } 158 159 private String CompilationUnit.relativeName; 160 private String CompilationUnit.pathName; 161 private boolean CompilationUnit.fromSource; 162 163 public void CompilationUnit.setRelativeName(String name) { 164 relativeName = name; 165 } 166 public void CompilationUnit.setPathName(String name) { 167 pathName = name; 168 } 169 public void CompilationUnit.setFromSource(boolean value) { 170 fromSource = value; 171 } 172 173 private boolean Program.pathsInitialized = false; 174 private java.util.ArrayList Program.classPath; 175 private java.util.ArrayList Program.sourcePath; 176 private FileNamesPart Program.sourceFiles = new FileNamesPart(this); 177 178 public void Program.pushClassPath(String name) { 179 PathPart part = PathPart.createSourcePath(name, this); 180 if(part != null) { 181 sourcePath.add(part); 182 System.out.println("Pushing source path " + name); 183 } 184 else 185 throw new Error("Could not push source path " + name); 186 part = PathPart.createClassPath(name, this); 187 if(part != null) { 188 classPath.add(part); 189 System.out.println("Pushing class path " + name); 190 } 191 } 192 public void Program.popClassPath() { 193 if(sourcePath.size() > 0) 194 sourcePath.remove(sourcePath.size()-1); 195 if(classPath.size() > 0) 196 classPath.remove(classPath.size()-1); 197 } 198 199 public void Program.initPaths() { 200 if(!pathsInitialized) { 201 pathsInitialized = true; 202 203 //System.err.println("Initializing class paths"); 204 205 ArrayList classPaths = new ArrayList(); 206 ArrayList sourcePaths = new ArrayList(); 207 208 String[] bootclasspaths; 209 if(options().hasValueForOption("-bootclasspath")) 210 bootclasspaths = options().getValueForOption("-bootclasspath").split(File.pathSeparator); 211 else 212 bootclasspaths = System.getProperty("sun.boot.class.path").split(File.pathSeparator); 213 for(int i = 0; i < bootclasspaths.length; i++) { 214 classPaths.add(bootclasspaths[i]); 215 //System.err.println("Adding classpath " + bootclasspaths[i]); 216 } 217 218 String[] extdirs; 219 if(options().hasValueForOption("-extdirs")) 220 extdirs = options().getValueForOption("-extdirs").split(File.pathSeparator); 221 else 222 extdirs = System.getProperty("java.ext.dirs").split(File.pathSeparator); 223 for(int i = 0; i < extdirs.length; i++) { 224 classPaths.add(extdirs[i]); 225 //System.err.println("Adding classpath " + extdirs[i]); 226 } 227 228 String[] userClasses = null; 229 if(options().hasValueForOption("-classpath")) 230 userClasses = options().getValueForOption("-classpath").split(File.pathSeparator); 231 else if(options().hasValueForOption("-cp")) 232 userClasses = options().getValueForOption("-cp").split(File.pathSeparator); 233 else { 234 userClasses = ".".split(File.pathSeparator); 235 } 236 if(!options().hasValueForOption("-sourcepath")) { 237 for(int i = 0; i < userClasses.length; i++) { 238 classPaths.add(userClasses[i]); 239 sourcePaths.add(userClasses[i]); 240 //System.err.println("Adding classpath/sourcepath " + userClasses[i]); 241 } 242 } 243 else { 244 for(int i = 0; i < userClasses.length; i++) { 245 classPaths.add(userClasses[i]); 246 //System.err.println("Adding classpath " + userClasses[i]); 247 } 248 userClasses = options().getValueForOption("-sourcepath").split(File.pathSeparator); 249 for(int i = 0; i < userClasses.length; i++) { 250 sourcePaths.add(userClasses[i]); 251 //System.err.println("Adding sourcepath " + userClasses[i]); 252 } 253 } 254 255 classPath = new ArrayList(); 256 sourcePath = new ArrayList(); 257 258 for(Iterator iter = classPaths.iterator(); iter.hasNext(); ) { 259 String s = (String)iter.next(); 260 PathPart part = PathPart.createClassPath(s, this); 261 if(part != null) { 262 classPath.add(part); 263 //System.out.println("Adding classpath " + s); 264 } 265 else if(options().verbose()) 266 System.out.println("Warning: Could not use " + s + " as class path"); 267 } 268 for(Iterator iter = sourcePaths.iterator(); iter.hasNext(); ) { 269 String s = (String)iter.next(); 270 PathPart part = PathPart.createSourcePath(s, this); 271 if(part != null) { 272 sourcePath.add(part); 273 //System.out.println("Adding sourcepath " + s); 274 } 275 else if(options().verbose()) 276 System.out.println("Warning: Could not use " + s + " as source path"); 277 } 278 } 279 } 280 281 /** 282 * Add a path part to the library class path. 283 */ 284 public void Program.addClassPath(PathPart pathPart) { 285 classPath.add(pathPart); 286 pathPart.program = this; 287 } 288 289 /** 290 * Add a path part to the user class path. 291 */ 292 public void Program.addSourcePath(PathPart pathPart) { 293 sourcePath.add(pathPart); 294 pathPart.program = this; 295 } 296 297 // remove user defined classes from this program but keep library classes 298 public void Program.simpleReset() { 299 lookupType_String_String_values = new HashMap(); 300 hasPackage_String_values = new HashMap(); 301 List list = new List(); 302 for(int i = 0; i < getNumCompilationUnit(); i++) { 303 CompilationUnit unit = getCompilationUnit(i); 304 if(!unit.fromSource()) { 305 list.add(unit); 306 } 307 } 308 setCompilationUnitList(list); 309 } 310 }