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    }