// modules.beh -- modules that can be run by the Demeter/Java front end. // $Id: modules.beh,v 1.30 2002/01/05 13:55:10 dougo Exp $ Modules { /** Find the module with the given name. */ Module findModule(String name) to Module { before Module (@ if (name.equals(host.toString())) return_val = host; @) } /** A formatted list of descriptions of the modules. */ String descriptions() to * { (@ String s = ""; @) before Module (@ String name = host.toString(); s += " " + name; for (int i = 16 - name.length(); i > 0; i--) s += " "; @) after New (@ s += "Start a new project."; @) after Studio (@ s += "Run the GUI design program."; @) after Generate (@ s += "Process the CD and BEH aspects."; @) after Cool (@ s += "Process the COOL coordination aspect."; @) after Ridl (@ s += "Process the RIDL remote aspect."; @) after Weave (@ s += "Weave the aspects into Java code."; @) after ParseGen (@ s += "Generate parser Java code from the grammar."; @) after Compile (@ s += "Compile the Java code into bytecodes."; @) after Test (@ s += "Test the compiled program."; @) after Clean (@ s += "Remove all generated files."; @) after FindJavaFiles (@ s += "Find java files in specified directories."; @) after Module (@ s += Line.nl; @) return (@ s @) } } Module { /** Print the usage info for this module. */ void printUsage() (@ Stream.err.println("Usage: demeterj " + this + " " + argumentUsage()); @) /** A usage string summarizing the arguments available for this module. */ String argumentUsage() (@ return ""; @) /** Read the project file, if it exists. Return null on error. */ Project getProject(ProjectName projectName) (@ if (projectName == null) { // Look for a file with the project file extension. File cwd = Utils.getcwd(); String projfiles[] = cwd.list(new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(Project.fileExtension); } }); if (projfiles.length == 0) { // None found, use the default. return Project.parse("program"); } if (projfiles.length > 1) { // More than one found, ask the user to specify one. Stream.err.println("Please specify a project name."); return null; } String name = projfiles[0]; name = name.substring(0, name.lastIndexOf(".")); projectName = ProjectName.parse(name); } File projectFile = projectName.file(); Project project = null; Stream.out.println("Reading project file " + projectFile + "..."); try { project = new Project(projectName, ProjectFile.parse(Utils.makeInputStream(projectFile))); } catch (ParseException e) { Stream.err.println(e); } catch (IOException e) { } return project; @) /** Run the module with the given args. Return true iff successful. */ abstract Object run(Project project, Arguments args); /** Destructively add to args any arguments specified in the project file. */ void addModuleArgs(Project project, Arguments args) (@ Enumeration proj_args = project.getModuleArgs(this); if (proj_args != null) { while (proj_args.hasMoreElements()) { args.addElement(proj_args.nextElement()); } } @) } New { String argumentUsage() (@ return "[ projname ] [ " + Main.optionPrefix + "nosamplefiles ]" + " [ " + Main.optionPrefix + "noinput ]"; @) /** There is no project file yet... */ Project getProject(ProjectName projectName) (@ if (projectName == null) return Project.parse("program"); return Project.parse(projectName + ""); @) /** Make a new project file. */ Object run(Project project, Arguments args) (@ boolean makeSampleFiles = true, makeInput = true; Enumeration e = args.elements(); while (e.hasMoreElements()) { String arg = e.nextElement().toString(); if (Main.matchOption(arg, "help")) { printUsage(); return null; } else if (Main.matchOption(arg, "nosamplefiles")) { makeSampleFiles = false; } else if (Main.matchOption(arg, "noinput")) { makeInput = false; } else { // Use the argument as the new project name. project = Project.parse(arg); } } File projfile = project.file(); Stream.out.println("Making new project file " + projfile + "..."); if (projfile.exists()) projfile.renameTo(new File(projfile + "~")); PrintWriter out = Utils.makePrintWriter(projfile); project.printSampleFile(out, makeInput); out.close(); if (makeSampleFiles) { ProjectName name = project.get_name(); // Create the other files, but don't overwrite files that already exist. File cdfile = new File(name + ".cd"); if (!cdfile.exists()) { Stream.out.println("Making sample class dictionary file " + cdfile + "..."); out = Utils.makePrintWriter(cdfile); out.println("Main = String."); out.close(); } File behfile = new File(name + ".beh"); if (!behfile.exists()) { Stream.out.println("Making sample behavior file " + behfile + "..."); out = Utils.makePrintWriter(behfile); String nl = Line.nl; out.println( "Main {" +nl +" public static void main(String args[]) throws Exception " + Text.begin +nl +" Main m = parse(" + (makeInput ? "System.in" : "\"\\\"It works!\\\"\"") + ");" +nl +" System.out.println(m.get_s());" +nl +" " + Text.end +nl +"}" ); out.close(); } if (makeInput) { File inputfile = new File(name + ".input"); if (!inputfile.exists()) { Stream.out.println("Making sample input file " + inputfile + "..."); out = Utils.makePrintWriter(inputfile); out.println("\"It works!\""); out.close(); } } } return Boolean.TRUE; @) } Studio { /** Run AP Studio. */ Object run(Project project, Arguments args) (@ addModuleArgs(project, args); Stream.out.println("Running AP Studio..."); edu.neu.ccs.demeter.tools.apstudio.graphedit.Example.main(args.toStringArray()); // The GUI has started in another thread, but if we return we'll // System.exit(). So just commit seppuku... Thread.currentThread().stop(); return Boolean.TRUE; @) } Cool { /** Run cool on the specified cool file(s). Return a vector of weaver files (empty if none, null if error). */ Object run(Project project, Arguments args) (@ addModuleArgs(project, args); File gendir = project.getGenDir(); File filelist = new File(gendir, "coolfiles"); long time = filelist.lastModified(); Vector weaverfiles = null; // Backwards compatibility: assume the user has specified all the // arguments already, so don't add any. if (!Main.compat) { args.addElement("-outputdir"); args.addElement(gendir); boolean doit = false; Enumeration coolfiles = project.getCoolFiles(); while (coolfiles.hasMoreElements()) { File coolfile = (File) coolfiles.nextElement(); args.addElement(coolfile); if (coolfile.lastModified() > time) doit = true; } if (!doit) { // Read the old list of weaver files. try { weaverfiles = (Vector) (new ObjectInputStream(new FileInputStream(filelist))) .readObject(); } catch (IOException e) { weaverfiles = new Vector(); } catch (ClassNotFoundException e) { throw new RuntimeException(e.toString()); } return weaverfiles; } } Stream.out.println("Running cool..."); Stream.verbose.println("Args = " + args); try { weaverfiles = (Vector) edu.neu.ccs.demeter.tools.cool.Cool.cool(args.toStringArray()); } catch (edu.neu.ccs.demeter.tools.cool.ParseException e) { Stream.err.println(e); } if (weaverfiles != null) try { (new ObjectOutputStream(new FileOutputStream(filelist))) .writeObject(weaverfiles); } catch (IOException e) { throw new RuntimeException(e.toString()); } return weaverfiles; @) } Ridl { /** Run ridl on the specified ridl file(s). Return a vector of weaver files (empty if none, null if error). */ Object run(Project project, Arguments args) (@ addModuleArgs(project, args); File gendir = project.getGenDir(); File filelist = new File(gendir, "ridlfiles"); long time = filelist.lastModified(); Vector weaverfiles = null; // Backwards compatibility: assume the user has specified all the // arguments already, so don't add any. if (!Main.compat) { args.addElement("-outputdir"); args.addElement(gendir); boolean doit = false; File cdfile = project.getCDFile(); args.addElement(cdfile); Enumeration ridlfiles = project.getRidlFiles(); if (ridlfiles.hasMoreElements()) { while (ridlfiles.hasMoreElements()) { File ridlfile = (File) ridlfiles.nextElement(); args.addElement(ridlfile); if (ridlfile.lastModified() > time) doit = true; } if (cdfile.lastModified() > time) doit = true; } if (!doit) { // Read the old list of weaver files. try { weaverfiles = (Vector) (new ObjectInputStream(new FileInputStream(filelist))) .readObject(); } catch (IOException e) { weaverfiles = new Vector(); } catch (ClassNotFoundException e) { throw new RuntimeException(e.toString()); } return weaverfiles; } } Stream.out.println("Running ridl..."); Stream.verbose.println("Args = " + args); weaverfiles = (Vector) edu.neu.ccs.demeter.tools.ridler.RIDL.main(args.toStringArray()); if (weaverfiles != null) try { (new ObjectOutputStream(new FileOutputStream(filelist))) .writeObject(weaverfiles); } catch (IOException e) { throw new RuntimeException(e.toString()); } return weaverfiles; @) } Generate { /** Pass the arguments along to the generate package. Return a vector of weaver files (empty if none, null if error). */ Object run(Project project, Arguments args) (@ addModuleArgs(project, args); File gendir = project.getGenDir(); File filelist = new File(gendir, "weaverfiles"); long time = filelist.lastModified(); Vector weaverfiles = null; // Backwards compatibility: assume the user has specified all the // arguments already, so don't add any. if (!Main.compat) { args.addElement("-grammar"); String parsegen_name = new File(project.getParseGen()).getName(); if (parsegen_name.indexOf("javacc") != -1) { args.addElement("-javacc"); } else if (parsegen_name.indexOf("mparse") != -1) { args.addElement("-mparse"); } args.addElement("-weaver"); args.addElement("-outputdir"); args.addElement(gendir); boolean doit = false; File cdfile = project.getCDFile(); args.addElement(cdfile); if (cdfile.lastModified() > time) doit = true; Enumeration behfiles = project.getBehFiles(); while (behfiles.hasMoreElements()) { File behfile = (File) behfiles.nextElement(); args.addElement(behfile); if (behfile.lastModified() > time) doit = true; } if (!doit) { // Read the old list of weaver files. try { weaverfiles = (Vector) (new ObjectInputStream(new FileInputStream(filelist))) .readObject(); } catch (IOException e) { weaverfiles = new Vector(); } catch (ClassNotFoundException e) { throw new RuntimeException(e.toString()); } return weaverfiles; } } Stream.out.println("Running the generator..."); Stream.verbose.println("Args = " + args); weaverfiles = (Vector) edu.neu.ccs.demeter.tools.generate.Main.main(args.toStringArray()); if (weaverfiles != null) try { (new ObjectOutputStream(new FileOutputStream(filelist))) .writeObject(weaverfiles); } catch (IOException e) { throw new RuntimeException(e.toString()); } return weaverfiles; @) } Weave { /** Run the weaver, returning a vector of files generated, or null on error. */ Object run(Project project, Arguments args) (@ Vector weaverfiles = (Vector) new Generate().run(project, new Arguments()); if (weaverfiles == null) return null; Vector coolweaverfiles = (Vector) new Cool().run(project, new Arguments()); if (coolweaverfiles == null) return null; Vector ridlweaverfiles = (Vector) new Ridl().run(project, new Arguments()); if (ridlweaverfiles == null) return null; // Argh, why didn't they define append? Enumeration cools = coolweaverfiles.elements(); while (cools.hasMoreElements()) weaverfiles.addElement(cools.nextElement()); Enumeration ridls = ridlweaverfiles.elements(); while (ridls.hasMoreElements()) weaverfiles.addElement(ridls.nextElement()); // if (weaverfiles.size() == 0) return null; addModuleArgs(project, args); args.addElement("-outputdir"); File gendir = project.getGenDir(); args.addElement(gendir); File filelist = new File(gendir, "javafiles"); long time = filelist.lastModified(); Vector javafiles = null; boolean doit = false; Enumeration f = weaverfiles.elements(); while (f.hasMoreElements()) { File weaverfile = (File) f.nextElement(); args.addElement(weaverfile); if (weaverfile.lastModified() > time) doit = true; } if (!doit) { // Read the old list of java files. try { javafiles = (Vector) (new ObjectInputStream(new FileInputStream(filelist))) .readObject(); } catch (IOException e) { } catch (ClassNotFoundException e) { throw new RuntimeException(e.toString()); } return javafiles; } Stream.out.println("Running the weaver..."); Stream.verbose.println("Args = " + args); try { Stream.debug.println("Building..."); javafiles = edu.neu.ccs.demeter.tools.weave.Weaver.weave(args.toStringArray()); Stream.debug.println("Generating..."); edu.neu.ccs.demeter.tools.weave.Weaver.generate(); } catch (edu.neu.ccs.demeter.tools.weave.ParseException e) { Stream.err.println(e); } if (javafiles != null) try { (new ObjectOutputStream(new FileOutputStream(filelist))) .writeObject(javafiles); } catch (IOException e) { throw new RuntimeException(e.toString()); } return javafiles; @) } ParseGen { /** Run the parser generator, returning a vector of files generated, or null on error. */ Object run(Project project, Arguments args) (@ if (new Generate().run(project, new Arguments()) == null) return null; addModuleArgs(project, args); final int JAVACC = 0, MPARSE = 1; int parsegen = MPARSE; String parsegen_path = project.getParseGen(); String parsegen_name = new File(parsegen_path).getName(); if (parsegen_name.indexOf("javacc") != -1) { parsegen = JAVACC; } else if (parsegen_name.indexOf("mparse") != -1) { parsegen = MPARSE; } File gendir = project.getGenDir(); if (parsegen == JAVACC) { args.addElement("-OUTPUT_DIRECTORY:" + gendir); } File grammar = new File(gendir, "Parser.jj"); args.addElement(grammar); File parser = new File(gendir, "Parser.java"); Vector files = new Vector(); files.addElement(parser); if (parsegen == JAVACC) { // Probably shouldn't be hardcoded, but there's no real api for // getting the list of generated files from JavaCC. String filenames[] = { "ASCII_UCodeESC_CharStream.java", "ParseException.java", "Token.java", "TokenMgrError.java", "ParserConstants.java", "ParserTokenManager.java", "JavaCharStream.java", }; for (int i = 0; i < filenames.length; i++) { files.addElement(new File(gendir, filenames[i])); } } if (grammar.lastModified() <= parser.lastModified()) { return files; } String cmdarray[] = new String[args.size() + 1]; cmdarray[0] = parsegen_path; System.arraycopy(args.toStringArray(), 0, cmdarray, 1, args.size()); Stream.out.println("Running the parser generator..."); Stream.verbose.println(cmdarray[0] + " " + args); int retval; try { retval = Utils.exec(cmdarray); } catch (Exception e) { Stream.err.println(e); return null; } if (retval != 0) { Stream.out.println("Aborting, parser generator exited with error value " + retval + "."); return null; } return files; @) } FindJavaFiles { /** Find the files by recursively descending the directory */ Object run(Project project, Arguments args) {{ Vector ret = new Vector(); Enumeration dirs = project.getJavaFileDirs(); while (dirs.hasMoreElements()) { File dirfile = (File)dirs.nextElement(); if (dirfile.isDirectory()) { searchDir(dirfile,ret); } else { System.err.println(dirfile+" is not a directory"); return null; } } return ret; }} /** the bruntwork of recursing is done here */ void searchDir(File dir, Vector found) {{ File[] files = dir.listFiles(); for (int i=0; i classfile.lastModified()) { Stream.debug.println(javafile + " is newer than " + classfile); args.addElement(javafile); doit = true; } } // we deal with the found java files somewhat differently than both // the user specified ones and generated; they are stored in package director // structure, so we need to find the location of the classfile using // their full path. enum = foundjavafiles.elements(); while (enum.hasMoreElements()) { File javafile = (File)enum.nextElement(); String jfname = javafile.toString(); File classfile = new File(classdir, jfname.substring(0, jfname.length() - 4) + "class"); if (javafile.lastModified() > classfile.lastModified()) { Stream.debug.println(javafile + " is newer than " + classfile); args.addElement(javafile); doit = true; } } if (!doit) return Boolean.TRUE; File gendir = project.getGenDir(); String cpadditions = project.getClassPath(); String classpath = classdir + File.pathSeparator + gendir + File.pathSeparator + cpadditions + System.getProperty("java.class.path"); String cmdarray[] = new String[args.size() + 3]; cmdarray[0] = project.getCompiler(); cmdarray[1] = project.getClasspathOption(); cmdarray[2] = classpath; System.arraycopy(args.toStringArray(), 0, cmdarray, 3, args.size()); Stream.out.println("Running the compiler..."); for (int i = 0; i < cmdarray.length; i++) Stream.verbose.print(cmdarray[i] + " "); Stream.verbose.println(); try { int retval = Utils.exec(cmdarray); if (retval != 0) { System.out.println("Aborting, compiler exited with error value " + retval + "."); return null; } } catch (Exception e) { Stream.err.println(e); e.printStackTrace(Stream.verbose); return null; } /* This doesn't work. The jar tool depends on the class directory hierarchy being rooted at the current directory, and there's no way to change the current directory in Java. (!) // Compiled successfully, make the jar file. Arguments jarargs = new Arguments(); jarargs.addElement("cfv0"); File jarfile = project.getJarFile(); jarargs.addElement(jarfile); String classfiles[] = classdir.list(); for (int i = 0; i < classfiles.length; i++) { jarargs.addElement(classfiles[i]); } Utils.pushd(classdir); Stream.verbose.println("Running the jar tool: " + jarargs); sun.tools.jar.Main jar = new sun.tools.jar.Main(System.out, System.err, "jar"); boolean ret = jar.run(jarargs.toStringArray()); Utils.popd(); return ret; */ return Boolean.TRUE; }} } Test { /** Test the program. */ Object run(Project project, Arguments args) (@ if (new Compile().run(project, new Arguments()) == null) return null; addModuleArgs(project, args); String cl = project.getMainClass(); String pkg = project.getPackage(); String name = (pkg == null ? cl : pkg + "." + cl); // Modify the class path to find the user's classes. String classpath = project./* getJarFile */ getClassDir() + File.pathSeparator + System.getProperty("java.class.path"); try { String cmdarray[] = new String[args.size() + 4]; cmdarray[0] = project.getJVM(); cmdarray[1] = project.getClasspathOption(); cmdarray[2] = classpath; cmdarray[3] = name; System.arraycopy(args.toStringArray(), 0, cmdarray, 4, args.size()); Stream.out.println("Running the test..."); for (int i = 0; i < cmdarray.length; i++) Stream.verbose.print(cmdarray[i] + " "); Stream.verbose.println(); File input = project.getTestInputFile(); int retval; if (input == null) { retval = Utils.exec(cmdarray, true); } else { Stream.verbose.println("with input from " + input + ","); retval = Utils.exec(cmdarray, new FileInputStream(input)); } return (retval == 0 ? Boolean.TRUE : null); } catch (FileNotFoundException e) { Stream.err.println(e); return null; } catch (Exception e) { e.printStackTrace(); return null; } @) } Clean { /** Remove generated files and directories. */ Object run(Project project, Arguments args) (@ addModuleArgs(project, args); Stream.out.println("Removing generated files and directories..."); Stream.verbose.println("Args = " + args); deleteRecursively(Utils.getcwd(), args.toStringArray()); return Boolean.TRUE; @) /** Recursively remove each file and directory. */ void deleteRecursively(File dir, String files[]) (@ // Globbing would be nice... for (int i = 0; i < files.length; i++) { File file = new File(dir, files[i]); if (file.isDirectory()) { deleteRecursively(file, file.list()); } Stream.debug.println("Deleting " + file); file.delete(); } @) } Arguments { /** Copy the arguments into a String array. */ String[] toStringArray() (@ String array[] = new String[size()]; int i = 0; Enumeration args = elements(); while (args.hasMoreElements()) { array[i++] = args.nextElement().toString(); } return array; @) }