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 if (sys == null) { 072 sys = 073 System.getProperty("java.home") 074 + java.io.File.separator 075 + "lib" 076 + java.io.File.separator 077 + "rt.jar"; 078 //System.out.println("SYS-JH " + sys); 079 } 080 081 if (sys != null && !sys.equals("")) { 082 if (!classPath.equals("")) { 083 classPath += System.getProperty("path.separator", ":"); 084 } 085 classPath += sys; 086 } 087 compositeSourcePath = sourcePath; 088 compositeClassPath = classPath; 089 } 090 091 public void setup() { 092 // javafe.util.Info.on = options.v; 093 setupPaths(); 094 Info.out("[Full classpath is " + compositeClassPath + "]"); 095 Info.out("[Full sourcepath is " + compositeSourcePath + "]"); 096 097 // It is ok if sourcePath is null; it then shares a database 098 // of the contents of the directory path with classpath, 099 // rather than creating a separate, identical database. 100 OutsideEnv.init( 101 makeStandardTypeReader( 102 compositeClassPath, 103 compositeSourcePath, 104 makePragmaParser())); 105 106 PrettyPrint.inst = makePrettyPrint(); 107 TypeCheck.inst = makeTypeCheck(); 108 } 109 110 /** 111 * Called to clear any static initializations, so that the parser 112 * can be called multiple times within one process. Called as 113 * part of construction of a new Main. 114 */ 115 public void clear(boolean complete) { 116 ErrorSet.clear(); 117 // FIXME LocationManagerCorrelatedReader.clear(); 118 OutsideEnv.clear(); 119 } 120 121 /** 122 * Called to obtain the {@link StandardTypeReader} to be used for 123 * locating and reading in types. 124 */ 125 //@ ensures \result != null; 126 public StandardTypeReader makeStandardTypeReader( 127 String path, 128 String sourcePath, 129 PragmaParser P) { 130 return StandardTypeReader.make(path, sourcePath, P); 131 } 132 133 /** 134 * Called to obtain the pragma parser to be used for parsing input 135 * files. If <code>null</code> is returned, then no pragma 136 * parsing is done. (By default, returns <code>null</code>). 137 */ 138 public PragmaParser makePragmaParser() { 139 return null; 140 } 141 142 /** 143 * Called to create a new {@link Options} object. 144 */ 145 //@ ensures \result != null; 146 public Options makeOptions() { 147 return new Options(); 148 } 149 150 /** Processes the options into the current Options instance as 151 * contained in the options field. 152 * @param args The command-line arguments to process 153 * @throws UsageError if the sequence of command-line arguments 154 * is invalid 155 */ 156 //@ requires args != null; 157 public void processOptions(String[] args) throws UsageError { 158 options.processOptions(args); 159 } 160 161 /** 162 * Called to obtain the pretty printer to set {@link 163 * PrettyPrint#inst} to. May not return <code>null</code>. By 164 * default, returns {@link javafe.ast.StandardPrettyPrint}. 165 */ 166 //@ ensures \result != null; 167 public PrettyPrint makePrettyPrint() { 168 return new StandardPrettyPrint(); 169 } 170 171 /** 172 * Called to obtain an instance of the {@link javafe.tc.TypeCheck} 173 * class (or a subclass thereof) to be used for typechecking. May 174 * not return <code>null</code>. By default, returns {@link 175 * javafe.tc.TypeCheck}. 176 */ 177 //@ ensures \result != null; 178 public TypeCheck makeTypeCheck() { 179 return new TypeCheck(); 180 } 181 182 /*************************************************** 183 * * 184 * Main processing code: * 185 * * 186 **************************************************/ 187 188 /** 189 * Start up an instance of this tool using command-line arguments 190 * <code>args</code>. 191 * 192 * <p> <strong>Note</strong>: this code needs to be copied 193 * verbatim to each subclass of {@link Tool} except with the name 194 * of the actual subclass inserted after the new operator and the 195 * comment characters (//) removed. </p> 196 * 197 * <p> (This needs to be done because static methods cannot be 198 * inherited.) </p> 199 */ 200 //@ requires \nonnullelements(args); 201 public static void main(String[] args) { 202 // Tool t = new FrontEndTool(); 203 // int result = t.run(args); 204 // if (result != 0) System.exit(result); 205 } 206 207 /** 208 * Parses the options into a new instance of an {@link Options} 209 * subclass. The new instance is assigned to the options field. 210 * If the argument is null, the tool is initialized with the 211 * existing options (the options field is unchanged). The tool 212 * is then initialized (by calling setup) with the designated options. 213 * 214 * @param args Either null or an array of arguments used to 215 * initialize the Options structure 216 * @return Returns -1 if arguments were parsed satisfactorily, 217 * otherwise returns the exit code with which to 218 * terminate the program 219 */ 220 221 //@ ensures args == null ==> \not_modified(options); 222 // FIXME //@ ensures args == null ==> \not_modified(options.* ); 223 public int handleOptions(String[] args) { 224 if (args != null) { 225 try { 226 // Handle all tool options: 227 options = makeOptions(); 228 processOptions(args); 229 if (options.issueUsage) { 230 usage(); 231 return okExitCode; 232 } 233 } catch (UsageError e) { 234 badOptionUsage(e); 235 ErrorSet.errors++; // Just so that the JUnit tests detect that 236 // an error message was issued 237 return badUsageExitCode; 238 } catch (FatalError e) { 239 Info.out("[" + name() + " exiting due to a fatal error]"); 240 } 241 } 242 // Setup the front end using the options: 243 setup(); 244 return -1; 245 } 246 247 /** 248 * A tool's main entry point, which should be overridden in derived classes 249 * to do the work of the tool. 250 * 251 * @param args The command-line arguments the program was invoked with 252 * @return The exit code for the program, with 0 indicating success 253 * @see javafe.Tool#run(java.lang.String[]) 254 */ 255 /*@ also public normal_behavior 256 @ requires args != null; 257 @ modifies \everything; 258 @*/ 259 public final int run(String[] args) { 260 int r = handleOptions(args); 261 if (r != -1) 262 return r; 263 264 if (ErrorSet.errors == 0) 265 try { 266 // Do our front-end-tool-specific processing: 267 frontEndToolProcessing(options.inputEntries); 268 } catch (FatalError e) { 269 Info.out("[" + name() + " exiting due to a fatal error]"); 270 } 271 272 if (ErrorSet.cautions != 0) 273 System.out.println( 274 ErrorSet.cautions 275 + " caution" 276 + (ErrorSet.cautions > 1 ? "s" : "")); 277 if (ErrorSet.warnings != 0) 278 System.out.println( 279 ErrorSet.warnings 280 + " warning" 281 + (ErrorSet.warnings > 1 ? "s" : "")); 282 if (ErrorSet.errors != 0) 283 System.out.println( 284 ErrorSet.errors + " error" + (ErrorSet.errors > 1 ? "s" : "")); 285 286 // If we call exit here, we will break GUI-based clients. 287 // Return error status to caller: 288 if (ErrorSet.errors > 0) 289 return errorExitCode; 290 else { 291 return okExitCode; 292 } 293 } 294 295 /** 296 * Perform any front-end-tool-specific processing. 297 * 298 * <p> The remaining arguments are <code>args[offset]</code>, 299 * <code>args[offset+1]</code>, ...</p> 300 */ 301 // requires \nonnullelements(args); 302 // requires 0 <= offset && offset <= args.length; 303 public abstract void frontEndToolProcessing(ArrayList args); 304 }