summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
blob: 3a14035312edc7fac34c05fddf7884ee3dfbc6c1 (plain) (tree)
1
2
3
4
5
6
7
8


                                

       
 
                                  
 




                                                
 





                                                                                                
 



                                  

                                                          
                           
 



























                                                                      

                        




                                                          
                                         














                                                                              
                                                                
 
    
                                                                       

                                         
                                                          
       
   
    









                                                                                                                                                              


                                                





                                                                                                                         
                              




                                                                                                

                                                                         


                                                 


                                                  
                

                         
          
                       



                                                 



                                                                

           

                                                    

           
                                             
                                                                                              


                                                          
                                                                               
 
                                                                     
 

                                                    






                                                                         
                                



                                                           
                                    



                                                                     


                                       
                       

                         
       
               


     
                                     

                                     

                                      
   
 
                                                          





                                                        

       
                                           

   
                                                         


                                                     

   



                                                                     


                                                                                                               
                                                 
 
                                  




                                                                        
                        




                                                                       




                                                       
                     

                                                  
              
                                               
                                             
                                                
         
                    


       
                                           

         
                              
 
                        

                                      

                                                                


                  
                                   
























                                                                             
                             
                        
                        

                                

                                                                       
                         
                                                     



             
                                            
 

                                
 
                         
                                                  



                                                          
                         
                       
                                



                                         
                                                                                         

     

                                                         



                                                            
                                                    



                                    
                                           


   
/* NSC -- new Scala compiler
 * Copyright 2005-2006 LAMP/EPFL
 * @author Burak Emir
 */
// $Id$

package scala.tools.nsc.ast.parser

import scala.collection.immutable.{Map, ListMap}
import scala.collection.mutable
import scala.tools.nsc.util.Position
import scala.xml.{Text, TextBuffer}
import symtab.Flags.MUTABLE

/** This class builds instance of Tree that represent XML.
 *
 *  @author  Burak Emir
 *  @version 1.0
 */
