    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    }