// utils.beh -- Utility traversals and functions // $Id: utils.beh,v 1.11 2002/07/26 05:28:34 dougo Exp $ Program { (@ private static Hashtable checksums; private static File output, old; private static Vector javaFiles = new Vector(); private static Checksum ck; @) /** Read in the checksum list from the file. */ static void readChecksums(File file) (@ try { checksums = (Hashtable) (new ObjectInputStream(new FileInputStream(file))).readObject(); } catch (IOException e) { checksums = new Hashtable(); } catch (ClassNotFoundException e) { throw new RuntimeException(e.toString()); } @) /** Write the current checksum list to the file. */ static void writeChecksums(File file) (@ try { (new ObjectOutputStream(new FileOutputStream(file))) .writeObject(checksums); } catch (IOException e) { throw new RuntimeException(e.toString()); } @) /** Open the file, setting Program.out to the stream. */ static void openOutputFile(File file) (@ output = file; old = new File(output + "~"); if (output.exists()) output.renameTo(old); try { ck = new /* CRC32 */ Adler32(); out = new PrintWriter (new CheckedOutputStream(new FileOutputStream(output), ck)); } catch (IOException e) { throw new RuntimeException(e.toString()); } @) /** Close and flush the current output file. If the file hasn't changed, move the old one back so the timestamp doesn't change. */ static void closeOutputFile() (@ out.flush(); out.close(); Long oldck = (Long) checksums.get(output); // System.err.println(output + ": " + ck.getValue() + " " + // old + ": " + oldck); if (oldck != null && oldck.longValue() == ck.getValue() && old.exists()) { output.delete(); // not needed on Unix, but it is on Windows... old.renameTo(output); } else { checksums.put(output, new Long(ck.getValue())); old.delete(); } @) /** Open a file for writing Java source code. */ static void openJavaOutputFile(ClassName c) (@ File f = new File(gendir, c + ".java"); openOutputFile(f); javaFiles.addElement(f); @) /** Close the current Java source code file. */ static void closeJavaOutputFile() (@ closeOutputFile(); @) } Program { traversal toAll(UniversalVisitor v) { bypassing { Hashtable } to *; } } ClassNameAccessor { before ClassSpec (@ @) before ParamClassName (@ @) before ClassName (@ @) } ClassDef { traversal toClassName(ClassNameAccessor v) { bypassing { ClassParts, ClassMethods, -> *,parameters,* } to ClassName; } } { Subclass, Superclass, Part, RepeatedPart } { traversal toClassName(ClassNameAccessor v) { bypassing { -> *,actual_parameters,* } to ClassName; } } { ClassDef, Subclass, Superclass, Part, RepeatedPart } { ClassName get_classname() = toClassName { before ClassName (@ return_val = host; @) } } { ClassDef, Part, RepeatedPart } { void set_classname(ClassName classname) = toClassName { before { ParamClassName, ClassSpec } (@ host.set_classname(classname); @) } } ClassDef { ClassName_Commalist get_parameters() via ParamClassName to ClassName_Commalist { before ClassName_Commalist (@ return_val = host; @) } } { Program, ClassGraph } { traversal allClassDefs(ClassDefVisitor v) { to ClassDef; } } ClassDefVisitor { before { ClassGraph, ClassDef } (@ @) after { ClassGraph } (@ @) } Program { // These need to be fixed if we have multiple classgraphs... void buildClassDefTable() (@ cg.buildClassDefTable(); @) ClassDef findClassDef(ClassName name) (@ return cg.findClassDef(name); @) boolean definesClass(ClassName name) (@ return cg.definesClass(name); @) void addClassDef(ClassDef def) (@ cg.addClassDef(def); @) void addClassGraphEntry(ClassGraphEntry cge) (@ cg.addClassGraphEntry(cge);@) Enumeration classnames() (@ return cg.classnames(); @) Enumeration classdefs() (@ return cg.classdefs(); @) } ClassGraph { init (@ defdict = new Hashtable(); classes = new ClassGraphEntry_DList(); @) void buildClassDefTable() = allClassDefs { (@ Hashtable defdict; @) before ClassGraph (@ defdict = new Hashtable(); @) before ClassDef (@ defdict.put(host.get_classname(), host); @) after ClassGraph (@ host.set_defdict(defdict); @) } ClassDef findClassDef(ClassName name) (@ return (ClassDef) defdict.get(name); @) boolean definesClass(ClassName name) (@ return findClassDef(name) != null; @) void addClassGraphEntry(ClassGraphEntry cge) (@ classes.addElement(cge); @) void addClassDef(ClassDef def) (@ defdict.put(def.get_classname(), def); addClassGraphEntry(def); @) Enumeration classnames() (@ return defdict.keys(); @) Enumeration classdefs() (@ return defdict.elements(); @) } ClassDef { ClassName getPartClass(PartName name) (@ Part thePart = getPartFromPartName(name); return (thePart == null ? null : thePart.get_classname()); @) Part getPartFromPartName(PartName name) // via ClassParts via { ConstructionClass, AlternationClass } to PartName { (@ boolean isPart; @) before PartName (@ isPart = host.equals(name); @) after Part (@ if (isPart) return_val = host; @) } } Part { boolean isTerminal() (@ ClassDef def = Program.prog.findClassDef(get_classname()); return def == null || def.isInterface(); @) String makeWrapper(ClassName source, String body) (@ return new PartGlob(source, get_partname(), get_classname()) + " " + Text.begin + body + Text.end; @) String makeBefore(ClassName source, String body) (@ return " before " + makeWrapper(source, "\n" + body + " "); @) String makeAfter(ClassName source, String body) (@ return " after " + makeWrapper(source, "\n" + body + " "); @) } ClassName { String makeWrapper(String body) (@ return this + " " + Text.begin + body + Text.end; @) String makeBefore(String body) (@ return " before " + makeWrapper("\n" + body + " "); @) String makeAfter(String body) (@ return " after " + makeWrapper("\n" + body + " "); @) } ClassName { (@ private static String builtinTypes[] = { "boolean", "char", "byte", "short", "int", "long", "float", "double" }; private static String terminalClasses[] = { // from java.lang.*: "Boolean", "Character", "Integer", "Long", "Float", "Double", "Number", "String", "StringBuffer", // from demeter.*: "Ident", "Text", "Line", "Word" }; @) boolean isBuiltinType() (@ String s = toString(); for (int i = 0; i < builtinTypes.length; i++) { if (builtinTypes[i].equals(s)) return true; } return false; @) boolean isTerminalClass() (@ String s = toString(); for (int i = 0; i < terminalClasses.length; i++) { if (terminalClasses[i].equals(s)) return true; } return false; @) boolean isKnownTerminal() (@ return isBuiltinType() || isTerminalClass(); @) } { Program, ClassDef } { traversal allParts(PartVisitor v) { to { Part, RepeatedPart }; } } PartVisitor { before { Program, ClassDef, Part, RepeatedPart } (@ @) around ClassDef (@ subtraversal.apply(); @) after { Program, ClassDef, Part, RepeatedPart } (@ @) } ClassDef { void addMethod(String signature, String body) (@ String method = signature + " {"; if (body.indexOf('\n') != -1) method += "\n"; method += body + " }\n"; addMethod(method); @) void addMethod(StringBuffer method_text) (@ addMethod(method_text.toString()); @) void addMethod(String method_text) (@ addMethod(new Verbatim(new JavaCode(new Text(method_text)))); @) void addMethod(Method method) to-stop Method_SList { before ClassDef (@ if (host.get_classmethods() == null) host.set_classmethods(new ClassMethods()); @) before ClassMethods (@ if (host.get_methods() == null) host.set_methods(new Method_SList()); @) before Method_SList (@ host.addElement(method); @) } } ClassDef { boolean hasNoArgConstructor() to Constructor { before Constructor (@ return_val = true; @) } } { Program, ClassDef } { traversal allEdges(EdgeVisitor v) { to { Part, Subclass, Superclass }; } } EdgeVisitor { before Program (@ @) around ClassDef (@ subtraversal.apply(); @) before { Part, Subclass, Superclass } (@ @) before { ClassGraph, ConstOrAltClass, ConstructionClass, AlternationClass, ClassParents, OptionalPart, ClassDef } (@ @) after { Part, Subclass, Superclass, ConstructionClass, ClassDef, OptionalPart } (@ @) } TraversalParms { traversal allVisitorNames(VisitorNameVisitor v) { to VisitorName; } } VisitorNameVisitor { before { Visitor, VisitorName } (@ @) after Visitor (@ @) } VisitorClass { (@ static VisitorClass instance = new VisitorClassWithoutStars(); @) } NotParsedClass { (@ static NotParsedClass instance = new NotParsedClassWithoutStars(); @) } DerivedPart { (@ static DerivedPart instance = new DerivedPartWithoutStars(); @) } ClassDef { boolean isConstructionClass() (@ return getClassType().get_is_con(); @) boolean isAlternationClass() (@ return getClassType().get_is_alt(); @) boolean isRepetitionClass() (@ return getClassType().get_is_rep(); @) boolean isPublic() (@ return getClassType().get_is_public(); @) boolean isFinal() (@ return getClassType().get_is_final(); @) boolean isInterface() (@ return getClassType().get_is_interface(); @) boolean isNotParsed() (@ return getClassType().get_is_not_parsed();@) boolean isVisitor() (@ return getClassType().get_is_visitor(); @) ClassType getClassType() to { ConstructionClass, AlternationClass, RepetitionClass, PublicClass, FinalClass, InterfaceClass, VisitorClass, NotParsedClass } { init (@ return_val = new ClassType(); @) before ConstructionClass (@ return_val.set_is_con(true); @) before AlternationClass (@ return_val.set_is_alt(true); @) before RepetitionClass (@ return_val.set_is_rep(true); @) before PublicClass (@ return_val.set_is_public(true); @) before FinalClass (@ return_val.set_is_final(true); @) before InterfaceClass (@ return_val.set_is_interface(true); @) before VisitorClass (@ return_val.set_is_visitor(true); @) before NotParsedClass (@ return_val.set_is_not_parsed(true); @) } void markVisitor() (@ if (keywords == null) keywords = new ClassKeyword_NList(); keywords.addElement(VisitorClass.instance); @) void markNotParsed() (@ if (keywords == null) keywords = new ClassKeyword_NList(); keywords.addElement(NotParsedClass.instance); @) } Part { boolean isFinal() (@ return getPartType().get_is_final(); @) boolean isStatic() (@ return getPartType().get_is_static(); @) boolean isDerived() (@ return getPartType().get_is_derived(); @) boolean hasGetter() (@ return getPartType().get_has_getter(); @) boolean hasSetter() (@ return getPartType().get_has_setter(); @) PartType getPartType() to { FinalPart, StaticPart, ReadOnlyPart, PrivatePart, DerivedPart } { init (@ return_val = new PartType(); return_val.set_has_getter(true); return_val.set_has_setter(true); @) before FinalPart (@ return_val.set_is_final(true); return_val.set_has_setter(false); @) before StaticPart (@ return_val.set_is_static(true); @) before PrivatePart (@ return_val.set_has_getter(false); return_val.set_has_setter(false); @) before ReadOnlyPart (@ return_val.set_has_setter(false); @) before DerivedPart (@ return_val.set_is_derived(true); @) } void markDerived() (@ if (keywords == null) keywords = new PartKeyword_NList(); keywords.addElement(DerivedPart.instance); @) } JavaType { boolean isVoid() (@ return toString().equals("void"); @) } ClassName { boolean isA(ClassName ancestor) (@ if (this.equals(ancestor)) return true; ClassDef def = Program.prog.findClassDef(this); if (def != null) { ClassName sup = def.get_superclass_name(); if (sup != null) return sup.isA(ancestor); } return false; @) } ClassDef { ClassDef get_superclass_def() (@ ClassName super_name = get_superclass_name(); return super_name == null ? null : Program.prog.findClassDef(super_name); @) ClassName get_superclass_name() via Superclass to ClassName { before ClassName (@ return_val = host; @) } } // Some utility constructors. { Start, Finish } { init (@ javacode = new JavaCode(); @) } JavaCode { init (@ code = new Text(); @) } PlainSyntax { /** Convert special chars to escaped strings. */ public String toString() {{ StringBuffer sb = new StringBuffer(string); for (int i = sb.length() - 1; i >= 0; i--) { char c = sb.charAt(i); String s = null; if (c > 0x7F) { if (c > 0xFFF) s = "\\u" + Integer.toHexString(c); else if (c > 0xFF) s = "\\u0" + Integer.toHexString(c); else s = "\\" + Integer.toOctalString(c); } else switch (c) { case '\n': s = "\\n"; break; case '\t': s = "\\t"; break; case '\b': s = "\\b"; break; case '\r': s = "\\r"; break; case '\f': s = "\\f"; break; case '\\': s = "\\\\"; break; case '\"': s = "\\\""; break; default: break; } if (s != null) sb.replace(i, i+1, s); } return "\"" + sb + "\""; }} } //////////////////////////////////////////////////////////////// // Everything below here ought to be automatically generated... //////////////////////////////////////////////// // String representations. ParseIdent { public String toString() (@ return "parse"; @) } NoParseIdent { public String toString() (@ return "noparse"; @) } VisitorsIdent { public String toString() (@ return "visitors"; @) } EndVisitorsIdent{ public String toString() (@ return "endvisitors"; @) } VisitorIdent { public String toString() (@ return "visitor"; @) } NotParsedIdent { public String toString() (@ return "notparsed"; @) } DerivedIdent { public String toString() (@ return "derived"; @) } InitIdent { public String toString() (@ return "init"; @) } CommonIdent { public String toString() (@ return "common"; @) } LookaheadIdent { public String toString() (@ return "lookahead"; @) } StrategyIdent { public String toString() (@ return "strategy"; @) } WithIdent { public String toString() (@ return "with"; @) } ThroughIdent { public String toString() (@ return "through"; @) } ViaIdent { public String toString() (@ return "via"; @) } BypassingIdent { public String toString() (@ return "bypassing"; @) } ToIdent { public String toString() (@ return "to"; @) } DoIdent { public String toString() (@ return "do"; @) } JoinIdent { public String toString() (@ return "join"; @) } MergeIdent { public String toString() (@ return "merge"; @) } IntersectIdent { public String toString() (@ return "intersect"; @) } TraversalIdent { public String toString() (@ return "traversal"; @) } BeforeIdent { public String toString() (@ return "before"; @) } AroundIdent { public String toString() (@ return "around"; @) } AfterIdent { public String toString() (@ return "after"; @) } GetIdent { public String toString() (@ return "get"; @) } SetIdent { public String toString() (@ return "set"; @) } StartIdent { public String toString() (@ return "start"; @) } FinishIdent { public String toString() (@ return "finish"; @) } OtherIdent { public String toString() (@ return id.toString(); @) } CommonWithStars { public String toString() (@ return Line.nl + "\t\t\t*common* "; @) } CommonWithoutStars { public String toString() (@ return Line.nl + "\t\t\tcommon "; @) } { PackageName, Name } { public String toString() (@ return first.toString(); @) } { Nonempty_PackageName, Nonempty_Name } { public String toString() (@ return it + (next == null ? "" : "." + next); @) } { ClassName, PartName, TraversalName, VisitorName, MethodName, ParmName, StrategyName } { public String toString() (@ return name.toString(); @) } TraversalMethodName { public String toString() (@ return methodname.toString(); @) } { Subclass, Superclass, Interface } { public String toString() (@ return classspec.toString(); @) } ClassSpec { public String toString() (@ return classname.toString(); @) } VisitorSpec { public String toString() (@ return methods.toString(); @) } JavaType { public String toString() (@ return type.toString(); @) } JavaCode { public String toString() (@ return Text.begin + code + Text.end; @)} PrintIndent { public String toString() (@ return "+"; @) } PrintUnindent { public String toString() (@ return "-"; @) } PrintSkip { public String toString() (@ return "*l"; @) } PrintSpace { public String toString() (@ return "*s"; @) } LocalLookahead{ public String toString() (@ return "*lookahead* "+javacode; @)} { ClassName_Commalist, Superclass_Commalist, Interface_Commalist, Glob_Commalist, ClassGlob_Commalist, Visitor_Commalist } { public String toString() (@ return (first == null ? "" : first.toString()); @) } { Nonempty_ClassName_Commalist, Nonempty_Interface_Commalist, Nonempty_Superclass_Commalist, Nonempty_Glob_Commalist, Nonempty_ClassGlob_Commalist, Nonempty_Visitor_Commalist } { public String toString() (@ return it + (next == null ? "" : ", " + next); @) } { ClassGlobSet, GlobSet } { public String toString() (@ return "{ " + (globs == null ? "" : globs.toString()) + " }"; @) } OneGlob { public String toString() (@ return glob.toString(); @) } OneClassGlob { public String toString() (@ return classglob.toString(); @) } ClassNameExact { public String toString() (@ return classname.toString(); @) } PartNameExact { public String toString() (@ return partname.toString(); @) } { AnyClass, AnyPart } { public String toString() (@ return "*"; @) } TraversalParms { public String toString() (@ return "(" + visitors + ")"; @) } TraversalRef { public String toString() (@ return (equals == null ? "" : "= ") + name; @) } Visitor { public String toString() (@ return classname + " " + visitorname; @) } VisitorRef { public String toString() (@ return "(" + visitorClasses + ");"; @) } { ClassGlob, SourceGlob, DestGlob } { public String toString() (@ return name.toString(); @) } PartGlob { public String toString() (@ return "-> " + source + ", " + name + ", " + dest; @) } SubclassGlob { public String toString() (@ return "=> " + source + ", " + dest; @) } SuperclassGlob { public String toString() (@ return ":> " + source + ", " + dest; @) } Before { public String toString() (@ return "before"; @) } Around { public String toString() (@ return "around"; @) } After { public String toString() (@ return "after"; @) } ClassMethods { public String toString() (@ return "{\n" + (methods == null ? "" : methods.toString()) + "\n}"; @) } { PackageDirective, Package, GlobalImports, Import, Method_SList, StrategyExpression, StrategyGraph, MethodSignature, Part } { public String toString() (@ StringWriter w = new StringWriter(); PrintWriter pw = new PrintWriter(w); toAll(new PrintVisitor(pw)); pw.flush(); return w.toString(); @) traversal toAll(UniversalVisitor v) { bypassing { Vector, Hashtable } to *; } } //////////////////////////////////////////////// // Equality predicates. { ClassName, PartName, TraversalName, Glob, WrapperKind, Superclass, Name, IdentOrKeyword, ClassGlobSpec } { public boolean equals(Object obj) (@ return toString().equals(obj.toString()); /* EqualVisitor eq = new EqualVisitor(obj); toAll(eq); // universal_trv0(eq); return eq.get_is_equal(); */ @) // traversal toAll(UniversalVisitor v) { to *; } } //////////////////////////////////////////////// // Deep copying functions. ClassDef { ClassDef deepCopy() (@ CopyVisitor c = new CopyVisitor(getClass()); toAll(c); // universal_trv0(c); return (ClassDef) c.get_copy(); @) traversal toAll(UniversalVisitor v) { bypassing ClassMethods to *; } } ClassMethods { ClassMethods deepCopy() (@ CopyVisitor c = new CopyVisitor(getClass()); toAll(c); return (ClassMethods) c.get_copy(); @) traversal toAll(UniversalVisitor v) { bypassing Hashtable to *; } } GlobSpec { GlobSpec deepCopy() (@ CopyVisitor c = new CopyVisitor(getClass()); universal_trv0(c); return (GlobSpec) c.get_copy(); @) } //////////////////////////////////////////////// // Hash code functions. { PackageName, ClassName, PartName, TraversalName, VisitorName, MethodName, StrategyName, Glob, WrapperKind, Name, IdentOrKeyword } { public int hashCode() (@ return toString().hashCode(); @) } //////////////////////////////////////////////// // List functions. ClassName_Commalist { /** The index of name in the list, or -1 if it's not in the list. */ public int indexOf(ClassName name) (@ Enumeration e = elements(); int i = 0; while (e.hasMoreElements()) { if (((ClassName) e.nextElement()).equals(name)) return i; i++; } return -1; @) } ClassSpec_Commalist { /** The ith element in the list, or null if the list isn't that long. */ public ClassSpec elementAt(int i) (@ Enumeration e = elements(); while (e.hasMoreElements()) { ClassSpec spec = (ClassSpec) e.nextElement(); if (i == 0) return spec; i--; } return null; @) } TraversalParms { int size() (@ return visitors == null ? 0 : visitors.size(); @) Enumeration elements() (@ Visitor_Commalist l = (visitors == null ? new Visitor_Commalist() : visitors); return l.elements(); @) TraversalParms reverse() (@ Visitor_Commalist revvis = null; Enumeration e = elements(); if (e.hasMoreElements()) { revvis = new Visitor_Commalist(); while (e.hasMoreElements()) { Visitor v = (Visitor) e.nextElement(); revvis.push(v); } } return new TraversalParms(revvis); @) }