    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package javafe;
    004
    005
    006    import java.util.Vector;
    007
    008    import javafe.ast.*;
    009    import javafe.tc.*;
    010    import javafe.util.*;
    011
    012    import java.io.BufferedReader;
    013    import java.io.FileReader;
    014    import java.io.*;
    015
    016    import java.util.StringTokenizer;
    017    import java.util.ArrayList;
    018    import java.util.Iterator;
    019
    020    public class CopyLoaded extends FrontEndTool implements Listener {
    021
    022        public String name() { return "CopyLoaded"; }
    023
    024        private PrintWriter libIndirectWriter;
    025        private PrintWriter progIndirectWriter;
    026
    027        /*
    028         * This maps files from original progIndirect file names to their names
    029         * relative to the outDir
    030         */
    031        public final Vector progIndirectFiles = new Vector();
    032        //+@ invariant progIndirectFiles.elementType == \type(String);
    033        //@  invariant progIndirectFiles.owner == this;
    034        //+@ invariant !progIndirectFiles.containsNull;
    035
    036        public final Vector argumentFileNames = new Vector();
    037        //+@ invariant argumentFileNames.elementType == \type(String);
    038        //+@ invariant !argumentFileNames.containsNull;
    039        //@  invariant argumentFileNames.owner == this;
    040
    041
    042
    043        /***************************************************
    044         *                                                 *
    045         * Keeping track of loaded CompilationUnits:       *
    046         *                                                 *
    047         **************************************************/
    048
    049
    050        //@  invariant loaded != null;
    051        //+@ invariant loaded.elementType == \type(CompilationUnit);
    052        //+@ invariant !loaded.containsNull;
    053        //@  invariant loaded.owner == this;
    054        public Vector loaded = new Vector();
    055
    056        //@ invariant loaded != argumentFileNames;
    057
    058        public CopyLoaded() {
    059            //+@ set argumentFileNames.elementType = \type(String);
    060            //+@ set argumentFileNames.containsNull = false;
    061            //@  set argumentFileNames.owner = this;
    062
    063            //+@ set loaded.elementType = \type(CompilationUnit);
    064            //+@ set loaded.containsNull = false;
    065            //@  set loaded.owner = this;
    066
    067            //+@ set progIndirectFiles.containsNull = false;
    068            //+@ set progIndirectFiles.elementType = \type(String);
    069            //@  set progIndirectFiles.owner = this;
    070        }
    071
    072
    073        public void setup() {
    074            super.setup();
    075        }
    076
    077
    078        private String packageDirForFile(/*@ non_null */ CompilationUnit cu) {
    079            Name pkg = cu.pkgName;
    080            String s = pkg == null ? "" : pkg.printName() + ".";
    081            s = s.replace('.', '/');
    082            return s;
    083        }
    084
    085        public void notify(CompilationUnit justLoaded) {
    086            loaded.addElement(justLoaded);
    087
    088            String fileName = Location.toFileName(justLoaded.loc);
    089            /* if a Java file, then copy the file over into outDir */
    090            if (fileName.endsWith(".java")) {
    091                copySourceFile(fileName,
    092                       packageDirForFile(justLoaded) + fileNameName(fileName));
    093            } else {
    094                TypeDeclVec elems = justLoaded.elems;
    095                /* generate a spec file for each type decl in compilation unit */
    096                for (int i=0; i<elems.size(); i++) {
    097                    TypeDecl d = elems.elementAt(i);
    098                    TypeSig sig = TypeCheck.inst.getSig(d);
    099                    if (d.specOnly || d.isBinary()) {
    100                        printSpec(sig.toString());
    101                    }
    102                }
    103            }
    104        }
    105
    106        /***************************************************
    107         *                                                 *
    108         * Main processing code:                   *
    109         *                                                 *
    110         **************************************************/
    111
    112
    113
    114        //@ requires \nonnullelements(args);
    115        public static void main(String[] args) {
    116            Tool t = new CopyLoaded();
    117            int result = t.run(args);
    118            if (result != 0) System.exit(result);
    119        }
    120
    121        public Options makeOptions() {
    122            return new CopyLoadedOptions();
    123        }
    124
    125        public CopyLoadedOptions options() {
    126            return (CopyLoadedOptions)options;
    127        }
    128
    129
    130
    131        //@ ensures \nonnullelements(\result);
    132        //@ ensures \result != null;
    133        public String[] FQNpackage(/*@ non_null */ String s) {
    134            StringTokenizer st = new StringTokenizer(s, ".", false);
    135            int len = st.countTokens();
    136            return fillArray(st, len-1);
    137        }
    138
    139        //@ ensures \result != null;
    140        public String FQNname(/*@ non_null */ String s) {
    141             return s.substring(s.lastIndexOf(".") + 1);
    142        }
    143
    144        //@ ensures \nonnullelements(\result);
    145        //@ ensures \result != null;
    146        public String[] fileNamePackage(/*@ non_null */ String file) {
    147            StringTokenizer st = new StringTokenizer(file, "/", false);
    148            int len = st.countTokens();
    149            return fillArray(st, len-1);
    150        }
    151
    152
    153        //@ ensures \result != null;
    154        public String fileNameName(/*@ non_null */ String s) {
    155             return s.substring(s.lastIndexOf("/") + 1);
    156        }
    157
    158        //@ ensures \nonnullelements(\result);
    159        //@ ensures \result != null;
    160        public String[] directoryPackage(/*@ non_null */ String dir) {
    161            StringTokenizer st = new StringTokenizer(dir, "/", false);
    162            int len = st.countTokens();
    163            return fillArray(st, len);
    164        }
    165
    166        //@ ensures \nonnullelements(\result);
    167        //@ ensures \result != null;
    168        private String[] fillArray(/*@ non_null */ StringTokenizer st, int len) {
    169            if (len < 0) {
    170                return new String[0];
    171            }
    172            String array[] = new String[len];
    173            for (int i = 0; i < len; i++) {
    174                array[i] = st.nextToken();
    175            }
    176            return array;
    177        }
    178
    179        //@ requires \nonnullelements(P);
    180        private String makeDirTree(/*@ non_null */ String root,
    181                                   /*@ non_null */ String P[]) {
    182            String s = root;
    183            for (int i = 0; i < P.length; i++) {
    184                s = s + "/" + P[i];
    185                File f = new File(s);
    186                if (!f.exists()) {
    187                    System.out.println("[making " + s + "]");
    188                    f.mkdir();
    189                } else {
    190                }
    191            }
    192            return s;
    193        }
    194
    195        //@ requires \nonnullelements(P);
    196        //@ ensures \result != null;
    197        private String makeDirPath(/*@ non_null */ String P[]) {
    198            String s = "";
    199            for (int i = 0; i < P.length; i++) {
    200                s = s + P[i] +"/";
    201            }
    202            return s;
    203        }
    204
    205        /**
    206         * Prints the spec file for the FQN s.  The file is written
    207         * relative to the outDir.
    208         */
    209        public void printSpec(/*@ non_null */ String s) {
    210            String P[] = FQNpackage(s);
    211            String T = FQNname(s);
    212            TypeSig sig = OutsideEnv.lookup(P, T);
    213            Assert.notFalse(sig != null); //@ nowarn Pre;
    214
    215            String path = makeDirTree(options().outDir, P);
    216            String outFile = T + ".spec";
    217            String filename = path + "/" +  outFile;
    218
    219            System.out.println("[generating spec file for " + s +
    220                               " as " + filename + "]");
    221
    222            //@ assume libIndirectWriter != null;
    223            libIndirectWriter.println("./" + makeDirPath(P) + outFile);
    224
    225            try {
    226                FileOutputStream fos = null;
    227                try {
    228                    fos = new FileOutputStream(filename);
    229                    PrettyPrint.inst.print(fos, sig.getCompilationUnit());
    230                } finally {
    231                    if (fos != null) fos.close();
    232                }
    233            } catch (Exception e) {
    234                ErrorSet.fatal(e.getMessage());
    235            }
    236        }
    237
    238        public final void frontEndToolProcessing(ArrayList args) {
    239            /*
    240             * At this point, all options have already been processed and
    241             * the front end has been initialized.
    242             */
    243
    244            String outDir = options().outDir;
    245            String outProgIndirect = options().outProgIndirect;
    246            String outLibIndirect = options().outLibIndirect;
    247
    248            System.out.println("[outdir is " + outDir + "]");
    249
    250            // Set up to receive CompilationUnit-loading notification events:
    251            OutsideEnv.setListener(this);
    252
    253            // create the outDir
    254            if (outDir.startsWith(".")) {
    255                makeDirTree(".", directoryPackage(outDir));
    256            } else {
    257                makeDirTree("", directoryPackage(outDir));
    258            }
    259
    260            // set up the indirection files.
    261            try {
    262                progIndirectWriter =
    263                  new PrintWriter(new FileWriter(new File(outProgIndirect)));
    264                libIndirectWriter =
    265                  new PrintWriter(new FileWriter(new File(outLibIndirect)));
    266            } catch (IOException e) {
    267                ErrorSet.fatal(e.getMessage());
    268            }
    269
    270            /*
    271             * Load in each source file:
    272             */
    273            Iterator i = args.iterator();
    274            while (i.hasNext()) OutsideEnv.addSource((String)i.next());
    275
    276             /* load in source files from supplied file name */
    277            i = argumentFileNames.iterator();
    278            while (i.hasNext()) {
    279                String argumentFileName = (String)i.next();
    280                try {
    281                        BufferedReader in = null;
    282                    try {
    283                        in = new BufferedReader(
    284                                new FileReader(argumentFileName));
    285                        String s;
    286                        while ((s = in.readLine()) != null) {
    287                            // allow blank lines in files list
    288                            if (!s.equals("")) {
    289                                progIndirectFiles.addElement(s);
    290                                OutsideEnv.addSource(s);
    291                            }
    292                        }
    293                    } finally {
    294                        if (in != null) in.close();
    295                    }
    296                } catch (IOException e) {
    297                    ErrorSet.fatal(e.getMessage());
    298                }
    299            }
    300
    301            i = loaded.iterator();
    302            while (i.hasNext()) {
    303                handleCU((CompilationUnit)i.next());
    304            }
    305
    306            progIndirectWriter.close();
    307            libIndirectWriter.close();
    308        }
    309
    310
    311        /**
    312         * Copy the source file original into the file newName.  newName
    313         * is appended to the outDir to construct the full file location
    314         * of the new file.  This method also puts the newName into the
    315         * correct indirection file.
    316         */
    317        private void copySourceFile(/*@ non_null */ String original,
    318                    /*@ non_null */ String newName) {
    319            try {
    320                String path = makeDirTree(options().outDir, fileNamePackage(newName));
    321                String newFileName = path + "/" + fileNameName(newName);
    322
    323                System.out.println("[copying source file " + original +
    324                           " to " + newFileName + "]");
    325
    326                //@ assume libIndirectWriter != null;
    327                //@ assume progIndirectWriter != null;
    328                if (progIndirectFiles.contains(original)) {
    329                    progIndirectWriter.println("./" + newName);
    330                } else {
    331                    libIndirectWriter.println("./" + newName);
    332                }
    333
    334                File f = new File(newFileName);
    335                BufferedReader reader = null;
    336                PrintWriter writer = null;
    337                try {
    338                    reader = new BufferedReader(new FileReader(original));
    339                    try {
    340                        writer = new PrintWriter(new FileWriter(f));
    341                        String s;
    342                        while ((s = reader.readLine()) != null) {
    343                            writer.println(s);
    344                        }
    345                    } finally {
    346                        if (writer != null) writer.close();
    347                    }
    348                } finally {
    349                    if (reader != null) reader.close();
    350                }
    351            } catch (IOException e) {
    352                ErrorSet.fatal(e.getMessage());
    353            }
    354        }
    355
    356
    357        /**
    358         * Process each CU's type decls.
    359         */
    360        public void handleCU(/*@ non_null */ CompilationUnit cu) {
    361            // Iterate over all the TypeDecls representing outside types in cu:
    362            TypeDeclVec elems = cu.elems;
    363            for (int i=0; i<elems.size(); i++) {
    364                TypeDecl d = elems.elementAt(i);
    365                handleTD(d);
    366            }
    367        }
    368
    369        /**
    370         * Called from handleCU on each TypeDecl from the CU's loaded from the
    371         * program files.  In addition, it calls itself recursively to handle types
    372         * nested within outside types.<p>
    373         */
    374        public void handleTD(/*@ non_null */ TypeDecl td) {
    375            TypeSig sig = TypeCheck.inst.getSig(td);
    376            if (sig.getTypeDecl().specOnly)    // do not process specs
    377                return;
    378
    379            System.out.println("\n" + sig.toString() + " ...");
    380
    381                        // Do actual work:
    382            boolean aborted = processTD(td);
    383
    384            TypeDecl decl = sig.getTypeDecl();
    385            for (int i=0; i<decl.elems.size(); i++) {
    386                if (decl.elems.elementAt(i) instanceof TypeDecl)
    387                handleTD((TypeDecl)decl.elems.elementAt(i)); //@ nowarn Cast;
    388            }
    389        }
    390
    391
    392        /**
    393         * Typecheck a TypeDecl;
    394         * return true if we had to abort. <p>
    395         *
    396         * Precondition: td is not from a binary file.<p>
    397         */
    398        private boolean processTD(/*@ non_null */ TypeDecl td) {
    399            int errorCount = ErrorSet.errors;
    400            TypeSig sig = TypeCheck.inst.getSig(td);
    401            sig.typecheck();
    402
    403            return false;
    404        }
    405
    406
    407    }
    408
    409    class CopyLoadedOptions extends SrcToolOptions {
    410
    411        /*@ non_null */ public String outDir = "./outdir/src-annotated";
    412        /*@ non_null */ public String outProgIndirect = "./outProgIndirect";
    413        /*@ non_null */ public String outLibIndirect = "./outLibIndirect";
    414
    415
    416        public String showNonOptions() {
    417            return ("<program indirection file>");
    418        }
    419
    420        public String showOptions(boolean all) {
    421            StringBuffer sb = new StringBuffer(super.showOptions(all));
    422            sb.append("  -outdir <root of output files>"); sb.append(eol);
    423            sb.append("  -outProgIndirect <new prog Indirect file>");sb.append(eol);
    424            sb.append("  -outLibIndirect <new lib Indirect file>"); sb.append(eol);
    425            sb.append("  -f <file containing source file names>"); sb.append(eol);
    426            return sb.toString();
    427        }
    428
    429
    430        /***************************************************
    431         *                                                 *
    432         * Option processing:                   *
    433         *                                                 *
    434         **************************************************/
    435
    436        //private final String name = "CopyLoaded";
    437
    438        public int processOption(String option, String[] args, int offset)
    439                                            throws UsageError {
    440            if (option.equals("-outProgIndirect")) {
    441                if (offset>=args.length) {
    442                    throw new UsageError("Option " + option +
    443                                             " requires one argument");
    444                }
    445                outProgIndirect = args[offset];
    446                return offset + 1;
    447            } else if (option.equals("-outLibIndirect")) {
    448                if (offset>=args.length) {
    449                    throw new UsageError("Option " + option +
    450                                             " requires one argument");
    451                }
    452                outLibIndirect = args[offset];
    453                return offset + 1;
    454            } else if (option.equals("-outdir")) {
    455                if (offset>=args.length) {
    456                    throw new UsageError("Option " + option +
    457                                             " requires one argument");
    458                }
    459                outDir = args[offset];
    460                return offset + 1;
    461            } else {
    462                // Pass on unrecognized options:
    463                return super.processOption(option, args, offset);
    464            }
    465        }
    466    }