package org.kohsuke.bali.optimizer;
import java.util.HashSet;
import java.util.Set;
import com.sun.msv.grammar.AttributeExp;
import com.sun.msv.grammar.DataExp;
import com.sun.msv.grammar.ElementExp;
import com.sun.msv.grammar.Expression;
import com.sun.msv.grammar.ExpressionCloner;
import com.sun.msv.grammar.ExpressionPool;
import com.sun.msv.grammar.Grammar;
import com.sun.msv.grammar.ListExp;
import com.sun.msv.grammar.MixedExp;
import com.sun.msv.grammar.OtherExp;
import com.sun.msv.grammar.ReferenceExp;
import com.sun.msv.grammar.SequenceExp;
import com.sun.msv.grammar.ValueExp;
import com.sun.msv.grammar.trex.TREXGrammar;
import com.sun.msv.grammar.util.ExpressionFinder;
/**
* Re-orders AttributeExps inside SequenceExps so that
* attribute comes earlier in the expression
*
* @author Kohsuke Kawaguchi (kk@kohsuke.org)
*/
public class AttributeReorder extends ExpressionCloner {
private final Set visitedExps = new HashSet();
/** Returns true if an expression contains something other than attributes. */
private static final ExpressionFinder hasNonAttributes = new ExpressionFinder() {
public boolean onAnyString() { return true; }
public boolean onAttribute(AttributeExp exp){ return false; }
public boolean onData(DataExp exp) { return true; }
public boolean onElement(ElementExp exp) { return true; }
public boolean onList(ListExp exp) { return true; }
public boolean onMixed(MixedExp exp) { return true; }
public boolean onValue(ValueExp exp) { return true; }
};
public static Grammar optimize( Grammar g ) {
ExpressionPool newPool = new ExpressionPool();
TREXGrammar result = new TREXGrammar(newPool);
AttributeReorder u = new AttributeReorder(newPool);
result.exp = g.getTopLevel().visit(u);
return result;
}
private AttributeReorder(ExpressionPool pool) {
super(pool);
}
public Expression onSequence(SequenceExp exp) {
Expression[] children = exp.getChildren();
// process branches first
for( int i=0; i<children.length; i++ )
children[i] = children[i].visit(this);
Expression r = Expression.epsilon;
// combine attributes
for( int i=0; i<children.length; i++ ) {
if( !children[i].visit(hasNonAttributes) ) {
r = pool.createSequence(r,children[i]);
children[i] = null;
}
}
// followed by other branches
for( int i=0; i<children.length; i++ )
if( children[i]!=null )
r = pool.createSequence(r,children[i]);
return r;
}
public Expression onAttribute(AttributeExp exp) {
return exp;
}
public Expression onElement(ElementExp exp) {
if( visitedExps.add(exp) )
exp.contentModel = exp.contentModel.visit(this);
return exp;
}
public Expression onRef(ReferenceExp exp) {
return exp.exp.visit(this);
}
public Expression onOther(OtherExp exp) {
return exp.exp.visit(this);
}
}