// glob.beh -- Glob matching and manipulation // $Id: glob.beh,v 1.3 2000/10/13 19:31:12 dougo Exp $ ClassGlobSpec { traversal allClassNames(ClassGlobVisitor v) { to { ClassName, AnyClass }; } } ClassGlobVisitor { before { ClassName, AnyClass } (@ @) } { GlobSpec, ClassGlobSpec } { boolean match(Glob glob) = allGlobs { before ClassGlob (@ if (glob instanceof ClassGlob && host.get_name().match(((ClassGlob) glob).get_name())) return_val = true; @) before PartGlob (@ if (glob instanceof PartGlob) { PartGlob pglob = (PartGlob) glob; if (host.get_source().match(pglob.get_source()) && host.get_name().match(pglob.get_name()) && host.get_dest().match(pglob.get_dest())) return_val = true; } @) before SubclassGlob (@ if (glob instanceof SubclassGlob) { SubclassGlob sglob = (SubclassGlob) glob; if (host.get_source().match(sglob.get_source()) && host.get_dest().match(sglob.get_dest())) return_val = true; } @) before SuperclassGlob (@ if (glob instanceof SuperclassGlob) { SuperclassGlob sglob = (SuperclassGlob) glob; if (host.get_source().match(sglob.get_source()) && host.get_dest().match(sglob.get_dest())) return_val = true; } @) } } ClassGlobSpec { traversal allGlobs(GlobVisitor v) { to ClassGlob; } /** Return true iff the globspec matches the class. */ boolean match(ClassName name) (@ return match(new ClassGlob(name)); @) } GlobSpec { traversal allGlobs(GlobVisitor v) { to { ClassGlob, PartGlob, SubclassGlob, SuperclassGlob }; } /** Return true iff the globspec matches the edge from source to part. */ boolean match(ClassName source, Part part) (@ return match(new PartGlob(source,part.get_partname(),part.get_classname())) || match(new ClassGlob(part.get_classname())); @) /** Return true iff the globspec matches the edge from source to sub. */ boolean match(ClassName source, Subclass sub) (@ return match(new SubclassGlob(source, sub.get_classname())) || match(new ClassGlob(sub.get_classname())); @) /** Return true iff the globspec matches the edge from source to sup. */ boolean match(ClassName source, Superclass sup) (@ return match(new SuperclassGlob(source, sup.get_classname())) || match(new ClassGlob(sup.get_classname())); @) /** Return true iff the globspec matches the edge. */ boolean match(Edge edge) (@ EdgeGlobMaker m = new EdgeGlobMaker(); edge.toAll(m); return match(m.get_return_val()) || match(new ClassGlob(m.get_d())); @) } EdgeGlobMaker { before -> Vertex,name,NameI (@ cl = (ClassName) dest; @) before -> CEdge,name,NameI (@ name = (PartName) dest; @) after -> Edge,source,Vertex (@ s = cl; @) after -> Edge,dest,Vertex (@ d = cl; @) after CEdge (@ return_val = new PartGlob(s, name, d); @) after AEdge (@ return_val = new SubclassGlob(s, d); @) after IEdge (@ return_val = new SuperclassGlob(s, d); @) } GlobVisitor { before { GlobSpec, ClassGlobSpec, Glob, ClassGlob, PartGlob, SubclassGlob, SuperclassGlob } (@ @) before { OneGlob, GlobSet, OneClassGlob, ClassGlobSet, EdgeGlob } {{ }} } SourceGlob { boolean match(SourceGlob glob) (@ return name.match(glob.name); @) } DestGlob { boolean match(DestGlob glob) (@ return name.match(glob.name); @) } ClassNameGlob { abstract boolean match(ClassNameGlob glob); } ClassNameGlob { abstract boolean match(ClassNameExact ex); } AnyClass { boolean match(ClassNameGlob glob) (@ return true; @) } AnyClass { boolean match(ClassNameExact ex) (@ return true; @) } ClassNameExact { boolean match(ClassNameGlob glob) (@ return glob.match(this); @) boolean match(ClassNameExact ex) (@ return classname.equals(ex.classname); @) } PartNameGlob { abstract boolean match(PartNameGlob glob); } PartNameGlob { abstract boolean match(PartNameExact ex); } AnyPart { boolean match(PartNameGlob glob) (@ return true; @) } AnyPart { boolean match(PartNameExact ex) (@ return true; @) } PartNameExact { boolean match(PartNameGlob glob) (@ return glob.match(this); @) boolean match(PartNameExact ex) (@ return partname.equals(ex.partname); @) } GlobSpec { /** Return a ClassGlobSpec that matches all the classes in the GlobSpec, or null if there are none. */ ClassGlobSet collectClassGlobs() to ClassGlob(ClassGlobCollector); /** Return a GlobSpec 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(new Glob_Commalist()); 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 @) } } ClassGlobCollector { before ClassGlob (@ if (return_val == null) return_val = new ClassGlobSet(new ClassGlob_Commalist()); return_val.addElement(host); @) } ClassGlobSpec { /** Convert a set of classes to a set of edges outgoing from the classes. */ GlobSet toOutgoingEdgeSpec() = allGlobs { before ClassGlobSpec (@ return_val = new GlobSet(); @) before ClassGlob (@ return_val.addElement(PartGlob.parse("-> " + host + ",*,*")); return_val.addElement(SubclassGlob.parse("=> " + host + ",*,*")); return_val.addElement(SuperclassGlob.parse(":> " + host + ",*,*")); @) } } Glob { void addToHostSet(HostSet hostset) (@ if (isExact()) hostset.addExactHost(this); else hostset.addGlob(this); @) /** An exact glob has no wildcards. */ boolean isExact() to { AnyClass, AnyPart } { init (@ return_val = true; @) before { AnyClass, AnyPart } (@ return_val = false; @) } /** A partname glob has an exact partname and no class wildcards. */ boolean isPartNameGlob() to { ClassNameExact, PartNameExact } { (@ boolean cne, pne; @) before ClassNameExact (@ cne = true; @) before PartNameExact (@ pne = true; @) return boolean (@ pne && !cne @) } /** Get the exact partname, assuming it's a partname glob. */ PartName get_partname() to PartName { before PartName (@ return_val = host; @) } } GlobSpec { /** Mutate the GlobSpec by mapping all names through nameMap. */ void mapNames(Dictionary nameMap) to { ClassName, PartName } { before -> ClassNameExact,classname,ClassName (@ source.set_classname((ClassName) nameMap.get(dest)); @) before -> PartNameExact,partname,PartName (@ NameI name = (NameI) nameMap.get(dest); // The name map might give us back a PartName or a ClassName... if (name instanceof PartName) { source.set_partname((PartName) dest); } else { source.set_partname(PartName.parse(name.toString())); } @) } } // 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); @) } // Constructors -- these should probably be generated automatically. ClassGlob { (@ public ClassGlob(ClassName name) { this(new ClassNameExact(name)); } @) } SourceGlob { (@ public SourceGlob(ClassName name) { this(new ClassNameExact(name)); } @) } DestGlob { (@ public DestGlob(ClassName name) { this(new ClassNameExact(name)); } @) } PartGlob { (@ public PartGlob(ClassName source, PartName name, ClassName dest) { this(new SourceGlob(source), new PartNameExact(name), new DestGlob(dest)); } @) } SubclassGlob { (@ public SubclassGlob(ClassName source, ClassName dest) { this(new SourceGlob(source), new DestGlob(dest)); } @) } SuperclassGlob { (@ public SuperclassGlob(ClassName source, ClassName dest) { this(new SourceGlob(source), new DestGlob(dest)); } @) }