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.InterleaveExp; 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.ValueExp; import com.sun.msv.grammar.trex.TREXGrammar; import com.sun.msv.grammar.util.ExpressionFinder; /** * Replaces interleaves whose branch is attribute by groups. * * Groups are computationally less expensive than interleaves, * so this is expected to reduce the size of the grammar. * * @author Kohsuke Kawaguchi (kk@kohsuke.org) */ public class InterleaveStrengthReducer extends ExpressionCloner { private InterleaveStrengthReducer( ExpressionPool pool ) { super(pool); } public static Grammar optimize( Grammar grammar ) { ExpressionPool pool = grammar.getPool(); TREXGrammar result = new TREXGrammar(pool); InterleaveStrengthReducer r = new InterleaveStrengthReducer(pool); result.exp = grammar.getTopLevel().visit(r); return result; } private final Set visitedExps = new HashSet(); public Expression onAttribute(AttributeExp att) { return att; } public Expression onElement(ElementExp exp) { if( visitedExps.add(exp) ) exp.contentModel = exp.contentModel.visit(this); return exp; } public Expression onInterleave(InterleaveExp exp) { if( !exp.exp1.visit(hasElementOrText) || !exp.exp2.visit(hasElementOrText) ) return pool.createSequence( exp.exp1.visit(this), exp.exp2.visit(this) ); else return super.onInterleave(exp); } public Expression onRef(ReferenceExp exp) { if( visitedExps.add(exp) ) exp.exp = exp.exp.visit(this); return exp; } public Expression onOther(OtherExp exp) { return exp.exp.visit(this); } /** * Returns true if the expression contains elements or texts. */ private static ExpressionFinder hasElementOrText = 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; } }; }