package org.kohsuke.bali.automaton; import java.util.Collection; import com.sun.msv.grammar.*; import com.sun.msv.grammar.util.NameClassSimplifier; /** * A transition with a non-existent attribute alphabet can be taken * only when none of the current attribute matches the set of * names contained * * @author Kohsuke Kawaguchi (kk@kohsuke.org) */ public class NonExistentAttributeAlphabet extends Alphabet { // attributes with these names are not allowed public final NameSignature[] negativeNameTests; // with the exception of these names public final NameSignature[] positiveNameTests; /** * Exact representation of the above semantics as one name class. * Used just for debugging. */ private final NameClass exactName; public NonExistentAttributeAlphabet( Collection neg, Collection pos ) { this((NameSignature[]) neg.toArray(new NameSignature[neg.size()]), (NameSignature[]) pos.toArray(new NameSignature[pos.size()])); } public NonExistentAttributeAlphabet( NameSignature[] neg, NameSignature[] pos ) { this.negativeNameTests = neg; this.positiveNameTests = pos; NameClass n = new NotNameClass(AnyNameClass.theInstance); for( int i=0; i<neg.length; i++ ) n = new ChoiceNameClass( n, neg[i].nameClass ); for( int i=0; i<pos.length; i++ ) n = new DifferenceNameClass( n, pos[i].nameClass ); exactName = NameClassSimplifier.simplify(n); } /** * Checks if the given attribute name is prohibited by this alphabet. */ public boolean accepts( int nameCode ) { for( int i=positiveNameTests.length-1; i>=0; i-- ) if( positiveNameTests[i].accepts(nameCode) ) return false; for( int i=negativeNameTests.length-1; i>=0; i-- ) if( negativeNameTests[i].accepts(nameCode) ) return true; // prohibited return false; // otherwise OK } public Object accept( AlphabetVisitor visitor ) { return visitor.nonExistentAttribute(this); } public String toString() { return "!@"+exactName.toString(); } public boolean isPersistent() { return false; } }