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 }