com.sun.msv.reader.trex.TREXSequencedStringChecker Maven / Gradle / Ivy
/*
* Copyright (c) 2001-2013 Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.sun.msv.reader.trex;
import java.util.Map;
import java.util.Set;
import com.sun.msv.grammar.AttributeExp;
import com.sun.msv.grammar.ChoiceExp;
import com.sun.msv.grammar.ConcurExp;
import com.sun.msv.grammar.DataExp;
import com.sun.msv.grammar.ElementExp;
import com.sun.msv.grammar.ExpressionVisitor;
import com.sun.msv.grammar.InterleaveExp;
import com.sun.msv.grammar.ListExp;
import com.sun.msv.grammar.MixedExp;
import com.sun.msv.grammar.OneOrMoreExp;
import com.sun.msv.grammar.OtherExp;
import com.sun.msv.grammar.ReferenceExp;
import com.sun.msv.grammar.SequenceExp;
import com.sun.msv.grammar.ValueExp;
/**
* makes sure that there is no sequenced string.
*
* "sequenced string" is something like this.
*
*
* abc
*
*
*
* Also, TREX prohibits sequence of typed strings and elements.
*
*
* In this checker, we introduce a function "f" that takes
* a string and computes the string-sensitivity of the pattern.
*
*
* "f" returns 3 bits of information. One is whether it contains
* elements. Another is whehter it contains text. And the last is
* whether it contains DataExp/ValueExp.
*
*
* "f" is computed recursively through the pattern.
*
* @author Kohsuke KAWAGUCHI
*/
public class TREXSequencedStringChecker implements ExpressionVisitor
{
/**
* If this flag is set to true, this class raises an error for
* anyStrings in two branches of interleave.
*/
private final boolean rejectTextInInterleave;
/** integer pool implementation. */
private static final Integer[] intPool = new Integer[]{
new Integer(0),new Integer(1),new Integer(2),new Integer(3),
new Integer(4),new Integer(5),new Integer(6),new Integer(7) };
// 3 bit of information
private static final int HAS_ELEMENT = 4;
private static final int HAS_ANYSTRING = 2;
private static final int HAS_DATA = 1; // data or value.
private final TREXBaseReader reader;
public TREXSequencedStringChecker( TREXBaseReader reader, boolean _rejectTextInInterleave ) {
this.reader = reader;
this.rejectTextInInterleave = _rejectTextInInterleave;
}
/**
* set of checked Expressions.
*
* once an ElementExp/AttributeExp is checked, it will be added to this set.
* this set is used to prevent infinite recursion.
*/
private final Set checkedExps = new java.util.HashSet();
/**
* set of checked ReferenceExps.
*
* Once a ReferenceExp is checked, it will be added (with its result)
* to this map. This is useful to speed up the check.
*/
private final Map checkedRefExps = new java.util.HashMap();
public Object onRef( ReferenceExp exp ) {
Object r = checkedRefExps.get(exp);
if(r!=null) return r;
checkedRefExps.put(exp, r=exp.exp.visit(this) );
return r;
}
public Object onOther( OtherExp exp ) {
return exp.exp.visit(this);
}
public Object onInterleave( InterleaveExp exp ) {
Object l = exp.exp1.visit(this);
Object r = exp.exp2.visit(this);
if(isError(l,r)) {
// where is the source of error?
reader.reportError( TREXBaseReader.ERR_INTERLEAVED_STRING );
return intPool[0];
}
if( rejectTextInInterleave
&& (toInt(l)&HAS_ANYSTRING)!=0
&& (toInt(r)&HAS_ANYSTRING)!=0 ) {
reader.reportError( TREXBaseReader.ERR_INTERLEAVED_ANYSTRING );
return intPool[0];
}
return merge(l,r);
}
public Object onSequence( SequenceExp exp ) {
Object l = exp.exp1.visit(this);
Object r = exp.exp2.visit(this);
if(isError(l,r)) {
// where is the source of error?
reader.reportError( TREXBaseReader.ERR_SEQUENCED_STRING );
return intPool[0];
}
return merge(l,r);
}
public Object onEpsilon() { return intPool[0]; }
public Object onNullSet() { return intPool[0]; }
public Object onData( DataExp exp ) { return intPool[HAS_DATA]; }
public Object onValue( ValueExp exp ) { return intPool[HAS_DATA]; }
// do not traverse contents of list.
public Object onList( ListExp exp ) { return intPool[HAS_DATA]; }
public Object onAnyString() { return intPool[HAS_ANYSTRING]; }
public Object onAttribute( AttributeExp exp ) {
if( checkedExps.add(exp) )
exp.exp.visit(this);
return intPool[0];
}
public Object onElement( ElementExp exp ) {
if( checkedExps.add(exp) )
// if this is the first visit
// this has to be done before checking content model
// otherwise it leads to the infinite recursion.
exp.contentModel.visit(this);
return intPool[HAS_ELEMENT];
}
private static final int toInt( Object o ) { return ((Integer)o).intValue(); }
private static Object merge( Object o1, Object o2 ) {
return intPool[toInt(o1)|toInt(o2)];
}
/**
* It is an error if a pattern with data is combined to other patterns.
*/
private static boolean isError( Object o1, Object o2 ) {
return (toInt(o1)&HAS_DATA)!=0 && toInt(o2)!=0
|| (toInt(o2)&HAS_DATA)!=0 && toInt(o1)!=0;
}
public Object onChoice( ChoiceExp exp ) {
return merge( exp.exp1.visit(this), exp.exp2.visit(this) );
}
public Object onConcur( ConcurExp exp ) {
return merge( exp.exp1.visit(this), exp.exp2.visit(this) );
}
public Object onOneOrMore( OneOrMoreExp exp ) {
Object o = exp.exp.visit(this);
if( (toInt(o)&HAS_DATA) !=0 ) {
reader.reportError(TREXBaseReader.ERR_REPEATED_STRING);
return intPool[0];
}
return o;
}
public Object onMixed( MixedExp exp ) {
Object o = exp.exp.visit(this);
if( rejectTextInInterleave
&& (toInt(o)&HAS_ANYSTRING)!=0 ) {
reader.reportError( TREXBaseReader.ERR_INTERLEAVED_ANYSTRING );
return intPool[0];
}
return merge(o,intPool[HAS_ANYSTRING]);
}
}