// glob.beh -- Glob matching and manipulation // $Id: glob.beh,v 1.8 2002/01/04 17:01:40 dougo Exp $ GlobSpec { /** Does class graph edge e match with an edge glob in this set, using name map N? */ boolean match(EdgeI e, NameMapI N) {{ return matchEdge(e, N); }} // FIXME: Can't have multiple adaptive methods with the same name :( boolean matchEdge(EdgeI e, NameMapI N) bypassing ClassGlob to { ClassName, PartName } { {{ boolean edgeglob_matches; }} before EdgeGlob {{ edgeglob_matches = false; }} after EdgeGlob {{ if (edgeglob_matches) return_val = true; }} around PartGlob {{ if (e.isConstructionEdge()) { edgeglob_matches = true; subtraversal.apply(); } }} around SubclassGlob {{ if (e.isAlternationEdge()) { edgeglob_matches = true; subtraversal.apply(); } }} around SuperclassGlob {{ if (e.isInheritanceEdge()) { edgeglob_matches = true; subtraversal.apply(); } }} {{ Object v; String l; }} before SourceGlob {{ v = e.getSource(); }} before PartNameGlob {{ l = e.getLabel(); }} before TargetGlob {{ v = e.getTarget(); }} before ClassName {{ // There is no &&= in Java for some reason... if (edgeglob_matches) edgeglob_matches = host.match(v, N); }} before PartName {{ if (edgeglob_matches) edgeglob_matches = host.match(l, N); }} } } { GlobSpec, ClassGlobSpec } { /** Does the class graph node v match with a class glob in this set, using the name map N? */ boolean match(Object v, NameMapI N) via ClassGlob to { ClassName, AnyClass } { before ClassName {{ if (!return_val) return_val = host.match(v, N); }} before AnyClass {{ return_val = true; }} } } ClassName { /** Does class graph node v match this classname, with name map N? */ boolean match(Object v, NameMapI N) {{ String s = toString(); return N == null ? String.valueOf(v).equals(s) : N.match(s, v); }} } PartName { /** Does class graph edge label l match this partname, with name map N? */ boolean match(String l, NameMapI N) {{ String toMatch = toString(); return N == null ? l.equals(toMatch) : N.match(toMatch, l); }} } ClassGlobSpec { /** A collection of strings corresponding to the classes in the glob, after applying the name map N. Return null if wildcard. */ Collection map(SymbolicNameMapI N) to { ClassName, AnyClass } { {{ Collection c = new ArrayList(); }} before AnyClass {{ c = null; }} before ClassName {{ if (c != null) { String l = host.toString(); ClassGlobSpec cgNames = N.get(l); if (cgNames == null) c.add(l); else c = cgNames.addStrings(c); } }} return {{ c }} } /** Add all class names in the glob as strings to c, returning c or null if wildcard. */ Collection addStrings(Collection c) to { ClassName, AnyClass } { before AnyClass {{ c = null; }} before ClassName {{ if (c != null) c.add(host.toString()); }} return {{ c }} } /** A collection of class names in the glob as strings, or null if a wildcard. */ Collection getStrings() {{ return addStrings(new ArrayList()); }} } ClassGlobSpec { traversal allGlobs(GlobVisitor v) { to ClassGlob; } } GlobSpec { traversal allGlobs(GlobVisitor v) { to { ClassGlob, PartGlob, SubclassGlob, SuperclassGlob }; } } GlobVisitor { before { GlobSpec, ClassGlobSpec, Glob, ClassGlob, PartGlob, SubclassGlob, SuperclassGlob } {{ }} before { OneGlob, GlobSet, OneClassGlob, ClassGlobSet, EdgeGlob } {{ }} } GlobSpec { /** Return a ClassGlobSpec that matches all the classes in the GlobSpec, or null if there are none. */ ClassGlobSpec collectClassGlobs() to ClassGlob { {{ OneClassGlob one; ClassGlobSet set; }} before ClassGlob {{ if (one == null) { one = new OneClassGlob(host); } else { if (set == null) { set = new ClassGlobSet(new ClassGlob_Commalist()); set.addElement(one.get_classglob()); } if (!set.contains(host)) set.addElement(host); } }} return {{ one == null ? null : set == null ? (ClassGlobSpec) one : (ClassGlobSpec) set }} } /** Return a GlobSet that matches all the edges in the GlobSpec, or null if there are none. */ GlobSet collectEdgeGlobs() to EdgeGlob { before EdgeGlob {{ if (return_val == null) return_val = new GlobSet(); return_val.addElement(host); }} } /** Merge two glob specs into the union of the two. */ GlobSpec union(GlobSpec spec) {{ if (spec == null) return this; return spec.collectGlobs(collectGlobs(new GlobSet())); }} /** Destructively append all globs to the set, and return it. */ GlobSet collectGlobs(GlobSet globset) = allGlobs { before Glob {{ globset.addElement(host); }} return {{ globset }} } } ClassGlobSpec { GlobSpec toGlobSpec() = allGlobs { {{ OneGlob one; GlobSet set; }} before ClassGlob {{ if (one == null) { one = new OneGlob(host); } else { if (set == null) { set = new GlobSet(); set.addElement(one.get_glob()); } set.addElement(host); } }} return {{ one == null ? (GlobSpec) new GlobSet() : set == null ? (GlobSpec) one : (GlobSpec) set }} } } // Repetition utility functions -- these should probably be generated // automatically. ClassGlobSet { void addElement(ClassGlob glob) {{ globs.addElement(glob); }} } GlobSet { void addElement(Glob glob) {{ if (globs == null) globs = new Glob_Commalist(); globs.addElement(glob); }} } ClassGlobSpec { abstract Enumeration elements(); } ClassGlobSet { Enumeration elements() {{ return globs.elements(); }} } OneClassGlob { Enumeration elements() {{ return ClassGlobSet.parse("{" + classglob + "}").elements(); }} } ClassGlobSet { void setadd(ClassGlobSpec spec) {{ Enumeration e = spec.elements(); while (e.hasMoreElements()) { ClassGlob glob = (ClassGlob) e.nextElement(); if (!contains(glob)) addElement(glob); } }} boolean contains(ClassGlob glob) {{ return globs.contains(glob); }} }