001 /* Copyright 2000, 2001, Compaq Computer Corporation */ 002 003 package javafe; 004 005 import java.util.Vector; 006 import java.util.Iterator; 007 import java.util.ArrayList; 008 009 import javafe.ast.*; 010 import javafe.tc.*; 011 import javafe.util.*; 012 import javafe.genericfile.GenericFile; 013 import javafe.genericfile.NormalGenericFile; 014 015 import java.io.BufferedReader; 016 import java.io.FileReader; 017 import java.io.IOException; 018 019 /** 020 * <code>SrcTool</code> is an abstract class for tools that use 021 * our Java front end to process the <code>CompilationUnit</code>s 022 * found in source files. <p> 023 * 024 * It adds to <code>FrontEndTool</code> code for processing a series of 025 * source files specified on the command line. 026 * 027 * If processRecursively is set, then files are processed 028 * recursively. (I.e., files loaded in the course of processing one 029 * file are also processed.)<p> 030 * 031 * The remaining processing, if any, is front-end-tool specific.<p> 032 */ 033 034 public abstract class SrcTool extends FrontEndTool implements Listener 035 { 036 037 /*************************************************** 038 * * 039 * Keeping track of loaded CompilationUnits: * 040 * * 041 **************************************************/ 042 043 /** 044 * A list of all the <code>CompilationUnit</code>s we have loaded 045 * so far. This list is extended automatically at the end as new 046 * <code>CompilationUnit</code>s are loaded using notification from 047 * <code>OutsideEnv</code>. 048 */ 049 //@ invariant loaded != null; 050 //@ invariant loaded.elementType == \type(CompilationUnit); 051 //@ invariant !loaded.containsNull; 052 //@ invariant loaded.owner == this; 053 public Vector loaded = new Vector(); 054 055 public SrcTool() { 056 super(); 057 058 //@ set loaded.elementType = \type(CompilationUnit); 059 //@ set loaded.containsNull = false; 060 //@ set loaded.owner = this; 061 } 062 063 064 /** 065 * Add a <code>CompilationUnit</code> to <code>loaded</code>. <p> 066 * 067 * This should only be called by <code>OutsideEnv</code> using the 068 * <code>Listener</code> interface.<p> 069 */ 070 public void notify(CompilationUnit justLoaded) { 071 if (!justLoaded.duplicate) loaded.addElement(justLoaded); 072 } 073 074 075 /*************************************************** 076 * * 077 * Main processing code: * 078 * * 079 **************************************************/ 080 081 public Options makeOptions() { 082 return new SrcToolOptions(); 083 } 084 085 private static SrcToolOptions options() { 086 return (SrcToolOptions)options; 087 } 088 089 /** 090 * Main processing loop for <code>SrcTool</code>. <p> 091 * 092 * The remaining arguments are <code>args[offset]</code>, 093 * <code>args[offset+1]</code>, ...<p> 094 * 095 * This method calls preload, loadAllFiles, postload, preprocess, handleAllCU, postprocess. 096 */ 097 public void frontEndToolProcessing(ArrayList args) { 098 long startTime = currentTime(); 099 /* 100 * At this point, all options have already been processed and 101 * the front end has been initialized. 102 */ 103 104 preload(); 105 106 loadAllFiles(args); 107 108 postload(); 109 110 // Do any tool-specific pre-processing: 111 preprocess(); 112 113 if (!options.quiet) 114 System.out.println(" [" + timeUsed(startTime) + "]"); 115 116 handleAllCUs(); 117 118 // Do any tool-specific post-processing: 119 postprocess(); 120 } 121 122 123 /*************************************************** 124 * * 125 * SrcTool-instance specific processing: * 126 * * 127 **************************************************/ 128 129 public void loadAllFiles(ArrayList args) { 130 ArrayList accumulatedResults = new ArrayList(args.size()); 131 Iterator i = args.iterator(); 132 while (i.hasNext()) { 133 InputEntry ie = (InputEntry)i.next(); 134 ArrayList a = resolveInputEntry(ie); 135 OutsideEnv.addSources(a); 136 } 137 } 138 139 //@ ensures \result.elementType <: \type(GenericFile); 140 public ArrayList resolveInputEntry(InputEntry iee) { 141 InputEntry ie = iee; 142 if (ie.contents == null) { 143 ie = ie.resolve(); 144 if (!ie.auto) { 145 String s = ie.verify(); 146 if (s != null) { 147 ErrorSet.error(s); 148 ie.contents = new ArrayList(0); 149 return ie.contents; 150 } 151 } 152 if (ie instanceof FileInputEntry) { 153 ie.contents = new ArrayList(1); 154 ie.contents.add(new NormalGenericFile(ie.name)); 155 } else if (ie instanceof DirInputEntry) { 156 ie.contents = OutsideEnv.resolveDirSources(ie.name); 157 } else if (ie instanceof PackageInputEntry) { 158 String[] pa = javafe.filespace.StringUtil.parseList(ie.name,'.'); 159 ie.contents = OutsideEnv.resolveSources(pa); 160 } else if (ie instanceof ClassInputEntry) { 161 ie.contents = new ArrayList(1); 162 int p = ie.name.lastIndexOf('.'); 163 if (p == -1) { 164 GenericFile gf = OutsideEnv.reader.findType( 165 new String[0],ie.name); 166 ie.contents.add(gf); 167 } else if (p==0 || p == ie.name.length()-1) { 168 ErrorSet.error("Invalid type name: " + ie.name); 169 ie.contents = new ArrayList(0); 170 } else { 171 String[] pa = javafe.filespace.StringUtil.parseList( 172 ie.name.substring(0,p),'.'); 173 GenericFile gf = OutsideEnv.reader.findType(pa, 174 ie.name.substring(p+1)); 175 ie.contents.add(gf); 176 } 177 } else if (ie instanceof ListInputEntry) { 178 ie.contents = resolveList(ie.name); 179 } else { 180 ErrorSet.caution("Skipping unknown (or not found) input item: " 181 + ie.name); 182 ie.contents = new ArrayList(0); 183 } 184 } 185 return ie.contents; 186 } 187 188 public void loadInputEntry(InputEntry ie) { 189 OutsideEnv.addSources(resolveInputEntry(ie)); 190 } 191 192 //@ requires argumentFileName != null; 193 //@ ensures \result.elementType <: \type(GenericFile); 194 public ArrayList resolveList(String argumentFileName) { 195 /* load in source files from supplied file name */ 196 ArrayList list = new ArrayList(); 197 try { 198 BufferedReader in = null; 199 try { 200 in = new BufferedReader( 201 new FileReader(argumentFileName)); 202 String s; 203 while ((s = in.readLine()) != null) { 204 // allow blank lines in files list 205 if (!s.equals("")) { 206 ArrayList a = (resolveInputEntry(InputEntry.make(s))); 207 if (a != null) list.addAll(a); 208 } 209 } 210 } finally { 211 if (in != null) in.close(); 212 } 213 } catch (IOException e) { 214 ErrorSet.error("I/O failure while reading argument list file " 215 + argumentFileName + ": " + e.getMessage()); 216 } 217 return list; 218 } 219 220 /* 221 public void resolvePackages(ArrayList packagesToProcess) { 222 Iterator i = packagesToProcess.iterator(); 223 while (i.hasNext()) { 224 String p = (String)i.next(); 225 } 226 } 227 */ 228 /** Iterates, calling handleCU for each loaded CU. 229 */ 230 public void handleAllCUs() { 231 /* 232 * Call handleCU on the resulting loaded CompilationUnits. 233 * 234 * If processRecursively is true, then continue calling handleCU 235 * on loaded CompilationUnits that have not had handleCU called 236 * on them in the order they were loaded until no such 237 * CompilationUnits remain. (handleCU may load CompilationUnits 238 * indirectly.) 239 */ 240 int i=0; 241 for (int end=loaded.size(); i<end; i++) { 242 handleCU((CompilationUnit)loaded.elementAt(i)); 243 if (options().processRecursively) { 244 Assert.notFalse(OutsideEnv.avoidSpec == true); 245 end = loaded.size(); 246 } 247 } 248 } 249 250 /** 251 * Hook for any work needed before any files are loaded. 252 */ 253 public void preload() { 254 // Set up to receive CompilationUnit-loading notification events: 255 OutsideEnv.setListener(this); 256 } 257 258 /** 259 * Called for any work after loading files 260 */ 261 // FIXME - can this be done at preload time? 262 public void postload() { 263 OutsideEnv.avoidSpec = options().avoidSpec; 264 if (options().processRecursively) 265 OutsideEnv.avoidSpec = true; 266 } 267 268 /** 269 * Hook for any work needed after files are loaded 270 * but before <code>handleCU</code> is called 271 * on each <code>CompilationUnit</code> to process them. 272 */ 273 public void preprocess() {} 274 275 /** 276 * Hook for any work needed after <code>handleCU</code> has been called 277 * on each <code>CompilationUnit</code> to process them. 278 */ 279 public void postprocess() {} 280 281 282 /** 283 * This method is called on each <code>CompilationUnit</code> 284 * that this tool processes. <p> 285 * 286 * The default implementation is simply to call 287 * <code>handleTD</code> on each <code>TypeDecl</code> present in 288 * cu. It is intended that subclassers override this method.<p> 289 */ 290 //@ requires cu != null; 291 public void handleCU(CompilationUnit cu) { 292 // Iterate over all the TypeDecls representing outside types in cu: 293 TypeDeclVec elems = cu.elems; 294 for (int i=0; i<elems.size(); i++) { 295 TypeDecl d = elems.elementAt(i); 296 297 handleTD(d); 298 } 299 } 300 301 302 /** 303 * This method is called on the TypeDecl of each 304 * outside type that SrcTool is to process. <p> 305 */ 306 //@ requires td != null; 307 public void handleTD(TypeDecl td) {} 308 309 }