// cd.beh -- behavior for creating & manipulating class dictionaries // $Id: cd.beh,v 1.12 2003/01/22 20:34:32 dougo Exp $ ClassGraph { /** Read a class dictionary from a reader and normalize it. */ public static ClassGraph readFrom(Reader in) throws ParseException {{ return parse(in).normalize(); }} /** Read a class dictionary from a char stream and normalize it. */ public static ClassGraph readFrom(InputStream in) throws ParseException {{ return parse(in).normalize(); }} /** Convert a string to a class dictionary and normalize it. */ public static ClassGraph fromString(String s) {{ return parse(s).normalize(); }} /** Convert the class graph to a simpler form by various transformations. */ public ClassGraph normalize() {{ ClassGraph cg; // Build the hash table of class defs for constant-time lookup. buildClassDefTable(); // Expand parameterized classes and remove their definitions. cg = expandParamDefs(); // Convert repetition classes to two linked-list construction classes. // cg.convertRepetition(); // Fill in missing partnames by lowercasing the type. cg.fillInPartNames(); // Add an inheritance edge for each alternation edge. cg.setInheritanceLinks(); // Fill in the two-way associations and incident-edges tables. cg.setBackLinks(); return cg; }} /** Make sure there is a vertex labeled l. If it doesn't exist, add it as a construction class; it will be changed to an alternation class later if alternation edges are added. */ ClassDef findOrAddClassDef(String l) {{ ClassDef def = findClassDef(l); if (def == null) { // doesn't work for qualified names... // def = ClassDef.parse(name + " = ."); def = ClassDef.parse("foo = ."); def.set_classname(ClassName.parse(l)); addClassDef(def); } return def; }} /** Add a construction edge named name from the vertex labeled source to the vertex labeled target. Return the new Part object. */ public Part addConstructionEdge(String source, String name, String target) {{ ClassDef srcdef = findOrAddClassDef(source); addNode(target); Part edge = Part.parse("<" + name + "> " + target); edge.def = srcdef; srcdef.addPart(edge); addOutgoingEdge(source, edge); addIncomingEdge(target, edge); return edge; }} /** Add an alternation edge from the vertex labeled source to the vertex labeled target. Return the new Subclass object. */ public Subclass addAlternationEdge(String source, String target) {{ ClassDef srcdef = findOrAddClassDef(source); if (srcdef.isConstructionClass()) { // Whoops, make it an alternation class. This is probably not // very adaptive. ConstructionClass cc = (ConstructionClass) srcdef.get_classparts(); AlternationClass ac = AlternationClass.parse(": common"); ac.set_parts(cc.get_parts()); ac.set_parents(cc.get_parents()); srcdef.set_classparts(ac); } findOrAddClassDef(target); addNode(target); Subclass edge = Subclass.parse(target); edge.def = srcdef; srcdef.addAlternation(edge); addOutgoingEdge(source, edge); addIncomingEdge(target, edge); return edge; }} /** Add an inheritance edge from the vertex labeled source to the vertex labeled target. Return the new Superclass or Interface object. */ public EdgeI addInheritanceEdge(String source, String target) {{ ClassDef srcdef = findOrAddClassDef(source); addNode(target); EdgeI edge; if (srcdef.isInterface() || srcdef.get_superclass_name() == null) { Superclass sup = Superclass.parse(target); sup.def = srcdef; srcdef.addSuperclass(sup); edge = sup; } else { // Assume the superclass was added first, and that this is an // interface. Interface inf = Interface.parse(target); inf.def = srcdef; srcdef.addInterface(inf); edge = inf; } addOutgoingEdge(source, edge); addIncomingEdge(target, edge); return edge; }} /** Add an edge. Return the EdgeI object that was added (which might not be the same object as edge). */ public EdgeI addEdge(EdgeI edge) {{ String source = edge.getSource().toString(); String target = edge.getTarget().toString(); EdgeI ret; if (edge.isConstructionEdge()) ret = addConstructionEdge(source, edge.getLabel(), target); else if (edge.isAlternationEdge()) ret = addAlternationEdge(source, target); else if (edge.isInheritanceEdge()) ret = addInheritanceEdge(source, target); else throw new RuntimeException("Unknown edge type: " + edge); return ret; }} } ClassDef { void addPart(Part part) to PartOrSyntax_List { before PartOrSyntax_List {{ host.addElement(part); }} } void addAlternation(Subclass subclass) to Subclass_Barlist { before AlternationClass {{ if (host.get_subclasses() == null) host.set_subclasses(new Subclass_Barlist()); }} before Subclass_Barlist {{ host.addElement(subclass); }} } void addSuperclass(Superclass superclass) to Superclass_Commalist { {{ ClassName child_name; boolean isInterface; }} before ClassDef {{ child_name = host.get_classname(); isInterface = host.isInterface(); superclass.def = host; }} {{ Superclass_Commalist parents; }} before Superclass_Commalist {{ parents = host; }} after ClassParents {{ if (parents == null) { Superclasses sup = Superclasses.parse("extends foo"); sup.set_superclasses(parents = new Superclass_Commalist()); host.set_superclasses(sup); } if (parents.contains(superclass)) { // It's already there, do nothing. } else if (isInterface || parents.isEmpty()) { parents.addElement(superclass); } else { System.err.println( "Error: class " + child_name + " cannot have more than one parent: " + superclass + " (previous parent: " + parents + ")"); } }} } void addInterface(Interface interf) to Interface_Commalist { {{ Interface_Commalist interfaces; }} before Interface_Commalist {{ interfaces = host; }} after ClassParents {{ if (interfaces == null) { Interfaces ifs = Interfaces.parse("implements foo"); ifs.set_interfaces(interfaces = new Interface_Commalist()); host.set_interfaces(ifs); } if (interfaces.contains(interf)) { // It's already there, do nothing. } else { interfaces.addElement(interf); } }} } } ClassGraph { /** Print the class dictionary corresponding to the subgraph determined by the traversal. */ public void printTraversalEdges(Traversal t, PrintWriter out) {{ Iterator nodes = t.getNodeSets().iterator(); while (nodes.hasNext()) { Object node = ((Traversal.NodeSet) nodes.next()).getNode(); ClassDef def = findClassDef((String) node); if (def != null) def.printTraversalEdges(t, out); } }} } ClassDef { void printTraversalEdges(Traversal t, PrintWriter out) to { ConstructionClass, AlternationClass, CommonKeyword, Part, Subclass, Superclass } { {{ ClassName source; }} before ClassDef {{ source = host.get_classname(); out.print(source + " "); }} before ConstructionClass {{ out.print("= "); }} {{ boolean need_bar; }} before AlternationClass {{ out.print(": "); need_bar = false; }} before CommonKeyword {{ out.print(host + " "); }} {{ boolean in_opt; }} before OptionalPart {{ in_opt = true; }} after OptionalPart {{ in_opt = false; }} before Part {{ if (t.getEdgeSet(host) != null) { if (in_opt) out.print("[ "); out.print(host + " "); if (in_opt) out.print("] "); } }} before Subclass {{ if (t.getEdgeSet(host) != null) { if (need_bar) { out.print("| "); } else { need_bar = true; } out.print(host + " "); } }} before Superclass {{ if (t.getEdgeSet(host) != null) { out.print("extends " + host); } }} after ClassDef {{ out.println("."); }} finish {{ out.flush(); }} } } Main { /** Testing stub. */ public static void main(String args[]) {{ InputStream in = System.in; // BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); try { ClassGraph cg = ClassGraph.readFrom(in); System.out.println(cg); } catch (ParseException e) { System.err.println(e.getMessage()); } }} }