/*
* @(#)$Id: SuperClassBodyRemover.java 971 2001-07-27 22:04:13Z Bear $
*
* Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the proprietary information of Sun Microsystems, Inc.
* Use is subject to license terms.
*
*/
package com.sun.tahiti.grammar.util;
import com.sun.msv.grammar.*;
import com.sun.msv.grammar.trex.ElementPattern;
import com.sun.msv.grammar.util.ExpressionWalker;
import com.sun.tahiti.grammar.*;
import java.util.Set;
/**
* removes ClassItem inside SuperClassItem as a preparation
* of the marshaller generation.
*
* <p>
* Care has to be taken not to remove ClassItems directly referenced
* from other part of the grammar. For example,
*
* <PRE><XMP>
* <start>
* <choice>
* <element name="derived" t:role="class">
* <ref name="body" t:role="superClass"/>
* </element>
* <element name="base">
* <ref name="body"/>
* </element>
* </choice>
* </start>
*
* <define name="body" t:role="class">
* <data type="string"/>
* </define>
* </XMP></PRE>
*
* We can't simply remove ClassItem from "body". Intuitively, we are
* to create the following pattern from the above pattern in this process.
*
* <PRE><XMP>
* <start>
* <choice>
* <element name="derived" t:role="class">
* <ref name="body1" t:role="superClass"/>
* </element>
* <element name="base">
* <ref name="body2"/>
* </element>
* </choice>
* </start>
*
* <define name="body1">
* <data type="string"/>
* </define>
*
* <define name="body2" t:role="class">
* <data type="string"/>
* </define>
* </XMP></PRE>
*
* @author
* <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a>
*/
public class SuperClassBodyRemover extends ExpressionCloner {
private final Set visitedRefs = new java.util.HashSet();
public static void remove( AnnotatedGrammar g ) {
SuperClassBodyRemover su = new SuperClassBodyRemover(g.getPool());
ClassItem[] cls = g.getClasses();
for( int i=0; i<cls.length; i++ )
cls[i].exp = cls[i].exp.visit(su);
}
public Expression onAttribute( AttributeExp exp ) {
return pool.createAttribute( exp.nameClass, exp.exp.visit(this) );
}
public Expression onElement( ElementExp exp ) {
if(visitedRefs.add(exp))
exp.contentModel = exp.contentModel;
return exp;
}
public Expression onRef( ReferenceExp exp ) {
if(visitedRefs.add(exp))
exp.exp = exp.exp.visit(this);
return exp; // recurse children if this is the first visit.
}
public Expression onOther( OtherExp exp ) {
if( exp instanceof SuperClassItem ) {
return exp.exp.visit(remover);
}
if(visitedRefs.add(exp))
exp.exp=exp.exp.visit(this);
return exp;
}
private ExpressionCloner remover;
private SuperClassBodyRemover( ExpressionPool pool ) {
super(pool);
remover = new ExpressionCloner(pool){
public Expression onRef( ReferenceExp exp ) {
return exp.exp.visit(this);
}
public Expression onOther( OtherExp exp ) {
if( exp instanceof ClassItem ) {
// this is the definition of this super class item.
// remove it.
return exp.exp;
}
// it must not be a JavaItem.
// this check should have already been done by the RelationNormalizer
if( exp instanceof JavaItem )
throw new Error("internal error");
// other unknown exps
return exp.exp.visit(this);
}
/*
we have to copy ElementExp/AttributeExp if that is necessary.
consider the following pattern:
<start>
<choice>
<group t:role="class">
<ref name="body" t:role="superClass"/>
<element name="ext"/>
</group>
<ref name="body">
</choice>
</start>
<define name="body">
<element name="body">
<group t:role="class" id="base">
<data />
</group>
</element>
</define>
We cannot strip the ClassItem of the "base" correctly unless
we copy the definition of the "body" elment.
*/
public Expression onAttribute( AttributeExp exp ) {
return super.pool.createAttribute(exp.nameClass,exp.exp.visit(this));
}
public Expression onElement( ElementExp exp ) {
Expression body = exp.contentModel.visit(this);
if(body==exp.contentModel) return exp; // this item is not modified.
else
// body of this element is modified.
// since this ElementExp might be shared,
// we need to create a fresh ElementExp.
return new ElementPattern(exp.getNameClass(),body);
}
};
}
}