symbolicxmlbuilder.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 367 行
SCALA
367 行
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author Burak Emir */// $Id: SymbolicXMLBuilder.scala 14017 2008-02-15 11:30:46Z michelou $package scala.tools.nsc.ast.parserimport scala.collection.mutable.{Buffer, HashMap, ListBuffer, Map}import scala.tools.nsc.util.Positionimport scala.xml.{EntityRef, Text}import symtab.Flags.MUTABLE/** This class builds instance of <code>Tree</code> 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 global.posAssigner.atPos 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 __Elem = global.newTermName("Elem") def _Group = global.newTypeName("Group") def _Unparsed = global.newTypeName("Unparsed") 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 __Text = global.newTermName("Text") def _EntityRef = global.newTypeName("EntityRef") final def _buf = global.newTermName("$buf") 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__Text = _scala_xml(__Text) private def _scala_xml_Elem = _scala_xml(_Elem) 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 _scala_xml_Unparsed = _scala_xml(_Unparsed) // 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: Position, isPattern: Boolean, pre: Tree, label: Tree, attrs: /*Array[*/Tree/*]*/ , scope:Tree, children: Buffer[Tree]): Tree = { if (isPattern) { convertToTextPat(children) atPos (pos) { //@todo maybe matching on attributes, scope? Apply( _scala_xml__Elem, List( pre, label, Ident(nme.WILDCARD) /* md */ , 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: Position, n: String) = { atPos(pos) { New( _scala_xml_EntityRef, LL(Literal(Constant( n )))) } }; // create scala.xml.Text here <: scala.xml.Node final def text(pos: Position, 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: Position, text: String): Tree = atPos(pos) { Comment( Literal(Constant(text))) } // create def charData(pos: Position, txt: String): Tree = atPos(pos) { makeText1(Literal(Constant(txt))) }; //{ CharData( Literal(Constant(txt))) }; // create scala.xml.Text here <: scala.xml.Node def procInstr( pos: Position, 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: Position, n: String, args: Buffer[Tree]): Tree = { val (prepat, labpat) = n.indexOf(':') match { case -1 => (Ident(nme.WILDCARD), Literal(Constant(n))) //case 0 => // is erroneous, but cannot happen case i => //if(i+1<n.length) // we ensure i+1<n.length in method xName (Literal(Constant(n.substring(0,i))), Literal(Constant(n.substring(i+1,n.length)))) //else { p.syntaxError(pos,"nonsensical qualified name in XML"); return Ident(nme.WILDCARD).setPos(pos)} } mkXML(pos, true, prepat, //Ident( nme.WILDCARD ), labpat, //Literal(Constant(n)), null, //Array[Tree](), null, args); } protected def convertToTextPat(t: Tree): Tree = t match { case _:Literal => makeTextPat(t) case _ => t } def parseAttribute(pos: Position, s: String): Tree = { val ns = xml.Utility.parseAttributeValue(s) val ts: ListBuffer[Tree] = new ListBuffer val it = ns.elements while (it.hasNext) it.next match { case Text(s) => ts += text(pos, s) // makeText1(Literal(Constant(s))) case EntityRef(s) => ts += entityRef(pos, s) } ts.length match { case 0 => gen.mkNil case 1 => val t = ts(0); ts.clear; t case _ => makeXMLseq(pos, ts) } } protected def convertToTextPat(buf: Buffer[Tree]) { 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 += 1 } } def freshName(prefix: String): Name def isEmptyText(t: Tree) = t match { case Literal(Constant("")) => true case _ => false } // could optimize if args.length == 0, args.length == 1 AND args(0) is <: Node. def makeXMLseq(pos: Position, args: Buffer[Tree] ) = { //var _buffer = New( _scala_xml_NodeBuffer, List(Nil)) var as:List[Tree] = ValDef(NoMods, _buf, TypeTree(), New( _scala_xml_NodeBuffer, List(Nil)))::Nil val it = args.elements while (it.hasNext) { val t = it.next if (!isEmptyText(t)) { //_buffer = Apply(Select(_buffer, _plus), List(t)) as = Apply(Select(Ident(_buf), _plus), List(t))::as } } //atPos(pos) { Select(_buffer, _toList) } atPos(pos) { Block(as.reverse, Ident(_buf)) } } /** 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: Position, args: Buffer[Tree]): Tree = { atPos(pos) { New( _scala_xml_Group, LL( makeXMLseq(pos, args))) } } /** code that constructs an unparsed node */ def unparsed(pos: Position, str: String): Tree = { atPos(pos) { New( _scala_xml_Unparsed, LL( Literal(Constant(str)))) } } /** makes an element */ def element(pos: Position, qname: String, attrMap: Map[String,Tree], args: Buffer[Tree]): Tree = { //Console.println("SymbolicXMLBuilder::element("+pos+","+qname+","+attrMap+","+args+")"); var setNS = new HashMap[String, Tree] var tlist: List[Tree] = List() /* pre can be null */ def handleNamespaceBinding(pre: String , uri1: Tree) { def mkAssign(t: Tree): Tree = Assign(Ident(_tmpscope), New( _scala_xml_NamespaceBinding, LL(Literal(Constant(pre)), t, Ident( _tmpscope)))) uri1 match { case Apply(_, List(uri @ Literal(Constant(_)))) => //text tlist = mkAssign(uri) :: tlist case _ => tlist = mkAssign(uri1) :: tlist //println("SymbolicXMLBuilder::handleNamespaceBinding:") //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) { 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) { 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)) } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?