package runtime;
import org.relaxng.datatype.Datatype;
import org.relaxng.datatype.ValidationContext;
/**
*
* Just a wrapper to enclose different types of transitions.
*
* @author Kohsuke Kawaguchi (kk@kohsuke.org)
*/
public abstract class Transition {
private Transition() {}
/** Transition by attribute. */
public final static class Att {
public Att( int mask, int test, boolean repeated, State.Single left, State.Single right, Att next ) {
this.mask = mask;
this.test = test;
this.repeated = repeated;
this.left = left;
this.right = right;
this.next = next;
}
/** Name signature. */
private final int mask,test;
/** True if this alphabet is of the form @X+. */
public final boolean repeated;
/** Left and right states. */
public final State.Single left,right;
/** Next transition of this kind, or null. */
public final Att next;
/** Returns true if this alphabet accets the given name code. */
public boolean accepts( int nameCode ) {
return (nameCode&mask)==test;
}
}
/** Transition by data. */
public final static class Data {
public Data( Datatype dt, State.Single left, State.Single right, Data next ) {
this.datatype=dt;
this.left=left;
this.right=right;
this.next=next;
}
/** Datatype object to validate. */
public final Datatype datatype;
/** Left and right states. */
public final State.Single left,right;
/** Next transition of this kind, or null. */
public final Data next;
}
/** Transition by attribute. */
public final static class Element {
public Element( int mask, int test, State.Single left, State.Single right, Element next ) {
this.mask = mask;
this.test = test;
this.left = left;
this.right = right;
this.next = next;
}
/** Name signature. */
public final int mask,test;
/** Left and right states. */
public final State.Single left,right;
/** Next transition of this kind, or null. */
public final Element next;
/** Returns true if this alphabet accets the given name code. */
public boolean accepts( int nameCode ) {
return (nameCode&mask)==test;
}
/** State that represents the head of the content model when no attribute is present. */
private State noAttContentHead = null;
protected State startElement( State result, AttributesSet attributes, StateFactory factory ) {
// e.left is very likely to be expandable, so don't bother
// use expandFast.
State s1;
if( attributes.size()==0 ) {
if( noAttContentHead!=null )
s1 = noAttContentHead;
else {
// create one. This needs to be synchronized because
// this object could be accessed simultaneously by many threads
synchronized(this) {
s1 = left.expand( attributes, State.emptySet, factory );
// the first if statement of "noAttContentHead!=null" is
// unsynchronized. There's a very small danger of two threads
// simultaneously entering the else clause.
if(noAttContentHead==null)
noAttContentHead = s1;
}
}
} else
s1 = left.expand( attributes, State.emptySet, factory );
State s2 = factory.makeAfter( s1, right );
return factory.makeChoice( result, s2 );
}
}
/** Transition by interleave. */
public final static class Interleave {
public Interleave( State.Single left, State.Single right, State.Single join, boolean textToLeft, Interleave next ) {
this.left = left;
this.right = right;
this.join = join;
this.next = next;
this.textToLeft = textToLeft;
}
/** Left and right states. */
public final State.Single left,right;
/** Join state. */
public final State.Single join;
/** True if text should be consumed by the left sub-automaton. */
public final boolean textToLeft;
/** Next transition of this kind, or null. */
public final Interleave next;
}
/** Transition by list. */
public final static class List {
public List( State.Single left, State.Single right, List next ) {
this.left = left;
this.right = right;
this.next = next;
}
/** Left and right states. */
public final State.Single left,right;
/** Next transition of this kind, or null. */
public final List next;
}
/** Transition by non-existent attribute. */
public final static class NoAtt {
public NoAtt( State.Single right, int[] negTests, int[] posTests, NoAtt next ) {
this.right = right;
this.negTests = negTests;
this.posTests = posTests;
this.next = next;
}
/** Right state. */
public final State.Single right;
/** Name tests. repeated (mask,test) pairs. */
private final int[] negTests, posTests;
/** Next transition of this kind, or null. */
public final NoAtt next;
public boolean accepts( int code ) {
for( int i=posTests.length-2; i>=0; i-=2 )
if( (code&posTests[i])==posTests[i+1] )
return false;
for( int i=negTests.length-2; i>=0; i-=2 )
if( (code&negTests[i])==negTests[i+1] )
return true;
return false;
}
}
/** Transition by value. */
public final static class Value {
public Value( Datatype dt, Object value, State.Single right, Value next ) {
this.datatype=dt;
this.value = value;
this.right=right;
this.next=next;
}
/** Datatype object to validate. */
private final Datatype datatype;
/** Value object to compare with. */
private final Object value;
public boolean accepts( String text, ValidationContext context ) {
Object o = datatype.createValue(text,context);
if(o==null) return false;
return datatype.sameValue(o,value);
}
/** Left and right states. */
public final State.Single right;
/** Next transition of this kind, or null. */
public final Value next;
}
}