Package com.sun.tahiti.compiler.ll

Source Code of com.sun.tahiti.compiler.ll.RuleSerializer

/*
* @(#)$Id: RuleSerializer.java 1256 2001-10-23 18:27:03Z 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.compiler.ll;

import com.sun.msv.datatype.xsd.XSDatatype;
import com.sun.msv.grammar.*;
import com.sun.msv.grammar.util.ExpressionWalker;
import com.sun.tahiti.compiler.XMLWriter;
import com.sun.tahiti.compiler.Symbolizer;
import com.sun.tahiti.grammar.*;
import com.sun.tahiti.reader.TypeUtil;
import com.sun.tahiti.reader.NameUtil;
import org.relaxng.datatype.Datatype;
import org.xml.sax.DocumentHandler;
import org.xml.sax.SAXException;
import java.io.PrintStream;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.text.MessageFormat;

/**
* serializes a LL grammar into the XML representation.
*
* @author
*  <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a>
*/
public class RuleSerializer implements Symbolizer {
 
  private RuleSerializer() {}
 
  /**
   *
   * @param grammar
   *    Grammar object to be generated as a Java source code.
   * @param rules
   *    production rules of the grammar. Actual type must be
   *    non-terminal -> Rule[].
   * @param grammarClassName
   *    the fully-qualified name of the class that is going to be generated.
   * @param outHandler
   *    Generated source code will be sent to this handler.
   *
   * @return
   *    return a symbolizer that is necessary to serialize class definitions.
   */
  public static Symbolizer serialize( AnnotatedGrammar grammar, Rules rules, DocumentHandler outHandler ) throws SAXException {
    RuleSerializer gen = new RuleSerializer();
    gen._serialize( grammar, rules, outHandler );
    return gen;
  }
 
 
  /**
   * this map serves as a dictionary to lookup the name of the given symbol.
   */
  final Map allNames = new java.util.HashMap();
  public String getId( Object symbol ) {
    if(symbol==nullreturn "null";
    String s = (String)allNames.get(symbol);
   
    if(s==null) {
      System.out.println(symbol);
      assert(false);
    }
    return s;
  }
 
  private void _serialize( AnnotatedGrammar grammar, Rules rules, DocumentHandler outHandler ) throws SAXException {
   
    // add pre-defined special symbols.
    allNames.put( Expression.epsilon, "epsilon" );
   
    try {
      final XMLWriter out = new XMLWriter(outHandler);
      outHandler.setDocumentLocator(new org.xml.sax.helpers.LocatorImpl());
      outHandler.startDocument();
      outHandler.processingInstruction("xml-stylesheet","type='text/xsl' href='../grammarDebug.xslt'");
      out.start("grammar");
     
      {
        int idx = grammar.grammarName.lastIndexOf('.');
        if(idx<0) {
          out.element("name", grammar.grammarName);
        } else {
          out.element("package", grammar.grammarName.substring(0,idx));
          out.element("name", grammar.grammarName.substring(idx+1));
        }
      }
     
    // collect various primitives (a map to its name)
    //====================================================================
      final Map elements = new java.util.HashMap()// ElementExps
      final Map attributes = new java.util.HashMap()// AttributeExps
      final Map datatypes = new java.util.HashMap()// Datatypes
      final Map classes = new java.util.HashMap()// ClassItems
      final Map fields = new java.util.HashMap();    // FieldItems
      final Map primitives = new java.util.HashMap()// PrimitiveItems
      final Map ignores = new java.util.HashMap()// IgnoreItems
     
      grammar.getTopLevel().visit( new ExpressionWalker(){
        public void onElement( ElementExp exp ) {
          if(!elements.containsKey(exp)) {
            elements.put(exp,computeName(exp.getNameClass(),elements));
            super.onElement(exp);
          }
        }
        public void onAttribute( AttributeExp exp ) {
          if(!attributes.containsKey(exp)) {
            attributes.put(exp,computeName(exp.nameClass,attributes));
            super.onAttribute(exp);
          }
        }
        public void onData( DataExp exp ) {
          if(!datatypes.containsKey(exp)) {
            datatypes.put(exp,computeName(exp.dt,datatypes));
            super.onData(exp);
          }
        }
        public void onValue( ValueExp exp ) {
          if(!datatypes.containsKey(exp)) {
            datatypes.put(exp,computeName(exp.dt,datatypes));
            super.onValue(exp);
          }
        }
        public void onOther( OtherExp exp ) {
          if(exp instanceof ClassItem) {
            if(!classes.containsKey(exp)) {
              classes.put(exp,computeName((ClassItem)exp,classes));
              super.onOther(exp);
            }
            return;
          }
          if(exp instanceof PrimitiveItem) {
            if(!primitives.containsKey(exp)) {
              primitives.put(exp,computeName((PrimitiveItem)exp,primitives));
              super.onOther(exp);
            }
            return;
          }
          if(exp instanceof FieldItem) {
            if(!fields.containsKey(exp)) {
              fields.put(exp,computeName((FieldItem)exp,fields));
              super.onOther(exp);
            }
            return;
          }
          if(exp instanceof IgnoreItem) {
            if(!ignores.containsKey(exp)) {
              ignores.put(exp,computeName((IgnoreItem)exp,ignores));
              super.onOther(exp);
            }
            return;
          }
         
          super.onOther(exp);
        }
      });
     
    // assign names to intermediate non-terminals.
    //====================================================================
     
     
      copyAll( elements, "E", allNames );
      copyAll( attributes, "A", allNames );
      copyAll( datatypes, "D", allNames );
      copyAll( classes, "C", allNames );
      copyAll( fields, "N", allNames );
      copyAll( primitives, "P", allNames );
      copyAll( ignores, "Ignore", allNames );
     
     
      final ElementExp[] elms = (ElementExp[])elements.keySet().toArray(new ElementExp[0]);
      final AttributeExp[] atts = (AttributeExp[])attributes.keySet().toArray(new AttributeExp[0]);
      final DataOrValueExp[] dts = (DataOrValueExp[])datatypes.keySet().toArray(new DataOrValueExp[0]);
      final ClassItem[] cis = (ClassItem[])classes.keySet().toArray(new ClassItem[0]);
      final FieldItem[] fis = (FieldItem[])fields.keySet().toArray(new FieldItem[0]);
      final PrimitiveItem[] pis = (PrimitiveItem[])primitives.keySet().toArray(new PrimitiveItem[0]);
      final IgnoreItem[] iis = (IgnoreItem[])ignores.keySet().toArray(new IgnoreItem[0]);
     
      for( int i=0; i<dts.length; i++ ) {
        // TODO: serious implementation
        out.start( "dataSymbol", new String[]{
          "id",(String)allNames.get(dts[i])});
       
        out.element("library", dts[i].getName().namespaceURI );
        out.element("name", dts[i].getName().localName );
       
        out.end("dataSymbol");
       
//          "type", ((XSDatatype)dts[i].dt).getConcreteType().getName()
//          } );
      }
     
      for( int i=0; i<cis.length; i++ ) {
        out.element( "classSymbol", new String[]{
          "id",(String)allNames.get(cis[i]),
          "type",(String)cis[i].getTypeName()
        } );
      }
     
      for( int i=0; i<pis.length; i++ )
        out.element( "primitiveSymbol", new String[]{"id",(String)allNames.get(pis[i])} );
     
      for( int i=0; i<fis.length; i++ )
        out.element( "namedSymbol", new String[]{"id",(String)allNames.get(fis[i])} );
     
      for( int i=0; i<iis.length; i++ )
        out.element( "ignoreSymbol", new String[]{"id",(String)allNames.get(iis[i])} );
     
      {// generate intermediate symbols.
        int cnt=1;
        for( Iterator itr = rules.iterateKeys(); itr.hasNext(); ) {
          Expression symbol = (Expression)itr.next();
          if(!allNames.containsKey(symbol)) {
            out.element( "intermediateSymbol", new String[]{"id","T"+cnt});
            allNames.put( symbol, "T"+cnt );
            cnt++;
          }
        }
      }
     
      {// write all rules
        int rcounter = 0;
        Iterator itr = rules.iterateKeys();
        while(itr.hasNext()) {
          Expression nonTerminal = (Expression)itr.next();
          Rule[] rs = rules.getAll(nonTerminal);
         
          for( int j=0; j<rs.length; j++ ) {
            if(allNames.get(rs[j])==null) {
              // name this rule.
              allNames.put( rs[j], Integer.toString(rcounter++) );
              // write this rule
              rs[j].write(out,this);
            }
          }
        }
      }
     
      {// write non-term -> rule relationship
        out.start("rulesList");
        Iterator itr = rules.iterateKeys();
        while(itr.hasNext()) {
          Expression symbol = (Expression)itr.next();
          out.start("nonTerminal",
            new String[]{"id",getId(symbol)});
          Rule[] rs = rules.getAll(symbol);
          for( int i=0; i<rs.length; i++ )
            out.element("rule",new String[]{"no",getId(rs[i])});
         
          out.end("nonTerminal");
        }
        out.end("rulesList");
      }
 
    // generate a source code that constructs the grammar.
    //==============================================================
     
      ExpressionSerializer eser = new ExpressionSerializer(this,out);
     
      /*
      visit all elements and attributes to compute the dependency between expressions.
      */
      for( int i=0; i<atts.length; i++ ) {
        atts[i].exp.visit(eser.sequencer);
        eser.assignId( atts[i] );
        // attributes are serialized just like other particles.
      }
      for( int i=0; i<elms.length; i++ )
        elms[i].contentModel.visit(eser.sequencer);
     
      // ... and don't forget to visit top level expression.
      grammar.getTopLevel().visit(eser.sequencer);
     
      // then obtain the serialization order by creating a map from id to expr.
      java.util.TreeMap id2expr = new java.util.TreeMap();
      for( Iterator itr=eser.sharedExps.iterator(); itr.hasNext(); ) {
        Expression exp = (Expression)itr.next();
        id2expr.put( eser.expr2id.get(exp), exp );
      }
     
      // then serialize shared expressions
      for( Iterator itr=id2expr.keySet().iterator(); itr.hasNext(); ) {
        Integer n = (Integer)itr.next();
       
        Expression exp = (Expression)id2expr.get(n);
       
        if( exp instanceof AttributeExp ) {
          AttributeExp aexp = (AttributeExp)exp;
          out.start( "attributeSymbol", new String[]{"id",(String)allNames.get(aexp)} );
       
          ExpressionSerializer.serializeNameClass(aexp.getNameClass(),out);
          out.start("content");
          aexp.visit(eser.serializer);
          out.end("content");
         
          LLTableCalculator.calc( aexp, rules, grammar.getPool(),this ).write(out,this);
         
          out.end("attributeSymbol");
        } else {
          // other normal particles.
          out.start("particle",new String[]{"id","o"+n});
          exp.visit(eser.serializer);
          out.end("particle");
        }
      }
     
      // elements are serialized at last.
      for( int i=0; i<elms.length; i++ ) {
        out.start("elementSymbol", new String[]{"id",(String)allNames.get(elms[i])} );
     
        ExpressionSerializer.serializeNameClass(elms[i].getNameClass(),out);
        out.start("content");
        elms[i].visit(eser.serializer);
        out.end("content");
       
        LLTableCalculator.calc( elms[i], rules, grammar.getPool(),this ).write(out,this);
       
        out.end("elementSymbol");
      }
     
      if( elements.containsKey(grammar.getTopLevel()) ) {
        // if the top-level expression is element symbol,
        // then we don't need the root grammar.
        out.start("topLevel");
        out.start("content");
        eser.serialize(grammar.getTopLevel());
        out.end("content");
        out.end("topLevel");
      } else {
        // serialize top-level expression
        out.start("topLevel",new String[]{"id",getId(grammar.getTopLevel())});
        out.start("content");
        grammar.getTopLevel().visit(eser.serializer);
        out.end("content");
          LLTableCalculator.calc( grammar.getTopLevel(), rules, grammar.getPool(),this ).write(out,this);
        out.end("topLevel");
      }
     
     
      {// compute the base type of possible top-level classes
        final Set rootClasses = new java.util.HashSet();
        grammar.getTopLevel().visit( new ExpressionWalker(){
          private Set visitedExps = new java.util.HashSet();
          public void onOther( OtherExp exp ) {
            if( exp instanceof TypeItem )
              rootClasses.add(exp);
            // we don't need to parse inside a JavaItem.
          }
          public void onElement( ElementExp exp ) {
            if( visitedExps.add(exp) )
              exp.contentModel.visit(this);
          }
        });
       
        Type rootType = TypeUtil.getCommonBaseType(rootClasses);
        out.element("rootType",
          new String[]{"name", rootType.getTypeName()});
      }
     
      out.end("grammar");
      outHandler.endDocument();
    } catch( XMLWriter.SAXWrapper w ) {
      throw w.e;
    };
  }
 
  /**
   * copy the source map to the destination map, while adding
   * the specified prefix to values.
   */
  private static void copyAll( Map src, String prefix, Map dst ) {
    for( Iterator itr=src.keySet().iterator(); itr.hasNext(); ) {
      Object symbol = itr.next();
      dst.put( symbol, prefix+src.get(symbol) );
    }
  }
 
  /**
   * computes a unique name that is used as a field name for
   * the ElementExp/AttributeExp.
   *
   * @param nc
   *    name class of that ElementExp/AttributeExp.
   * @param m
   *    values of this map are the names of other ElementExp/AttributeExps.
   *    This method has to return the unique name.
   */
  private static String computeName( NameClass nc, Map m ) {
    if( nc instanceof SimpleNameClass ) {
      SimpleNameClass snc = (SimpleNameClass)nc;
      String name = NameUtil.toIdentifier(snc.localName);
      if(!m.containsValue(name))
        return name;
     
      return getNumberedName( snc.localName, 2, m );
    } else {
      return getNumberedName( "", 1, m );
    }
  }
 
  /**
   * generate an unique name by concatenating a number to its tail.
   */
  private static String getNumberedName( String prefix, int count, Map m ) {
   
    if( NameUtil.toIdentifier(prefix).length()==0 )
      prefix = "_" + prefix;
   
    String name;
    do {
      name = NameUtil.toIdentifier( prefix+Integer.toString(count++) );
    } while( m.containsValue(name) );

    return name;
  }

  /**
   * computes an unique name that is used as a field name for
   * the Datatype.
   *
   * @param dt
   *    Datatype object.
   * @param m
   *    values of this map are the names of other ElementExp/AttributeExps.
   *    This method has to return the unique name.
   */
  private static String computeName( Datatype dt, Map m ) {
    if( dt instanceof XSDatatype ) {
      XSDatatype xsdt = (XSDatatype)dt;
      if( xsdt.getName()!=null ) {
        String name = NameUtil.toIdentifier( xsdt.getName() );
        if(!m.containsValue(name) )  return name;
        else
          getNumberedName( name, 2, m );
      } else
        return getNumberedName( xsdt.displayName(), 2, m );
    }
   
    return getNumberedName( "", 0, m );
  }
 
  private static String computeName( ClassItem cls, Map m ) {
    String name = cls.getBareName();
   
    if(!m.containsValue(name))    return name;
    return getNumberedName( name, 2, m );
  }

  private static String computeName( PrimitiveItem pitm, Map m ) {
    String name = pitm.type.getBareName();
   
    if(!m.containsValue(name))    return name;
    return getNumberedName( name, 2, m );
  }

  private static String computeName( FieldItem field, Map m ) {
    if(!m.containsValue(field.name))    return field.name;
    return getNumberedName( field.name, 2, m );
  }
 
  private static String computeName( IgnoreItem iim, Map m ) {
    return getNumberedName( "", 1, m );
  }

 
  /**
   * gets the source code representation of the specified string.
   */
  private static String javaStringEscape( String s ) {
//    throw new Error();
    return "\""+s+"\"";
  }
 
 
  private static void assert( boolean b ) {
    if(!bthrow new Error();
  }
}
TOP

Related Classes of com.sun.tahiti.compiler.ll.RuleSerializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.