abstract class SymbolicXMLBuilder(make: TreeBuilder, p: Parsers # Parser, preserveWS: Boolean) {

  val global: Global
  import global._
  import RequiresIntsAsPositions._
  import global.posAssigner.atPos
  //import scala.tools.scalac.ast.{TreeList => myTreeList}

  var isPattern:Boolean = _

  def _Attribute           = global.newTypeName("Attribute")
  def _MetaData            = global.newTypeName("MetaData")
  def _NamespaceBinding    = global.newTypeName("NamespaceBinding")
  def _NodeBuffer          = global.newTypeName("NodeBuffer")
  def _Null                = global.newTermName("Null")

  def _PrefixedAttribute   = global.newTypeName("PrefixedAttribute")
  def _UnprefixedAttribute = global.newTypeName("UnprefixedAttribute")
  def _Elem                = global.newTypeName("Elem")
  def _Group               = global.newTypeName("Group")
  def _Seq                 = global.newTypeName("Seq")
  def _immutable           = global.newTermName("immutable")
  def _mutable             = global.newTermName("mutable")
  def _append              = global.newTermName("append")
  def _plus                = global.newTermName("$amp$plus")
  def _collection          = global.newTermName("collection")
  def _toList              = global.newTermName("toList")
  def _xml                 = global.newTermName("xml")
  def _Comment             = global.newTypeName("Comment")
  def _Node                = global.newTypeName("Node")
  def _None                = global.newTermName("None")
  def _Some                = global.newTypeName("Some")
  def _ProcInstr           = global.newTypeName("ProcInstr")
  def _Text                = global.newTypeName("Text")
  def _EntityRef           = global.newTypeName("EntityRef")
  final def _md = global.newTermName("$md")
  final def _scope = global.newTermName("$scope")
  final def _tmpscope = global.newTermName("$tmpscope")

  // convenience methods
  private def LL[A](x:A*):List[List[A]] = List(List(x:_*))

  private def _scala(name: Name) =
    Select(Select(Ident(nme.ROOTPKG), nme.scala_), name)

  private def _scala_Seq   = _scala(_Seq)
  private def _scala_xml(name: Name) = Select(_scala(_xml), name)

  private def _scala_xml_MetaData           = _scala_xml(_MetaData)
  private def _scala_xml_NamespaceBinding   = _scala_xml(_NamespaceBinding)
  private def _scala_xml_Null               = _scala_xml(_Null)
  private def _scala_xml_PrefixedAttribute  = _scala_xml(_PrefixedAttribute)
  private def _scala_xml_UnprefixedAttribute= _scala_xml(_UnprefixedAttribute)
  private def _scala_xml_Node               = _scala_xml(_Node)
  private def _scala_xml_NodeBuffer         = _scala_xml(_NodeBuffer)
  private def _scala_xml_EntityRef          = _scala_xml(_EntityRef)
  private def _scala_xml_Comment            = _scala_xml(_Comment)
  private def _scala_xml_ProcInstr          = _scala_xml(_ProcInstr)
  private def _scala_xml_Text               = _scala_xml(_Text)
  private def _scala_xml_Elem               = _scala_xml(_Elem)
  private def _scala_xml_Attribute          = _scala_xml(_Attribute)
  private def _scala_xml_Group              = _scala_xml(_Group)

  /*
  private def bufferToArray(buf: mutable.Buffer[Tree]): Array[Tree] = {
    val arr = new Array[Tree](buf.length)
    var i = 0
    for (val x <- buf.elements) { arr(i) = x; i = i + 1; }
    arr
  }
  */

  // create scala xml tree

  /**
   *  @arg  namespace: a Tree of type defs.STRING_TYPE
   *  @arg  label:     a Tree of type defs.STRING_TYPE
   *  @todo map:       a map of attributes !!!
   */

  protected def mkXML(pos: int, isPattern: boolean, pre: Tree, label: Tree, attrs: /*Array[*/Tree/*]*/ , scope:Tree, children: mutable.Buffer[Tree]): Tree = {
    if (isPattern) {
      //val ts = new mutable.ArrayBuffer[Tree]()
      convertToTextPat(children)
      atPos (pos) {
        Apply( _scala_xml_Elem, List(
          pre, label, Ident( nme.WILDCARD ) /* attributes? */ , Ident( nme.WILDCARD )) /* scope? */ ::: children.toList )
      }
    } else {
      var ab = List(pre, label, attrs, scope);
      if (children.length > 0)
        ab = ab ::: List(Typed(makeXMLseq(pos, children), Ident(nme.WILDCARD_STAR.toTypeName)));
      atPos(pos) { New( _scala_xml_Elem, List(ab) )}
    }
  }

  final def entityRef(pos: int, n: String) = {
    atPos(pos) { New( _scala_xml_EntityRef, LL(Literal(Constant( n )))) }

  };
  // create scala.xml.Text here <: scala.xml.Node
  final def text(pos: Int, txt:String): Tree =  {
    //makeText( isPattern, gen.mkStringLit( txt ))
    val txt1 = Literal(Constant(txt))
    atPos(pos) {
      if (isPattern)
        makeTextPat(txt1)
      else
        makeText1(txt1)
    }
  }

  // create scala.xml.Text here <: scala.xml.Node
  def makeTextPat(txt: Tree) = Apply(_scala_xml_Text, List(txt))

  def makeText1(txt: Tree) =
    New(_scala_xml_Text, LL(txt))

  // create
  def comment(pos: int, text: String): Tree =
    atPos(pos) { Comment( Literal(Constant(text))) }

  // create
  def charData(pos: int, txt: String): Tree =
    atPos(pos) { makeText1(Literal(Constant(txt))) }; //{ CharData( Literal(Constant(txt))) };

  // create scala.xml.Text here <: scala.xml.Node
  def procInstr( pos: int, target: String, txt: String ) =
    atPos(pos) { ProcInstr(Literal(Constant(target)), Literal(Constant(txt))) }

  protected def Comment(txt: Tree) = New(_scala_xml_Comment, LL(txt))

  protected def ProcInstr(target: Tree, txt: Tree) =
    New(_scala_xml_ProcInstr, LL(target, txt))

  /** @todo: attributes */
  def makeXMLpat(pos: int, n: String, args: mutable.Buffer[Tree]): Tree =
    mkXML(pos,
          true,
          Ident( nme.WILDCARD ),
          Literal(Constant(n)),
          null, //Array[Tree](),
          null,
          args);

  protected def convertToTextPat(t: Tree): Tree = t match {
    case _:Literal => makeTextPat(t)
    case _ => t
  }

  protected def convertToTextPat(buf: mutable.Buffer[Tree]): Unit = {
    var i = 0; while (i < buf.length) {
      val t1 = buf(i)
      val t2 = convertToTextPat(t1)
      if (!t1.eq(t2)) {
        buf.remove(i)
        buf.insert(i, t2)
      }
      i = i + 1
    }
  }

  def freshName(prefix: String): Name

  def isEmptyText(t:Tree) = t match {
    case Literal(Constant("")) => true
    case _ => false
  }

  def makeXMLseq( pos:int, args:mutable.Buffer[Tree] ) = {
    var _buffer = New( _scala_xml_NodeBuffer, List(Nil))
    val it = args.elements
    while (it.hasNext) {
      val t = it.next
      if (!isEmptyText(t)) {
        _buffer = Apply(Select(_buffer, _plus), List(t))
      }
    }
    atPos(pos) { Select(_buffer, _toList) }
  }

  /** returns Some(prefix) if pre:name, None otherwise */
  def getPrefix(name: String): Option[String] = {
    val i = name.indexOf(':')
    if (i != -1) Some(name.substring(0, i)) else None
  }

  def group(pos: int, args: mutable.Buffer[Tree]): Tree = {
    atPos(pos) { New( _scala_xml_Group, LL( makeXMLseq(pos, args))) }
  }

  /** makes an element */
  def element(pos: int, qname: String, attrMap: mutable.Map[String,Tree], args: mutable.Buffer[Tree]): Tree = {
    //Console.println("SymbolicXMLBuilder::element("+pos+","+qname+","+attrMap+","+args+")");
    var setNS = new mutable.HashMap[String, Tree]

    var tlist: List[Tree] = List()

    /* pre can be null */
    def handleNamespaceBinding(pre:String , uri:Tree): Unit = {
      val t = Assign(Ident(_tmpscope), New( _scala_xml_NamespaceBinding,
        LL(Literal(Constant(pre)), uri, Ident( _tmpscope))));
      tlist = t :: tlist
      //Console.println("SymbolicXMLBuilder::handleNamespaceBinding:");
      //Console.println(t.toString());
    }

    /* DEBUG */
    val attrIt = attrMap.keys
    while (attrIt.hasNext) {
      val z = attrIt.next
      if (z.startsWith("xmlns")) {  // handle namespace
        val i = z.indexOf(':')
        if( i == -1 )
          handleNamespaceBinding(null, attrMap(z))
          //setNS.update("default", attrMap(z))
        else {
          val zz = z.substring(i+1, z.length())
          //setNS.update( zz, attrMap( z ) );
          handleNamespaceBinding(zz, attrMap(z))
        }
        attrMap -= z
      }
    }

    val moreNamespaces = (0 < tlist.length)

    /* */
    val i = qname.indexOf(':')

    var newlabel = qname
    val pre = getPrefix(qname) match {
      case Some(p) =>
        newlabel = qname.substring(p.length()+1, qname.length())
        p
      case None =>
        null
    }
    var tlist2: List[Tree] = List()

    // make attributes

    def handlePrefixedAttribute(pre:String, key:String, value:Tree): Unit = {
      val t = atPos(pos) {
        Assign(Ident(_md), New( _scala_xml_PrefixedAttribute,
                                       LL(
                                         Literal(Constant(pre)),
                                         Literal(Constant(key)),
                                         value,
                                         Ident(_md)
                                       )))};
      tlist2 = t :: tlist2;
     // Console.println("SymbolicXMLBuilder::handlePrefixed :");
     // Console.println(t.toString());
    }

    def handleUnprefixedAttribute(key:String, value:Tree): Unit = {
      val t = atPos(pos) {
        Assign(Ident(_md), New(_scala_xml_UnprefixedAttribute,
                               LL(Literal(Constant(key)),value,Ident(_md))
                             ))};
      tlist2 = t :: tlist2;
    }

    var it = attrMap.elements
    while (it.hasNext) {
      val ansk = it.next
      getPrefix(ansk._1) match {
        case Some(pre) =>
          val key = ansk._1.substring(pre.length()+1, ansk._1.length())
          handlePrefixedAttribute(pre, key, ansk._2)
        case None      =>
          handleUnprefixedAttribute(ansk._1, ansk._2)
      }
    }
    //  attrs

    val moreAttributes = (0 < tlist2.length)

    var ts: List[Tree] = tlist
    var ts2: List[Tree] = List()

    if (moreAttributes) {
      ts2 = atPos(pos) {ValDef(Modifiers(MUTABLE),
                              _md,
                              _scala_xml_MetaData,
                              _scala_xml_Null)} :: tlist2;
    }
    if (moreNamespaces) {
      ts = atPos(pos) {
      ValDef(Modifiers(MUTABLE),
             _tmpscope,
             _scala_xml_NamespaceBinding,
             Ident(_scope))} :: ts;

      ts2 = ValDef(NoMods, _scope, _scala_xml_NamespaceBinding, Ident(_tmpscope)) :: ts2;
    }

    val makeSymbolicAttrs =
      if (moreAttributes) Ident(_md) else _scala_xml_Null

    var t = mkXML(pos,
                  false,
                  Literal(Constant(pre)) /* can be null */ ,
                  Literal(Constant(newlabel)): Tree,
                  makeSymbolicAttrs,
                  Ident(_scope),
                  args);

    atPos(pos) { Block(ts, Block(ts2, t)) }
  }
}