001 /* Copyright 2000, 2001, Compaq Computer Corporation */
002
003 package javafe;
004
005 import javafe.ast.PrettyPrint;
006 import javafe.ast.StandardPrettyPrint;
007
008 import javafe.reader.StandardTypeReader;
009 import javafe.parser.PragmaParser;
010
011 import javafe.tc.OutsideEnv;
012 import javafe.tc.TypeCheck;
013
014 import javafe.util.*;
015
016 import java.util.ArrayList;
017
018 /**
019 * <code>FrontEndTool</code> is an abstract class for tools that use
020 * our Java front end.
021 *
022 * <p> It handles parsing the standard options for setting up the
023 * front end and initializing the front end using those options. At
024 * the end of a run, it prints a count of how many cautions, warnings,
025 * and errors occurred (cf. <code>ErrorSet</code>). It also handles
026 * catching <code>FatalError</code>s (see
027 * <code>ErrorSet.fatal</code>). The remaining processing, if any, is
028 * front-end-tool specific. </p>
029 */
030
031 public abstract class FrontEndTool extends Tool
032 {
033 /***************************************************
034 * *
035 * Standard front-end setup: *
036 * *
037 **************************************************/
038
039 /**
040 * Setup: initialize the front end using the standard
041 * front-end-tool option variables ({@link Options#userPath},
042 * {@link Options#sysPath}).
043 *
044 * <p> This can be done only once. The standard front-end-tool
045 * option variables have no effect after this point. May exit
046 * with an error (via {@link ErrorSet#fatal(String)}). </p>
047 *
048 * <p> Ensures {@link OutsideEnv} has been properly initialized
049 * (except if an error occurs). </p>
050 *
051 * <p> Also initializes {@link PrettyPrint#inst} and {@link
052 * TypeCheck#inst} to their default front end values. </p>
053 */
054 protected String compositeSourcePath;
055 protected String compositeClassPath;
056
057 public void setupPaths() {
058 String classPath = options.userPath;
059 if (classPath == null)
060 // The behavior of this code differs between 1.1 and 1.2:
061 classPath = javafe.filespace.ClassPath.current();
062
063 String sourcePath = options.userSourcePath;
064
065 String sys = options.sysPath;
066 if (sys == null) {
067 // This works only on Sun implementations of Java...
068 sys = System.getProperty("sun.boot.class.path", null);
069 //System.out.println("SYS-SUN " + sys);
070 }
071 Info.out("sysPath: " + sys);
072 if (sys == null) {
073 sys =
074 System.getProperty("java.home")
075 + java.io.File.separator
076 + "lib"
077 + java.io.File.separator
078 + "rt.jar";
079 //System.out.println("SYS-JH " + sys);
080 }
081
082 // TODO: does this work if classPath is empty
083 Info.out("sysPath: " + sys);
084 if (sys != null && !sys.equals("")) {
085 if (!classPath.equals("")) {
086 classPath += java.io.File.pathSeparator;
087 }
088 classPath += sys;
089 }
090 compositeSourcePath = sourcePath;
091 compositeClassPath = classPath;
092 }
093
094 public void setup() {
095 // javafe.util.Info.on = options.v;
096 setupPaths();
097 Info.out("[Full classpath is " + compositeClassPath + "]");
098 Info.out("[Full sourcepath is " + compositeSourcePath + "]");
099
100 // It is ok if sourcePath is null; it then shares a database
101 // of the contents of the directory path with classpath,
102 // rather than creating a separate, identical database.
103 OutsideEnv.init(
104 makeStandardTypeReader(
105 compositeClassPath,
106 compositeSourcePath,
107 makePragmaParser()));
108
109 PrettyPrint.inst = makePrettyPrint();
110 TypeCheck.inst = makeTypeCheck();
111 }
112
113 /**
114 * Called to clear any static initializations, so that the parser
115 * can be called multiple times within one process. Called as
116 * part of construction of a new Main.
117 */
118 public void clear(boolean complete) {
119 ErrorSet.clear();
120 // FIXME LocationManagerCorrelatedReader.clear();
121 OutsideEnv.clear();
122 }
123
124 /**
125 * Called to obtain the {@link StandardTypeReader} to be used for
126 * locating and reading in types.
127 */
128 //@ ensures \result != null;
129 public StandardTypeReader makeStandardTypeReader(
130 String path,
131 String sourcePath,
132 PragmaParser P) {
133 return StandardTypeReader.make(path, sourcePath, P);
134 }
135
136 /**
137 * Called to obtain the pragma parser to be used for parsing input
138 * files. If <code>null</code> is returned, then no pragma
139 * parsing is done. (By default, returns <code>null</code>).
140 */
141 public PragmaParser makePragmaParser() {
142 return null;
143 }
144
145 /**
146 * Called to create a new {@link Options} object.
147 */
148 //@ ensures \result != null;
149 public Options makeOptions() {
150 return new Options();
151 }
152
153 /** Processes the options into the current Options instance as
154 * contained in the options field.
155 * @param args The command-line arguments to process
156 * @throws UsageError if the sequence of command-line arguments
157 * is invalid
158 */
159 //@ requires args != null;
160 public void processOptions(String[] args) throws UsageError {
161 options.processOptions(args);
162 }
163
164 /**
165 * Called to obtain the pretty printer to set {@link
166 * PrettyPrint#inst} to. May not return <code>null</code>. By
167 * default, returns {@link javafe.ast.StandardPrettyPrint}.
168 */
169 //@ ensures \result != null;
170 public PrettyPrint makePrettyPrint() {
171 return new StandardPrettyPrint();
172 }
173
174 /**
175 * Called to obtain an instance of the {@link javafe.tc.TypeCheck}
176 * class (or a subclass thereof) to be used for typechecking. May
177 * not return <code>null</code>. By default, returns {@link
178 * javafe.tc.TypeCheck}.
179 */
180 //@ ensures \result != null;
181 public TypeCheck makeTypeCheck() {
182 return new TypeCheck();
183 }
184
185 /***************************************************
186 * *
187 * Main processing code: *
188 * *
189 **************************************************/
190
191 /**
192 * Start up an instance of this tool using command-line arguments
193 * <code>args</code>.
194 *
195 * <p> <strong>Note</strong>: this code needs to be copied
196 * verbatim to each subclass of {@link Tool} except with the name
197 * of the actual subclass inserted after the new operator and the
198 * comment characters (//) removed. </p>
199 *
200 * <p> (This needs to be done because static methods cannot be
201 * inherited.) </p>
202 */
203 //@ requires \nonnullelements(args);
204 public static void main(String[] args) {
205 // Tool t = new FrontEndTool();
206 // int result = t.run(args);
207 // if (result != 0) System.exit(result);
208 }
209
210 /**
211 * Parses the options into a new instance of an {@link Options}
212 * subclass. The new instance is assigned to the options field.
213 * If the argument is null, the tool is initialized with the
214 * existing options (the options field is unchanged). The tool
215 * is then initialized (by calling setup) with the designated options.
216 *
217 * @param args Either null or an array of arguments used to
218 * initialize the Options structure
219 * @return Returns -1 if arguments were parsed satisfactorily,
220 * otherwise returns the exit code with which to
221 * terminate the program
222 */
223
224 //@ ensures args == null ==> \not_modified(options);
225 // FIXME //@ ensures args == null ==> \not_modified(options.* );
226 public int handleOptions(String[] args) {
227 if (args != null) {
228 try {
229 // Handle all tool options:
230 options = makeOptions();
231 processOptions(args);
232 if (options.issueUsage) {
233 usage();
234 return okExitCode;
235 }
236 } catch (UsageError e) {
237 badOptionUsage(e);
238 ErrorSet.errors++; // Just so that the JUnit tests detect that
239 // an error message was issued
240 return badUsageExitCode;
241 } catch (FatalError e) {
242 Info.out("[" + name() + " exiting due to a fatal error]");
243 }
244 }
245 // Setup the front end using the options:
246 setup();
247 return -1;
248 }
249
250 /**
251 * A tool's main entry point, which should be overridden in derived classes
252 * to do the work of the tool.
253 *
254 * @param args The command-line arguments the program was invoked with
255 * @return The exit code for the program, with 0 indicating success
256 * @see javafe.Tool#run(java.lang.String[])
257 */
258 /*@ also public normal_behavior
259 @ requires args != null;
260 @ modifies \everything;
261 @*/
262 public final int run(String[] args) {
263 int r = handleOptions(args);
264 if (r != -1)
265 return r;
266
267 if (ErrorSet.errors == 0)
268 try {
269 // Do our front-end-tool-specific processing:
270 frontEndToolProcessing(options.inputEntries);
271 } catch (FatalError e) {
272 Info.out("[" + name() + " exiting due to a fatal error]");
273 }
274
275 if (ErrorSet.cautions != 0)
276 System.out.println(
277 ErrorSet.cautions
278 + " caution"
279 + (ErrorSet.cautions > 1 ? "s" : ""));
280 if (ErrorSet.warnings != 0)
281 System.out.println(
282 ErrorSet.warnings
283 + " warning"
284 + (ErrorSet.warnings > 1 ? "s" : ""));
285 if (ErrorSet.errors != 0)
286 System.out.println(
287 ErrorSet.errors + " error" + (ErrorSet.errors > 1 ? "s" : ""));
288
289 // If we call exit here, we will break GUI-based clients.
290 // Return error status to caller:
291 if (ErrorSet.errors > 0)
292 return errorExitCode;
293 else {
294 return okExitCode;
295 }
296 }
297
298 /**
299 * Perform any front-end-tool-specific processing.
300 *
301 * <p> The remaining arguments are <code>args[offset]</code>,
302 * <code>args[offset+1]</code>, ...</p>
303 */
304 // requires \nonnullelements(args);
305 // requires 0 <= offset && offset <= args.length;
306 public abstract void frontEndToolProcessing(ArrayList args);
307 }