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 }