-*- mode:outline; minor-mode:outl-mouse -*- * Changes in 0.8.6, released 30 Jan 2003: ** API docs now included in the release Javadoc-generated API documentation is now included in the release, in the doc directory. This includes DJ, the AP Library, and the runtime support classes in in edu.neu.ccs.demeter and RIDL_Runtime. ** DJ and AP Library: strategy intersection DJ and the AP Library now support strategy intersection, for example: intersect(from A via X to B, from A via Y to B) The traversals with this strategy will only include paths that are expansions of or . ** DJ and AP Library: strategy reference DJ and the AP Library now support strategy references, for example: Map env = new HashMap(); env.put("s1", new Strategy("from A via X to B")); env.put("s2", new Strategy("from A via Y to B")); Strategy s = new Strategy("intersect(s1, s2)", env); ** DJ: TraversalGraph -> Traversal The TraversalGraph class has been renamed to Traversal, because a traversal may be a combination of graphs instead of just a single graph. For backwards compatibility, there is still a TraversalGraph class that extends Traversal, but it will probably go away soon; please switch to using Traversal. ** DJ and AP Library: debug flag made static The debug versions of the constructors for aplib.TraversalGraph and dj.Traversal have been removed; set the static "debug" flag on these classes instead to get debugging output. ** DJ: bug fix: no construction edges from other packages When a class or its package is added to a ClassGraph directly (with ClassGraph.addClass() or .addPackage()), the class's construction and inheritance edges are also added to the ClassGraph, as well as the targets of those edges. However, the construction edges of the targets will not be added to the ClassGraph. This was previously true for targets of construction edges of classes added directly, but it is now true for targets of inheritance edges (superclasses) as well. The most noticeable effect of this fix is that Object.getClass() and .toString() will not be added to a ClassGraph unless Object or java.lang is added directly (with the addMethods flag turned on). ** DJ: bug fix: strategy starts with an interface Traversing a strategy that starts with an interface no longer throws TraversalSourceException. ** AP Library: cd package: default partnames use mixed case If you leave out the partname for a construction edge in a class dictionary parsed by the aplib.cd package, one will be generated by lowercasing the first character of the class name, rather than lowercasing the entire class name. This conforms more closely to the naming conventions in the JLS. ** AP Library: cd package: bug fix: don't attach EOF to the link node class generated from a repetition class If a repetition class declaration ends with an EOF parse token, the generated link node class was also getting the EOF, but it now only appears on the container class. ** AP Library: cd package: made more stuff public ** AP Library: cd package: added allSyntax traversal and SyntaxVisitor * Changes in 0.8.5, released 03 Jan 2003: ** DemeterJ: bug fix: optional parts of builtin type An optional part whose type is a builtin type now generates correct traversal code, i.e. it no longer tries to compare it with null. ** DemeterJ: added JavaCharStream.java to the output files of JavaCC 2.1 ** DemeterJ: bug fix: properly catch thread exception in OutputForwarder Running "demeterj test" with test input and output was causing a NullPointerException in Java 1.4; this should no longer happen. ** AP Library: bug fix: cd package allows terminal types The aplib.cd.ClassGraph class now handles terminal types correctly (types on the right side of a class definition that do not appear on a left side, such as "String" or "int"). In particular, ClassGraph.getNode() will no longer throw a NoSuchClassGraphNodeException when called with a terminal type name, and Edge.getTarget() will no longer return null for edges returned from ClassGraph.getOutgoingEdges/getIncomingEdges(). ** AP Library: made cd package visitor classes public ** AP Library: added cd/ClassGraph.readFrom(Reader) ** DJ: construction edge visitor methods Traversing a construction edge (i.e. a field or method) now invokes before and after methods on the visitor(s). See the API docs for details. ** DJ: bug fix: asList().iterator().next() on a Collection Traversing a Collection that is not a List using the APCollection iterator no longer throws an UnsupportedOperationException. ** AP Studio: bug fix: Help displays user manual * Changes in 0.8.4, released 05 Jan 2002: ** DJ: bug fix: asList().iterator().next() would sometimes hang A synchronization bug would sometimes cause the list iterator to hang while calling next(). That will no longer happen. ** DJ: bug fix: asList().iterator().set() would sometimes replace the wrong object The list iterator would sometimes replace the wrong item in a collection when using the set() method. It now rewinds to the correct spot before replacing. ** DJ: bug fix: gather no longer has duplicates The gather method was including objects multiple times when multiple classes in an object's hierarchy were targets of the strategy. Now such objects will only be added once (unless they are actually visited more than once). ** DJ & AP Library: via edge patterns supported Path directive strategy expressions may now contain positive constraints with edge patterns, e.g. from A via -> X,y,Z to B which will select only paths from A to B that contain at least one construction edge from X to Z labeled y, while from A via { -> *,foo,*, => K,*, Q } to B will select only paths from A to B that contain either a construction edge labeled foo, an alternation edge from K, or a node labeled Q. ** DJ & AP Library: bug fix: better handling of strategy nodes that overlap When two or more strategy nodes overlap, either because their labels intersect or they map to the same class graph nodes, there were some problems with paths not being found. It's more careful to do the right thing in this case now. ** DemeterJ: bug fix: allow parsing of big hex literals The generated grammar file can now parse hex literals bigger than the maximum integer (or long if followed by L); they are converted to negative numbers as defined in the Java spec. E.g. 0xffffffff becomes the integer -1. ** DemeterJ: weaver: improved output formatting Improved the output formatting of the weaver, i.e. the generated Java code. ** DemeterJ: front end: JAVADIRS option added to project file The JAVADIRS option in the prj file allows you to specify a space delimited set of directories which are scanned for java files. All found java files are compiled into CLASSDIR. In order for dependency calculation to work, ie, for the files only to be recompiled when newer than the .class files they generate, a the directory organisation of the sources must correspond to the package structure of the classes. Example: If I have class foo.bar.Baz and grok.zap.Arff, I would expect to see directories foo and grok both in the current dir and JAVADIRS = foo grok I would expect foo/bar/Baz.java and grok.zap.Arff.java to be the source files. ** DemeterJ: bug fix: remove Cloneable interface A long time ago, all Demeter-generated classes implemented the Cloneable interface. Then something broke and only those classes that explicitly implemented an interface in the class dictionary were also given the Cloneable interface. Rather than restore the original behavior, it seemed like a better idea to not implement any implicit interfaces; in other words, if you want a class to implement Cloneable, you must say so in the class dictionary file. (Previously, if you did so, it would cause a compile error because the generated class would implement Cloneable twice.) ** DJ: added ClassGraph constructors for packages Added two new constructors, ClassGraph(String pkg) and ClassGraph(String pkg, boolean fields, boolean methods), where pkg is a package name. This is how to create a class graph that does not include the default (unnamed) package. ** DJ: optimized traversals Added memoization to Visitor and ObjectGraphSlice to avoid redundant calls to the reflection package. ** AP Studio: restored the help files "Help->User's Guide" in the AP Studio (invoked by "demeterj studio") now displays the HTML User's Guide. * Changes in 0.8.3, released 24 Jan 2001: ** DJ: print entire stack trace when visitor method throws exception Added the new class VisitorMethodException to DJ, which is thrown when a method defined on a visitor throws an exception; when its stack trace is printed, the exception thrown by the visitor method is printed instead. This helps debug errors in a visitor method; previously, only the stack trace up to Visitor.invokeMethod() was printed. ** DJ: bug fix: exception when using a class graph created from a traversal graph Some ClassGraph constructors were not properly initializing everything, which sometimes would cause a NullPointerException. ** DJ: bug fix: Visitor.getMethod() finds method on superclass Visitor.getMethod() was only returning a matching method if it was declared in the visitor instance's class, and not checking any of its superclasses. ** bug fix: escaped chars in syntax strings in class dictionaries Escaped characters in syntax strings in .cd files were causing parse exceptions. For example, A = "\"" . This now correctly compiles and generates a parser which will accept the single character '"' (double-quote). All other escape sequences defined by Java are also accepted, including octal escapes. ** bug fix: generated parser incorrectly interpreted octal escapes The parser created by DemeterJ mistranslated octal escapes in an input sentence; e.g. the octal escape sequence "\123" was being translated as "\23" and the wrong character was produced. * Changes in 0.8.2, released 23 Oct 2000: ** new name: DemeterJ Demeter/Java and demjava are now known as DemeterJ and demeterj, respectively. ** DJ: intercession interface to Visitor method invocation Several methods have been added to edu.neu.ccs.demeter.dj.Visitor that may be overridden in subclasses to provide customized behavior other than simple before and after methods: void before(Object obj, Class cl) void after(Object obj, Class cl) void invokeMethod(String name, Object obj, Class cl) The first two methods are called for each node visited in the traversal graph when traversing with traverse(). Their default behavior is to call the third method with "before" and "after" as the first argument, respectively; its default behavior is to use reflection to invoke the appropriate method on the visitor object (if a subclass defines one). ** DJ: iterator set() implemented The set() method on the ListIterator returned by asList().listIterator() has been implemented. Still unimplemented are hasPrevious(), previous(), add(), remove(), nextIndex(), and previousIndex() (they all throw UnsupportedOperationException). ** DJ: backwards traversal The traverse(), gather(), and asList() methods in ObjectGraphSlice now take an optional boolean argument that determined whether to traverse the graph forwards or backwards (i.e. left-to-right prefix order or right-to-left postfix order). The default is to go forwards. ** DJ: final members added to the class graph Final fields and methods weren't being added to the class graph unless added explicitly with addConstructionEdge(); they are now added the same way that non-final fields and methods are. Static members must still be added explicitly. ** DJ: bug fix: JVM hangs when using asList The JVM was hanging after the program had finished because the iterator thread was still waiting. It is now a daemon thread, which does not cause the JVM to stay running when all other threads have finished. ** DJ: bug fix: fetch throws spurious non-unique path exception ObjectGraphSlice.fetch() was throwing a FetchException claiming there was a non-unique path when there was a unique path. It no longer does this. ** DJ: bug fix: traversal to primitive types throws ClassNotFoundException DJ traversals to primitive types (e.g. "from A to int") now work. ** DJ: bug fix: arrays of strategy target type are gathered The Lists returned by gather() and asList() were including array objects whose component types were targets of the strategy; they are no longer considered target objects and only the component objects are included. ** DJ: bug fix: superclasses visited multiple times per object When visiting an object whose superclass is also in the traversal graph, the visitor methods on the superclass were being called multiple times; in addition, inherited members were being traversed multiple times. This no longer happens. ** DJ: bug fix: visitor methods called in wrong order Sometimes a subclass before-method was being called before the superclass before-method for the same object; now they are always called in order from least-specific to most-specific, as per the algorithm in Figure 9.1 on page 257 of the Demeter book. The after-methods are called in reverse order. ** DJ: bug fix: sets or wildcard in strategy expression Strategies of the form "from X to {Y, Z}" and "from X to *" were not working and/or causing an InternalError. They should work now. ** naming an inline visitor in an adaptive method You can name an inline visitor in an adaptive method like so: void f() via X to Y visitor MyVisitor { before X {{ ... }} ... } ** specifying the superclass of an inline visitor in an adaptive method You can name an inline visitor in an adaptive method like so: void f() via X to Y extends MyVisitor { before X {{ ... }} ... } You can also combine this with visitor naming: void f() via X to Y visitor MyVisitor extends SomeOtherVisitor { before X {{ ... }} ... } ** visitor wrapper methods are inherited Visitor methods on a visitor's superclass are now called in a traversal. For example, if you define: V1 { before X {{ ... }} } V2 { before Y {{ ... }} } // V2 extends V1 traversal f(V2 v) { via X to Y; } then the before methods will be called at both X and Y. Previously only visitor methods that were defined directly on the visitor class used in the traversal parameters would be called. * Changes in 0.8.1, released 21 Sep 2000: ** EDU -> edu in package name According to http://java.sun.com/docs/books/jls/clarify.html, package names are supposed to be lowercase, not uppercase. The Demeter package names have been converted from EDU.neu.ccs.demeter... to edu.neu.ccs.demeter... ** COOL: a coordination aspect language The COOL processor has been added to Demeter. Set COOLFILES in your project file to be the list of .cool files, or run `demjava cool' directly. See the User Manual for more details about COOL. ** AP Library interface changed The AP Library interface has changed in many ways to be closer to the structures defined in the strategies paper, as well as to use Java 2 collection classes. See the javadoc for details (which can be generated by `make doc' in the aplib directory). ** DJ class graphs are made by reflection instead of from source files The dj.ClassGraph constructor now builds the graph using reflection instead of parsing .java files. It contains only the default package by default; use addPackage() to add other packages. It searches the class path to find class names in the package (there's no way in JDK 1.2 to get a list of classes in a package). All fields and no-argument methods in each class are added by default, even non-public ones. ** DJ follows the class graph rather than the object graph In version 0.8, DJ traversals followed the object graph and used reflection to determine outgoing edges; they now follow the class graph that was made by reflection, maintaining token sets as described in Algorithm 2 from the strategies paper. This should produce more correct traversals, as well as being faster by only using reflection on fields and methods corresponding to the edges in the traversal graph rather than all fields and methods defined on and inherited by each object's class. ** removed TraversalGraph.compute from DJ and AP Library The static compute methods have been removed from dj.TraversalGraph and aplib.TraversalGraph. Use the constructors instead. ** removed -Xdepend from javac options in .prj file The version of javac in Java 2 SDK v1.3 no longer supports the -Xdepend option, so it no longer appears in .prj files generated with `demjava new'. If you need stronger dependency checking, use the oldjavac compiler with -Xdepend. ** duplicate part name detection The code generator now aborts if it detects duplicate part names in a class definition, either explicitly defined or implicitly, e.g. Foo = Bar Bar. ** bug fix: project names may now be non-Idents Formerly, a project name (as an argument to `demjava new', as a value for the `-project' option, or as the base name of a .prj file) was required to be an Ident, i.e. no punctuation other than underscore. It may now be a Word, i.e. any sequence of non-whitespace chars. * Changes in 0.8, released 07 Oct 1999: ** DJ: run-time adaptive traversals in pure Java Demeter/Java now includes the DJ package, EDU.neu.ccs.demeter.dj, a library of Java classes for performing traversals at run-time. The classes are in the file dj.jar, which depends on aplib.jar and rt.jar. See the DJ home page at http://www.ccs.neu.edu/research/demeter/DJ/ for more information. ** AP Library: traversal graph computation The old tg package has been replaced with EDU.neu.ccs.demeter.aplib (still in the aplib.jar file). See the AP Library home page at http://www.ccs.neu.edu/research/demeter/AP-Library/ for more information. ** parse(java.io.Reader in) available A parse method with a java.io.Reader argument is now available on each class. The java.io.InputStream version is still available as well. ** -depend changed to -Xdepend The COMPILER_ARGS line in the .prj file generated from "demjava new" now includes -Xdepend instead of -depend, for Java 2 javac. ** apstudio compatible with Java 2 Swing Changed the Swing imports to javax in AP Studio so that it runs with Java 2. ** bug fix: .java args to "demjava compile" forces a compile Previously, "demjava compile" only invoked the compiler if any generator-produced java files had changed relative to their class files; now, if the user gives java files on the command line or in COMPILE_ARGS, the compiler will always be run. * Changes in 0.7.3, released 31 Mar 1999: ** separate jar files The demjava.jar file has been split into four files: rt.jar -- runtime support for demjava-compiled programs aplib.jar -- the AP Library (see below) demjava.jar -- the demjava tool apstudio.jar -- the AP Studio GUI tool Each jar file depends on classes in the ones above it, so you need all the relevant ones in your class path. (I.e. to use AP Studio you need all four.) The demjava script and demjava.bat batch file have been modified to take care of this. ** name maps for strategy graphs Name maps for strategy graphs are now supported, as defined in the strategies paper. For example: Foo { traversal t(V) { { A -> B bypassing -> *,x,* B -> C } with { A = Foo, B = Bar, C = Baz, x = garply }; } } is equivalent to: Foo { traversal t(V) { { Foo -> Bar bypassing -> *,garply,* Bar -> Baz }; } } Note that the name map need not be onto; nodes in the strategy graph which are not present in the name map are simply mapped to themselves. Moreover, the name map may not even be one-to-one; this is useful, for example, in expressing the requirement that a cycle be traversed at least once: A { traversal t(V) { { A -> B B -> C C -> X } with { C = A }; } } This is not equivalent to: A { traversal t(V) { { A -> B B -> A A -> X }; } } because the latter allows all paths of the form "A,(B,A)*,X" whereas the former only allows paths of the form "A,B,A,(B,A)*,X". ** new traversal graph calculation API The AP Library (also known as the EDU.neu.ccs.demeter.common.tg package) has undergone an overhaul. The main entry point is: /** Compute the traversal graph corresponding to the strategy graph sg with the given nameMap. A null nameMap means the identity function. */ public TraversalGraph computeTraversalGraph(StrategyGraphI sg, Dictionary nameMap) which is called on a ClassGraph object built from your class graph; the TraversalGraph object can then be queried (or iterated over) to determine which nodes and edges are in it. See tg/tg.beh for more details. NOTE: this will soon be replaced with a better interface in EDU.neu.ccs.demjava.aplib. Stay tuned... ** no reserved words Demeter keywords (e.g. "common", "start", "get", "before") are now usable everywhere as identifiers without causing a parse error: class names, part names, package names, traversal names, visitor names, method names, parameter names and types, and return types. ** alternate syntax for code fragments Code fragments in class dictionary and behavior files may now be enclosed in {{ }} instead of (@ @). This interacts more nicely with Java indentation mode in emacs, for example. ** bug fix: via X to * A long-standing bug relating to multi-edge strategies ending in "to *" has been fixed. See the regression test suite-line-strategy/j-pos-vs-neg/ for an example. ** bug fix: don't call edge wrappers when not traversing the edge With multi-edge strategies, sometimes edge wrappers were being called on edges that weren't actually being traversed (because of the node set checking). That no longer happens. See regression test suite-edge-wrappers/j-shortcut. ** bug fix: lookahead in possibly-empty repetition classes Lookahead directives in possibly-empty repetition classes (e.g. Foo ~ { X }.) are now put in the right places. See regression test suite-repetition/j-lookahead. * Changes in 0.7.2, released 8 Oct 1998: ** New module: demjava studio The AP Studio GUI tool has been merged into demjava as the studio module. To use it, you'll need to install Sun's JFC (aka Swing) and make sure the demjava script or demjava.bat batch file has the right directory for it. ** New module: demjava weave The generator now produces core aspect weaver files (.wvr), which are translated into Java files by the weave module, which is called by default before the compile module is run. ** "demjava new" produces sample files The "new" module now produces sample .cd, .beh, and .input files with the given project name (still "program" by default). Use the -nosamplefiles option (i.e. "demjava new -nosamp") to only produce the .prj file. Also, the -noinput option makes it not produce the .input file, and produce .prj and .beh files that do not read from the input. ** alternate syntax for Text objects A Text object may now be delimited by {{ ... }} in addition to (@ ... @). However, CD files and behavior files must still use (@ ... @) until the next version. ** slightly more front-end output in non-verbose mode In non-verbose mode, the front-end now prints one line status for each module run. Otherwise, it was hard to tell when (e.g.) the compiler was being run, since javac by default produces no output itself. ** removed: -compile and -parser generator options The -compile and -parser options to the generator has been removed; use the front end (i.e. "demjava compile" and "demjava parsegen"). ** syntax removed: with This syntax for adaptive methods is no longer supported (aka "Doug's preference" in version 0.6.2): void foo() to Bar with Vis1, Vis2; Instead, use this (aka "Josh's preference" in 0.6.2): void foo() to Bar (Vis1, Vis2); ** PrintVisitor and EqualVisitor now have derived part visitor methods PrintVisitor and EqualVisitor (as well as their abstract parent UniversalVisitor) now include visitor methods for derived parts. In particular, derived parts are printed by PrintVisitor. ** new option: -eofbug If you're getting the dreaded "hanging bug" (usually happens on Win95), try the -eofbug option. This will terminate threads that are still around 3 seconds after an exec'd process (e.g. JavaCC or your test program) has completed. ** bug fix: unfinished output Undid a previous attempt at fixing the "hanging bug", which was killing an output thread prematurely on some platforms (e.g. Solaris). The old behavior (with a 3 second timeout added) is available with the -eofbug option (see above). This behavior is also needed for the -noblock option. If neither option is used, then it will wait politely for all output threads to terminate. ** bug fix: weird interaction with getters & setters and init methods Fixed an odd bug which caused this to produce erroneous code: Main { // x is a derived part of type int get x (@ return 0; @) init (@ @) // this generates "int()" instead of "Main()" } * Changes in 0.7.1, released 14 Aug 1998: ** bug fix: allow all project names Fixed a bug that prevented the module names (e.g. generate, test) from being used as project names. ** front end passes all environment variables through The front end now passes the complete calling environment to each module, so that, e.g., your test program can access "$HOME" (probably indirectly through AWT). A side effect is the addition of the "CLASSPATH_OPTION" setting in the project file, which is used to pass the classpath to the JVM and the compiler; the default is "-classpath". ** better detection of blocking in front end The front end is slightly smarter about avoiding being blocked, but still hangs sometimes on Windows 95. See the BUGS file for more details. * Changes in 0.7, released 24 Jun 1998: ** new front end There is now better front-end support for managing a Demeter project. Usage: demjava [ -project projname ] [ -verbose ] [ -debug ] [ -noblock ] [ -tie ] [ module [ module-options ] ] demjava -version demjava -help Modules: new Start a new project. generate Generate aspects, grammar, or Java code. parsegen Generate parser Java code from the grammar. compile Compile the Java code into bytecodes. test Test the compiled program. clean Remove all generated files. Each module runs preceding modules that it depends on, if needed. If no module is specified, the "compile" module will be run, unless there is a .cd file in the arguments, in which case, for backwards compatibility, only the "generate" module will be run. The -verbose and -debug flags determine the level of output; the -noblock flag is for platforms on which blocking I/O blocks the process, not just the thread; the -tie flag ties error output to standard output, as it did before. Any unrecognized options before the module name are passed on to the module (again, for backwards compatibility). The first thing demjava does is to load the project file. If the project name is specified with the "-project projname" option, then the file "projname.prj" is loaded from the current directory; otherwise, if there is exactly one .prj file in the current directory, then it is loaded; otherwise (unless the module is "new") demjava aborts. A project file is created by "demjava new [projname]", where projname defaults to "program". The project file can then be hand-edited (it's just an ordinary text file) to specify project configuration options as necessary. See the comments in the generated project file for more info on how to customize the project file. The generate module is the code, grammar, and aspect generator (i.e. the entire demjava program in previous versions). Its options are the same as in 0.6.6, except that the -parser, -compile, and -classdir options are now ignored. The parsegen and compile modules invoke programs by calling exec(). The programs they invoke are specified in the project file as the values of PARSEGEN and COMPILER, respectively. If your platform's version of exec() uses an executable path to search for programs to be executed (e.g. the PATH environment variable on Unix and Windows), then the programs specified by these variables must be on this path at runtime (or else their paths must be fully specified in the project file). The test module invokes the Java virtual machine (specified by JVM in the project file) on your compiled program (as specified by CLASSDIR, PACKAGE, and MAIN). If TEST_INPUT is set, it specifies a file which will be read as input for the test. The clean module removes all files and directories (recursively) specified in the CLEAN_ARGS setting in the project file. The demjava script and the demjava.bat batch file in the bin directory take care of setting the class path correctly and passing the user path to demjava, but you will need to customize the paths in these files when installing. ** traversal graphs printed to output directory Each calculated traversal graph is now printed to a file in the output dircetory ("gen" by default) with a name of the form _.trv where is the name of the traversal method and is the name of the source of the traversal, i.e. the class that the traversal method is attached to. Note that will be of the form __trav_ for inline adaptive methods. The traversal graph is in the form of a subset of the class graph; the token set info is not displayed. ** default classdir changed to "gen/classes" The default directory into which the class files are generated has been changed from just "gen" to "gen/classes", to make it easier to create jar files from the class files. ** -aspect option renamed to -weaver The option to the generate module for generating aspect weaver files is now "-weaver" rather than "-aspect". ** aspect files extension changed from ".asp" to ".wvr" Files generated for the aspect weaver now end in ".wvr" rather than ".asp". ** terminal classes implement java.io.Serializable The terminal classes, Ident, Text, Word, and Line, now implement the java.io.Seralizable interface, allowing them to be serialized. ** slightly more stringent error handling The generate module now terminates with an error message if any traversals are bad, i.e. if the subgraph resulting from combining a traversal strategy with the class graph doesn't include all of the sources and targets of the strategy. This prevents the error from not being noticed until (possibly cryptic) compiler error messages much later. ** changed utility method on PrintVisitor from private to protected The space() method on the generated PrintVisitor is now protected rather than private, so that descendant classes can use it. ** bug fix: extra paths in traversal graph A long-standing bug involving extra paths existing in the traversal graph when a strategy edge has a negative constraint has been fixed. See suite-line-strategy/j-extra-path for the regression test. ** bug fix: common parts grammar bug Another long-standing bug involving spurious left recursion errors in the grammar generated when an abstract class with common parts has an alternation that can be matched by the empty string has been fixed. See suite-parse/j-common for the regression test. * Changes in 0.6.6, released 10 Mar 1998: ** new terminals: Line and Word Two new terminal classes are available, Line and Word, which represents a line (everthing up to the next newline) and a word (everything up to the next whitespace), respectively. Where it appears in the class dictionary grammar, the rest of the current line or word will be read verbatim and put into the Line or Word object (which can be converted toString() just like Ident and Text). Note that a Word is different from an Ident in that it may contain any non-whitespace character, rather than just alphanumerics. Caveat: don't use Line or Word at a choice point in the grammar (i.e., anywhere you can put a lookahead specification); because these overlap with other tokens, they use separate lexical states, which are not taken into account when lookahead is done. In particular, you can't use them by themselves in a repetition class, for example Words ~ { Word }. because it won't know when to stop reading words. Instead, prefix the Word or Line by either syntax or another class (that isn't representable by the empty string), like this: Words ~ { "word:" Word }. ** start and finish methods Two new types of visitor methods, for use in adaptive methods: start (@ ... @) and finish (@ ... @). The start method is called once at the beginning of the traversal, after the visitor has been constructed and the adaptive method parameters have been filled in (if present); the finish method is called once at the end of the traversal, before the return method (if present). Important: to use a visitor that is not defined "inline" in an adaptive method, you must define start and finish methods (possibly empty) in addition to the parameter and return_val parts that were required previously; for convenience, the generated UniversalVisitor provides empty definitions of these, and by marking a class as a visitor in the class definition it will automatically extend UniversalVisitor. See the regression test in suite-adapmeth/j-start-finish for an example program that couldn't be implemented easily without start and finish methods. ** no more stars! Asterisks in Demeter keywords (e.g. "*common*") are now optional (except for in the print syntax commands "*s" and "*l") and in fact deprecated. At some point they will no longer be recognized. ** allow "throws" clause in method declarations Verbatim methods may now declare a comma-separated list of exceptions thrown, just as in plain Java. ** allow array return types Methods may now return an array type just as in plain Java. ** changed traversal method name generation The generated traversal methods' names now include the name of the source class, rather than using a global counter. This ensures they will be unique while not causing addition or deletion of traversals to affect large portions of the generated .java files. ** removed 'preamble' A general 'preamble', a block enclosed in (@ @), at the top of the class dictionary is no longer allowed. The only things allowed at the top are import statements. ** derived edge getters and setters are public All derived edge getter and setter methods are now declared as public. In the future, they will be just like other Demeter methods, and can be public, package, or private. ** quoted arguments to the demjava script The bin/demjava shell script now correctly passes a quoted argument as one argument, even if it includes spaces. * Changes in 0.6.5, released 29 Jan 1998: ** changed ParseError to ParseException, for JavaCC 0.7 The generated code now uses ParseException instead of ParseError. ** bug fix: -aspect: use "constructor" for init methods Aspect generation now correctly generates init methods with the "constructor" keyword. ** bug fix: -aspect generating invalid .asp files Wrapper code in the generic visitors is now generated with (@ @) instead of { }. * Changes in 0.6.4, released 9 Oct 1997: ** demjava.bat -- DOS batch file The file demjava.bat in the bin directory is a DOS batch file for running demjava, javacc, and javac. It assumes you have everything on your %CLASSPATH% already. ** classes put into demjava.jar file The demeter classes are packaged into a single demjava.jar file. Add this file to your CLASSPATH instead of the classes directory. ** package names changed All the package names were changed: demeter is now EDU.neu.ccs.demeter demeter.tools.demjava is now EDU.neu.ccs.demeter.tools.demjava demeter.tools.demjava.tg is now EDU.neu.ccs.demeter.common.tg ** -parser command-line option The -parser command-line option causes demjava to invoke the parser generator (currently COM.sun.labs.javacc) on the grammar file. ** -compile command-line option The -compile command-line option causes demjava to invoke the Java compiler (currently sun.tools.javac) on the generated .java files, with options "-g -deprecation -d -classpath :" where is set by the -classdir option (see below) and is the current value of the Java class path. ** -classdir command-line option The -classdir command-line option sets the output directory for the -compile option (see above). It defaults to "gen" (the same as -outputdir). ** -aspect command-line option The -aspect command-line option generates core aspect files to the output directory with the ".asp" extension. These are intended to be read by an aspect weaver and converted into plain Java code. ** DisplayVisitor and TraceVisitor now use PrintWriters Constructors are now available for DisplayVisitor and TraceVisitor that take a PrintWriter. The old PrintStream constructors still work too, and an empty constructor still uses System.out. ** EqualVisitor and CopyVisitor use return methods EqualVisitor and CopyVisitor return their values (boolean and Object, respectively) with visitor return methods, so that, e.g., they can be used in adaptive methods. The old accessor functions get_is_equal() and get_copy() still work too. ** bug fix: around methods for multi-edge traversals Traversals with multiple edges pass a BitSet called "nodes" along as part of the arguments. Around methods weren't properly including this argument. They do now. ** bug fix: multiple visitors in an adaptive method Using multiple visitors in an adaptive method (e.g. foo() = t(V1, V2)) caused a compile error, because both arguments to the traversal method were "v0". This no longer happens (it names them "v0", "v1", etc.) ** bug fix: parsing a class that extends a non-parsed class The parser rule for a class that is parsed that extends a non-parsed class contained a bogus call to _common(). It no longer does this. * Changes in 0.6.3, released 7 Sep 1997: ** init methods are public Init methods (no-arg constructors) are now public by default (they were previously package scope). ** bug fix: parser rules for terminal classes Parser rules for terminal classes inside not-parsed visitors (e.g. inline adaptive methods) were being erroneously generated, which caused compile errors if the terminal class had no no-arg constructor (e.g. PrintWriter). This no longer happens. ** bug fix: importing a specific class Import statements in a CD of the form "import foo.bar.Baz;" now work correctly. ** performance: use Adler32 instead of CRC32 Checksums computed when generating code now use the Adler32 algorithm instead of CRC32, which should make it a bit faster. * Changes in 0.6.2, released 4 Sep 1997: ** interfaces You can now define interface classes in your .cd file, just like regular classes: *interface* Foo : Bar | Baz. *interface* Bar = . *interface* Baz = . Currently you can't define parts on an interface. You can define interface methods in a .beh file: Bar { int quux(String s); void garply(Baz b, int x); } You cannot traverse to an interface, nor can you put wrappers on an interface-- they are treated just like terminal classes. ** abstract methods You can now define abstract methods in a .beh file: Foo { abstract void bar(int x); } You can only define abstract methods on alternation classes. ** alternation classes need not have alternatives You can define an alternation class without any alternatives: Foo : . This defines an abstract class, which cannot be parsed. ** package-qualified names in the class dictionary You may now refer to fully package-qualified names in the class dictionary (e.g. "Foo = java.util.Vector"). If no part name is provided, the generated part name will be the base class name converted to lowercase (e.g. "" in the above example). ** import statements in class dictionary You may now specify import statements at the top of the class dictionary, below the package declaration (if any). Both forms are allowed: import java.util.Vector; // import one class import java.io.*; // import all classes in the package ** new *visitors* keyword You may flag a section (or multiple sections) of the class dictionary as being visitor classes by surrounding it with "*visitors*" and "*endvisitors*". Or, for a single class, use the keyword "*visitor*" before the class name. Any class so marked will automatically extend UniversalVisitor (unless it already extends something else); thus you can write traversal methods that take UniversalVisitor arguments and pass them any visitor class. ** alternate syntax for adaptive methods You may use any of the following syntaxes for defining an adaptive method using an existing traversal method and visitor classes: // assume "trav" is a traversal method with args "Vis1" and "Vis2" void m1() trav(Vis1,Vis2); // old syntax void m2() = trav(Vis1,Vis2); // Josh's preference void m3() = trav with Vis1,Vis2; // Doug's preference Two of these are likely to go away soon... ** return value in adaptive methods need not declare return type For an "inline" adaptive method, a return value method need not declare a return type; it will be the same as the adaptive method's return type. For example, you can say: int f() to X { return (@ 3 @) } rather than: int f() to X { return int (@ 3 @) } However, visitor classes defined outside of adaptive methods must still specify the return type. ** -tie option to tie stderr to stdout For broken command shells that don't let you redirect the standard error stream (e.g. DOS 7 in Windows 95), the "-tie" command-line option can be used to send all error messages to standard output. ** performance: around methods no longer use inner classes To avoid creating huge number of .class files, around methods have been reimplemented using the reflection package instead of with inner classes. ** bug fix: class with init method and no parts A class with an init method and no parts now compiles without error. ** bug fix: using existing traversal methods with inline visitor in adaptive methods You can now use an existing traversal method with an inline visitor in an adaptive method; the generated visitor will extend the traversal method's parameter class. The traversal method must have exactly one parameter, though. ** bug fix: adaptive method with multiple sources An adaptive method attached to multiple source classes now compiles correctly. E.g. { Foo, Bar } { void f() to Baz { before Baz (@ ... @) } } will generate two traversal methods and two visitors. (Probably should be optimized to one visitor...) * Changes in 0.6.1, released 14 Oct 1997: ** automatic return_val variable in adaptive methods An adaptive method with inline behavior without a return value expression will have an implicit variable "return_val" whose type is the return type of the adaptive method. For example: A { B getB() to B { before B (@ return_val = host; @) } } ** bug fix: empty behavior list in adaptive method This no longer causes an exception: A { void foo() to B {} } ** bug fix: multiple adaptive methods on a class There may now be more than one adaptive method per class. ** better diagnostic for traversal calculation A warning is printed for each source and target of a traversal that isn't in the calculated traversal graph. ** "No path found" error less restrictive Traversal graph calculation only halts with an error if none of the sources or none of the targets of a traversal are in the traversal graph. * Changes in 0.6, released 11 Oct 1997: ** traversals as objects Traversals as Objects allows the programmer to manipulate traversals (instances of the class Traversal) as any other object. This technology is enabled with the -tao switch. The -debug switch gives [very] verbose debugging info. To make a traversal, use the static fromString method: Traversal t1 = Traversal.fromString("from A to {B,C};"); Traversal t2 = Traversal.fromString("from {A,B} to C then to {D,E};"); Traversal t3 = Traversal.fromString("from {A,B} bypassing D to C;"); Then call a traversal on an instance object. t1.traverse(instobj,some_visitor); instobj must be one of the classnames given as a from class. some_visitor is either a Vector, array or single instance of a Visitor. All visitors used must be a subclass of TAOVisitor. TAOVisitor must be in the .cd file. The current implemention is naive, so there are some constant factors that can be shaved off both runtime and compile time, but I don't think better than 1/3 the performance of static traversals is achievable. This may be optimistic. Known bugs: Edges are ignored. They cannot be specified in the traversal, and their wrappers will not be called. The * classname glob is not [yet] implemented. Thanks to Johan Ovlinger for the TAO implementation. ** method signatures can be declared outside (@ @) The following syntax for a method in a behavior file is now accepted: Foo { boolean bar(Baz b, Fred x[], int[][] j) (@ // arbitrary java code here @) } The old style of putting the signature inside the (@ @) is still supported, and still necessary in certain cases (e.g. constructors, or methods that throw static exceptions) but this new style of declaring methods is encouraged. ** return values for visitors A visitor class may declare a return value expression, for example: FooVisitor { return int (@ x + y @) } Inside (@ @) can be any valid Java expression of the type declared. This is useful for visitors used in adaptive methods (see below). ** traversal parameter names no longer need to be specified Instead of saying this: traversal t(FooVisitor f, BarVisitor b) { ... } you can just list the argument types (visitor classes): traversal t(FooVisitor, BarVisitor) { ... } since the variables aren't accessible to user code anyway. ** adaptive methods An adaptive method is a combination of a traversal method with one or more visitor classes: program.cd: Foo = Bar. Bar = int Baz. Baz = String. BarBazVisitor : BarBazCollector. BarBazCollector = String int. program.beh: Foo { traversal bazInBar(BarBazVisitor) { via Bar to Baz; } } BarBazVisitor { before { Bar, Baz } (@ @) return String (@ "" @) } BarBazCollector { before Bar (@ if (host.get_i() > min) s += "i > min"; @) before Baz (@ s += host.get_s(); @) return String (@ s + "\n" @) } Foo { // Adaptive method combining a traversal with a visitor. String collectBarBaz(String s, int min) bazInBar(BarBazCollector); } The above adaptive method gets translated (roughly) to: Foo { String collectBarBaz(String s, int min) BarBazCollector v = new BarBazCollector(); v.set_s(s); v.set_min(min); bazInBar(v); return v.get_return_val(); @) } The visitor class that is specified in the adaptive method must have parts matching the parameters in the adaptive method signature, and a return method (see above) matching the return type (unless it's void). An adaptive method may specify a list of visitor classes to be combined with a traversal method: Foo { traversal t(V1, V2, V3); int f(float x, boolean b) t(V1, V2, V3); } However, the adaptive method parameters must exist as parts on the first visitor, and only the first visitor's return value is returned from the adaptive method. (A future enhancement may provide a more general way to initialize a set of visitor objects and compute the return value from them.) Either or both of the traversal and visitor may be specified "inline" when defining an adaptive method. For instance, the above adaptive method, traversal, and visitor could all be specified with a single adaptive method definition: Foo { String collectBarBaz(String s, int min) via Bar to Baz // the traversal strategy { // the set of visitor methods before Bar (@ if (host.get_i() > min) s += "i > min"; @) before Baz (@ s += host; @) return String (@ s + "\n" @) } } The arguments to the adaptive method automatically become parts of the new (implicitly generated) visitor class. ** *lookahead* keyword Parser lookahead directives can be specified at choice points in the class dictionary grammar with "*lookahead* (@ @)". A choice point is one of: * An alternation: Foo : *lookahead* (@ 2 @) Bar | Baz. * An optional part: Foo = [ *lookahead* (@ 2 @) Bar ]. * A repetition part: Foo ~ { *lookahead* (@ 2 @) Bar }. A lookahead directive is one of: * An integer: the number of tokens to look ahead. (default is 1) * A parser rule or set of rules: each class Foo has a rule _Foo(); a lookahead directive (@ _Foo() _Bar() @) means to look ahead until Foo and Bar have been matched. * An arbitrary boolean Java expression, inside curly brackets. See the file examples/Lookahead/README in the JavaCC distribution for more detail on how this works and when it is needed. Thanks to Binoy Samuel for lookahead directives. ** Repetitions have contains(Foo) method. It uses .equals() to check if an element is in the collection. ** fixed isEmpty() on repetition classes The generated isEmpty() method on repetition classes now returns the right answer. ** LongGetters removed. Getting them right in all cases turned out to be a lot of work; with adaptive methods availible, I'm not willing to do it. * Changes in 0.5.1, released 22 Jul 1997: ** selective parser code generation There are now several ways to turn off generation of parser code for classes. To turn it off for an individual class, use: Foo *noparse* = ... To turn it off for a section of the class dictionary: *noparse* Foo = ... Bar = ... *parse* To turn it on for an individual class inside a section of classes in which it's turned off: *noparse* Foo = ... Bar *parse* = ... Baz = ... *parse* In any case, when parser code generation is turned off, no .parse() method will be defined for the class, and no parsing rule in the grammar will be generated. This means that a parsed class with a part that's a non-parsed class will cause a compile-time error. The generated PrintVisitor and DisplayVisitor still include non-parsed classes, so specifying syntax may still be useful for these. ** wrapper method lookup optimizations Traversal method expansion is now much faster, especially for visitors with a large number of wrappers (e.g. the generic visitors). * Changes in 0.5, released 14 Jul 1997: ** general traversal strategies A strategy expression may be a path or a general graph. Here's the currently supported syntax for strategies. It was pretty much hacked up from nowhere, so it's likely to change, especially the general graph form. Other syntaxes will be added, e.g. strategy variables and compound strategies (join, merge, intersect). Note that the current traversal syntax is still supported by this syntax. Note also that everywhere you can specify a single class or edge, you can also specify a curly-bracketed set of classes or edges. And finally, "through " is not yet supported, but "through " and "only-through " are both supported, so you can translate it by hand for now (see example below). *** Syntax: // Same syntax as before; a traversal is a strategy attached to a // class with a name and list of formal parameters. Traversal = "traversal" TraversalName TraversalParms "{" StrategyExpression ";" "}". TraversalParms = "(" [ Commalist(Visitor) ] ")". Visitor = ClassName VisitorName. // Strategies can be lines or graphs. StrategyExpression : PathDirective | StrategyGraph. // Line strategies: PathDirective = [ NegativeConstraint ] List(PathSegment) TargetDirective. PathSegment = PositiveConstraint [ NegativeConstraint ]. TargetDirective : To | ToStop *common* ClassGlobSpec. To = "to". ToStop = "to-stop". // General graphs: StrategyGraph = "{" List(SGEdge) "}" [ "source:" ClassGlobSpec ] [ "source-edge:" NList(Integer) ] // indices of source edges [ "target:" ClassGlobSpec ]. SGEdge = ClassGlobSpec "->" ClassGlobSpec [ NegativeConstraint ]. // Constraints: Constraint : PositiveConstraint | NegativeConstraint *common* GlobSpec. PositiveConstraint : Through | Via. // These are synonyms. Through = "through". Via = "via". NegativeConstraint : Bypassing | OnlyThrough. // These are antonyms. Bypassing = "bypassing". OnlyThrough = "only-through". // Globs -- nothing's changed here. GlobSpec : OneGlob | GlobSet. OneGlob = Glob. GlobSet = "{" [ Commalist(Glob) ] "}". ClassGlobSpec : OneClassGlob | ClassGlobSet. OneClassGlob = ClassGlob. ClassGlobSet = "{" [ Commalist(ClassGlob) ] "}". Glob : ClassGlob | EdgeGlob. EdgeGlob : PartGlob | SubclassGlob | SuperclassGlob. ClassGlob = ClassNameGlob. PartGlob = "->" SourceGlob "," PartNameGlob "," DestGlob. SubclassGlob = "=>" SourceGlob "," DestGlob. SuperclassGlob = ":>" SourceGlob "," DestGlob. SourceGlob = ClassNameGlob. DestGlob = ClassNameGlob. ClassNameGlob : ClassNameExact | AnyClass. ClassNameExact = ClassName. AnyClass = "*". PartNameGlob : PartNameExact | AnyPart. PartNameExact = PartName. AnyPart = "*". // Parameterized classes. List(S) ~ { S }. NList(S) ~ S { S }. // Terminal buffer classes. ClassName = Ident. PartName = Ident. TraversalName = Ident. VisitorName = Ident. *** Some examples: via A to B; through A to B; // synonym for above via { A, B, C } bypassing -> *,x,* to { D, E, F }; via A via B via C to D; via A only-through -> A,b,B via B to C; // same as "through -> A,b,B to C". { A -> B bypassing X B -> C C -> A } source: A target: C; { A -> B B -> A A -> C } source-edge: 0 target: C; // same as "via B via A to C" attached to A. ** new methods on repetition classes Repetition classes now define the additional methods void push(...) -- add an element to the front of the list boolean isEmpty() -- is the list empty? ** multiple targets & common parts bug fixed A long-standing bug relating to multiple targets in a traversal over an alternation class with common parts has been fixed. ** .xcd bug fixed The expanded class dictionary printed to program.xcd no longer includes the dump of the classdef hashtable. ** deprecated JavaCC syntax removed The generated grammar.jj file now compiles without warning by JavaCC-0.7pre4. * Changes in 0.4.8, released 29 Jun 1997: ** new subgraph calculation code Subgraph calculation (i.e. traversal expansion) is now much faster. ** parse(String) catches ParseError The parse(String) method generated for each class now throws a RuntimeException rather than a ParseError, to avoid having to wrap every call in a try/catch block. The InputStream version still throws ParseError. ** less verbose output Some messages are coalesced from many lines into one line. ** log messages to stdout instead of stderr All non-error messages are printed to the standard output stream, rather than the standard error stream. ** PrintVisitor is smarter about spaces The generated PrintVisitor now only prints spaces if it needs to, rather than after every object. It will print a space whenever it is needed to disambiguate between syntax and identifiers, e.g.: program.cd: Foo = "x" Ident "x" "(" Ident ")". program.beh: Ident f = new Ident("foo"); Foo foo = new Foo(f, f); foo.universal_trv0(new PrintVisitor(System.out)); This will print "x foo x(foo)" rather than "x foo x ( foo )". To print extra spaces, use the "*s" syntax directive, e.g. Commalist(X) ~ X { "," *s X } ** PrintVisitor constructor for PrintStream A PrintVisitor object can be constructed from either a PrintWriter or a PrintStream, because even in JDK 1.1, System.out is a PrintStream. ** expanded class dictionary is saved After parsing "program.cd", the expanded class dictionary is written to "gen/program.xcd". This CD has no parameterized classes or repetition classes, and all part names and inheritance edges are explicitly specified. E.g. A : B | C *common* List(D). B = . C = . D = . List(X) ~ { X }. becomes A : B | C *common* D_List. B = *extends* A. C = *extends* C. D = . D_List = [ D ]. Nonempty_D_List = D Nonempty_D_List. Note that the class dictionary is *not* flattened. Also, repetition class expansion is likely to change (or go away entirely). ** repetition classes use java.util.Enumeration instead of Enumeration Class dictionaries with repetition classes are no longer required to import java.util.Enumeration. * Changes in 0.4.7, released 8 Jun 1996: ** PrintVisitor uses PrintWriter The generated PrintVisitor constructor now takes a PrintWriter instead of a PrintStream, to be compatible with JDK 1.1. ** parts are protected instead of private Parts defined by the class dictionary are now generated as protected parts instead of private. This is mainly to make visitor inheritance less painful. ** Long_Getters To avoid gratuitous breaking of LoD in Johan's programs, I've added long_getters. If you have a long chain of get_far().get_foo().get_bar().get_blox(), this can be replaced by a single long_get_blox(). Of course, you might not get the one you want. Then you need to use a 'through' like concatenation: long_get_foo().long_get_blox(). The object that gets returned by a long_getter is (should be) the first part that is found by a depth first search of the parts reachable from a class. Superclasses, and parts reachable from them come last. Ie, the part that is returned is the first such part that would have been encountered by a traversal to that part. NullPointerException is thrown if an optional part fails to exist. I attempted to do some error handling before, but the interaction with primitive types is nasty (basically, int and null are disjoint. Yuck). Think of a better solution? look in gengetters.beh. I generate getters for ALL reachable parts. Code explosion? I don't think so, but the switch -no_long_get turns off their generation. ** Enumeration thingies Repetition classes now define the methods void addElement(...), Enumeration elements(), nextElement(), hasMoreElements. They behave as expected. Apparently, Enumeration must be imported by the application. Perhaps we can fix this, when interfaces can contain "."s. There is a tentative fix and a nicer version that requires itself to compile commented out in repetition.beh. Please use that for 0.4.8. ** Around methods "Around" methods are methods on a visitor class that control when and how a subtraversal is continued. For example: Visitor { around Foo (@ if (some_condition) subtraversal.apply(); @) } A traversal through a Foo using a Visitor will only continue to its subobjects if "some_condition" is true. The variable "subtraversal" is a reference to an object of an unspecified class that defines one method, void apply(), which performs the continuation of the current traversal. Any "before" and "after" methods for Foo would also be called as normal, before and after the "around" method. An "around" method may be attached to anything "before" and "after" methods may be attached to, including an edge or a set of classes or edges. For more information, see http://www.ccs.neu.edu/home/lth/aao/impl.html. Thanks to Lars Hansen for the design and implementation of this feature. ** Derived parts These are parts that aren't represented in the structure of an object, but are instead computed as they are needed. You specify that a part should be derived by providing a 'get' or a 'set' method for the part in one of the program's .beh files. You specify how a derived part is ccomputed by providing a 'get' method in one of your program's .beh files (some parts of demjava require you to specify a get method for every derived part...this may change in a future version). eg: In .cd: Class = Derived_Part . In .beh: Class { get derived_part (@ return new Derived_Part(...); @) } A get method simply provides a getter for the part, so a call to get_derived_part() would invoke it to get the part. You can also specify a 'set' method that will be called when set_derived_part() is called. In the set method the new object (in the example an object of class Derived_Part) will be bound to 'dest'. ** GNUmakefile.template changes to support derived methods Behavior files may now influence grammar generation, so there is no reason to generate code and grammar in separate passes. ** Display and Trace generic visitors Two more generic visitors: -displayvis ==> generates DisplayVisitor -tracevis ==> generates TraceVisitor (see the next changes section for a bit more info about generic visitors). "new DisplayVisitor(PrintStream out)" creates a visitor that displays the parts of the object being traversed as a tree. "new TraceVisitor(PrintStream out)" creates a visitor that traces before and after methods for every class and edge a traversal visits. ** fixed bug w/ universal traversal and extending external classes The universal traversal generated in relation to the generic visitors was producing bad code for a class that extended an external class, e.g. MyStack = *extends* Stack. This should now compile correctly with generic visitors. * Changes in 0.4.6, released 24 Mar 1997: ** generic visitors and the universal traversal Three generic visitors can be generated: -printvis ==> generates PrintVisitor -copyvis ==> generates CopyVisitor -equalvis ==> generates EqualVisitor If any of these are generated, an abstract UniversalVisitor will also be generated. To generate just the UniversalVisitor, use -univis. "new PrintVisitor(PrintStream out)" creates a visitor that prints syntax for every class and edge in the traversal. "new CopyVisitor(Class cl)" creates a visitor that copies every object in the traversal. Terminals are copies by reference. "cl" is the class of the root object. Use "get_copy()" to retrieve the copy after traversal. "new EqualVisitor(Object obj)" creates a visitor that compares every edge in the traversal with every edge in obj. Use "get_is_equal()" to retrieve the equality boolean after traversal. In addition, a special universal traversal named "universal_trv0" is generated that traverses every construction edge in every class. Its argument is a UniversalVisitor. Thanks to Geoff Hulten for these three visitors. ** terminal edge wrappers get called Wrappers on construction edges to terminal classes are invoked. For example, before -> Foo,x,int (@ total += dest; @) These are currently only generated in "to *" traversals. ** traversal methods have package scope Generated traversal methods of the form "foo_trv3" have package scope instead of public. Only the entry points are publicly accessible. ** "this." to prevent name clashes Generated traversal methods use "this." to refer to parts, to prevent conflicts with visitor argument names. ** Text.begin, Text.end, Text.quoted_end Final static String members on Text: begin = "(@" end = "@)" quoted_end = "\"@\" + \")\"" * Changes in 0.4.5, released 20 Mar 1997 ** multiple behavior files The command line argument interface has changed slightly. Instead of demjava program use demjava program.cd program.beh You can also have more than one behavior file, e.g. demjava program.cd program1.beh program2.beh program3.beh The behavior files will simply be concatenated before compiling. ** better file error handling A nicer error message is printed if any of the input files do not exist or are unreadable, or if the output directory is not writable. Also, if the output directory does not exist, it will be created automatically. ** compatibility with JavaCC The generated grammar file is called "grammar.jj" to comply with JavaCC's ".jj" naming convention. ** GNUmakefile.template changes Various changes to support the above three changes. ** init methods In the behavior file, you can specify an init method for a class: Foo { init (@ System.out.println("new Foo"); @) } This becomes a constructor with no arguments. The constructor has default scope (i.e. package). ** multiple construction edge wrappers You may now have multiple construction edge wrappers with the same source and dest in a single visitor, e.g. Visitor { before -> *,a,* (@ ... @) before -> *,b,* (@ ... @) } Previously, this didn't work because both were generated as before(Object source, String edge, Object dest) Now, they are generated as before__a(Object source, Object dest) before__b(Object source, Object dest) Note the "edge" argument is now only available with construction edge wrappers that use a wildcard for the part name. ** JDK 1.1 compatibility The use of StringBufferInputStream for parsing from strings caused deprecation warnings with javac 1.1. Instead, we now use ByteArrayInputStream. (We can't use StringReader because JavaCC doesn't yet support Readers.) Also, demjava now uses PrintWriter internally, so it will not work without 1.1 classes. However, demjava-generated code will still work with 1.0.2. * Changes in 0.4.4, released 5 Mar 1997: ** bypassing classes When a traversal bypasses a class, it now bypasses all incoming edges to that class. Previously it was bypassing outgoing edges, which was incorrect. ** fixed wrapper call bugs In some traversals involving alternation classes, a wrapper method (before or after) was being called multiple times, being called in the wrong order, or not being called at all. This no longer happens: each wrapper method on an object's class or ancestors is called once for each object, and the order in which they are called obeys the prefix-super-sub and suffix-sub-super rules (see p. 258 in the Demeter book). ** prematurely terminated paths A traversal that enters an object whose class is not in the path will now be terminated, rather than continuing. ** fixed file descriptor leak Running demjava for the second time on a large cd file would cause demjava to run out of file descriptors, because it wasn't closing the diff streams. It now closes them. * Changes in 0.4.3, released 23 Feb 1997: ** part initializers A class part (in a .cd file) may have a default initializer using the following syntax: float *init* (@ 23.45 @) The text inside (@ @) may be any Java expression that can be used as an initializer for a data member of the given type. ** one .java file per class Rather than create one large program.java file, a classname.java file is created for every class in program.cd. This follows the Java standard style, and is required for public classes (and even package classes, with javac 1.1). ** timestamp preservation For every output file, if there already exists a file of the same name with the exact same contents, demjava does not overwrite the old file, so as to preserve the timestamp for the benefit of programs like make. ** new -outputdir command-line option Specifies where to put the output files. Default is the gen/ directory. ** GNUmakefile.template changes The GNUmakefile.template (which is copied into the user's directory with j-gen-make) now supports the above three features to minimize recompilation. ** class keywords *public* and *final* A class definition (in a .cd file) may be preceded by the tokens *public* and/or *final*; these have the same meaning as they do in Java. Just don't try to make an alternation class *final*! ** part keywords *static*, *final*, *read-only*, and *private* A class part (in a .cd file) may be preceded by the tokens *static*, *final*, *read-only*, and *private* (before the part class, but after the part name, e.g. *static* Foo). *static* and *final* have the same meaning as they do in Java; *read-only* means that no mutator (set_foo) function will be generated, and *private* means that no accessor (set_foo and get_foo) functions will be generated. [Actually, they are generated, but they have package scope rather than public.] ** new -version command-line option Prints the current version number. ** nonzero return code on error When demjava exits with an error, the return code is nonzero, for the benefit of programs like make. ** improved error handling Top-level syntax errors in .cd or .beh files are now reported. (Accomplished via the *EOF* token in demjava.cd -- see below.) ** new *EOF* token A class definition may end with the *EOF* token. This causes the parser to ensure that the object sentence ends after parsing this class, throwing a ParseError otherwise. For example, Foo = "foo" *EOF* . Foo.parse("foo bar") will cause a ParseError to be thrown, rather than quietly succeeding without fully consuming the input string. ** parsing bug fixed Parsing a class whose parent has common parts now works. For example: Foo : Bar | Baz *common* Garply. Bar = "bar". Baz = "baz". Garply = "garply". Previously, Bar.parse("bar garply") would result in a Bar object whose garply field was null. ** added CHANGES file You're looking at it! * History does not report changes previous to 0.4.3. * 0.4.2, released 14 Feb 1997 * 0.4.1, released 10 Feb 1997 * 0.4, released 22 Jan 1997 * RCS id: $Id: CHANGES,v 1.153 2003/01/31 01:05:05 dougo Exp $