From 761d162a7a86bf4c7633220729811412744d8982 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 30 May 2009 19:24:25 +0000 Subject: Jumbo sized rewrite/cleanup of SymbolicXMLBuilder. --- .../tools/nsc/ast/parser/SymbolicXMLBuilder.scala | 434 ++++++++------------- 1 file changed, 158 insertions(+), 276 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala index 27e506b361..71721389bf 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala @@ -6,9 +6,10 @@ package scala.tools.nsc.ast.parser -import scala.collection.mutable.{Buffer, HashMap, ListBuffer, Map} -import scala.tools.nsc.util.Position -import scala.xml.{EntityRef, Text} +import collection.mutable.Map +import xml.{ EntityRef, Text } +import xml.XML.{ xmlns } +import util.Position import symtab.Flags.MUTABLE /** This class builds instance of Tree that represent XML. @@ -16,352 +17,233 @@ import symtab.Flags.MUTABLE * @author Burak Emir * @version 1.0 */ -abstract class SymbolicXMLBuilder(make: TreeBuilder, p: Parsers # Parser, preserveWS: Boolean) { - +abstract class SymbolicXMLBuilder(make: TreeBuilder, p: Parsers#Parser, preserveWS: Boolean) +{ val global: Global import global._ + def freshName(prefix: String): Name var isPattern: Boolean = _ - def _Attribute = global.newTypeName("Attribute") + def _Comment = global.newTypeName("Comment") + def _Elem = global.newTypeName("Elem") + def _EntityRef = global.newTypeName("EntityRef") + def _Group = global.newTypeName("Group") 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 _ProcInstr = global.newTypeName("ProcInstr") + def _Text = global.newTypeName("Text") + def _Unparsed = global.newTypeName("Unparsed") 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 __Text = global.newTermName("Text") + def _Null = global.newTermName("Null") 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") + 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 const(x: Any) = x match { + case s: runtime.RichString => Literal(Constant(s.toString)) // not our finest hour + case _ => Literal(Constant(x)) + } + private def wild = Ident(nme.WILDCARD) + private def wildStar = Ident(nme.WILDCARD_STAR.toTypeName) + private def _scala(name: Name) = Select(Select(Ident(nme.ROOTPKG), nme.scala_), name) + private def _scala_xml(name: Name) = Select(_scala(_xml), name) - 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_Comment = _scala_xml(_Comment) + private def _scala_xml_Elem = _scala_xml(_Elem) + private def _scala_xml_EntityRef = _scala_xml(_EntityRef) + private def _scala_xml_Group = _scala_xml(_Group) private def _scala_xml_MetaData = _scala_xml(_MetaData) private def _scala_xml_NamespaceBinding = _scala_xml(_NamespaceBinding) + private def _scala_xml_NodeBuffer = _scala_xml(_NodeBuffer) 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) + private def _scala_xml_UnprefixedAttribute= _scala_xml(_UnprefixedAttribute) + private def _scala_xml__Elem = _scala_xml(__Elem) + private def _scala_xml__Text = _scala_xml(__Text) - // 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) )} - } + /** Wildly wrong documentation deleted in favor of "self-documenting code." */ + protected def mkXML( + pos: Position, + isPattern: Boolean, + pre: Tree, + label: Tree, + attrs: Tree, + scope:Tree, + children: Seq[Tree]): Tree = + { + def starArgs = + if (children.isEmpty) Nil + else List(Typed(makeXMLseq(pos, children), wildStar)) + + def pat = Apply(_scala_xml__Elem, List(pre, label, wild, wild) ::: convertToTextPat(children)) + def nonpat = New(_scala_xml_Elem, List(List(pre, label, attrs, scope) ::: starArgs)) + + atPos(pos) { if (isPattern) pat else nonpat } } - final def entityRef(pos: Position, n: String) = { - atPos(pos) { New( _scala_xml_EntityRef, LL(Literal(Constant( n )))) } + final def entityRef(pos: Position, n: String) = + atPos(pos)( New(_scala_xml_EntityRef, LL(const(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) - } + final def text(pos: Position, txt: String): Tree = atPos(pos) { + if (isPattern) makeTextPat(const(txt)) + else makeText1(const(txt)) } - // 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)) + def makeTextPat(txt: Tree) = Apply(_scala_xml__Text, List(txt)) + def makeText1(txt: Tree) = New(_scala_xml_Text, LL(txt)) + def comment(pos: Position, text: String) = atPos(pos)( Comment(const(text)) ) + def charData(pos: Position, txt: String) = atPos(pos)( makeText1(const(txt)) ) - // create - def comment(pos: Position, text: String): Tree = - atPos(pos) { Comment( Literal(Constant(text))) } + def procInstr(pos: Position, target: String, txt: String) = + atPos(pos)( ProcInstr(const(target), const(txt)) ) - // 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)) + 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 (const(pre), const(rest)) + case _ => (wild, const(n)) } - mkXML(pos, - true, - prepat, //Ident( nme.WILDCARD ), - labpat, //Literal(Constant(n)), - null, //Array[Tree](), - null, - args); + mkXML(pos, true, prepat, labpat, null, null, args) } protected def convertToTextPat(t: Tree): Tree = t match { - case _:Literal => makeTextPat(t) - case _ => t + case _: Literal => makeTextPat(t) + case _ => t } + protected def convertToTextPat(buf: Seq[Tree]): List[Tree] = + (buf map convertToTextPat).toList def parseAttribute(pos: Position, s: String): Tree = { - val ns = xml.Utility.parseAttributeValue(s) - val ts: ListBuffer[Tree] = new ListBuffer - val it = ns.iterator - while (it.hasNext) it.next match { - case Text(s) => ts += text(pos, s) // makeText1(Literal(Constant(s))) - case EntityRef(s) => ts += entityRef(pos, s) + val ts = xml.Utility.parseAttributeValue(s) map { + case Text(s) => text(pos, s) + case EntityRef(s) => entityRef(pos, s) } ts.length match { case 0 => gen.mkNil - case 1 => val t = ts(0); ts.clear; t - case _ => makeXMLseq(pos, ts) + case 1 => ts.head + case _ => makeXMLseq(pos, ts.toList) } } - 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.iterator - 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) } + /** could optimize if args.length == 0, args.length == 1 AND args(0) is <: Node. */ + def makeXMLseq(pos: Position, args: Seq[Tree]) = { + val buffer = ValDef(NoMods, _buf, TypeTree(), New(_scala_xml_NodeBuffer, List(Nil))) + val applies = args filterNot isEmptyText map (t => Apply(Select(Ident(_buf), _plus), List(t))) - 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 + atPos(pos)( Block(buffer :: applies.toList, Ident(_buf)) ) } - def group(pos: Position, args: Buffer[Tree]): Tree = { - atPos(pos) { New( _scala_xml_Group, LL( makeXMLseq(pos, args))) } + /** Returns (Some(prefix) | None, rest) based on position of ':' */ + def splitPrefix(name: String): (Option[String], String) = (name indexOf ':') match { + case -1 => (None, name) + case i => (Some(name take i), name drop (i + 1)) } - /** code that constructs an unparsed node - */ - def unparsed(pos: Position, str: String): Tree = { - atPos(pos) { New( _scala_xml_Unparsed, LL( Literal(Constant(str)))) } - } + /** Various node constructions. */ + def group(pos: Position, args: Seq[Tree]): Tree = + atPos(pos)( New(_scala_xml_Group, LL(makeXMLseq(pos, args))) ) + + def unparsed(pos: Position, str: String): Tree = + atPos(pos)( New(_scala_xml_Unparsed, LL(const(str))) ) + + def element(pos: Position, qname: String, attrMap: Map[String, Tree], args: Seq[Tree]): Tree = { + def handleNamespaceBinding(pre: String, z: String): Tree = { + def mkAssign(t: Tree): Tree = Assign( + Ident(_tmpscope), + New(_scala_xml_NamespaceBinding, LL(const(pre), t, Ident(_tmpscope))) + ) - /** 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 Select(_, nme.Nil) => // allow for xmlns="" -- bug #1626 - tlist = mkAssign(Literal(Constant(null))) :: tlist - case _ => - tlist = mkAssign(uri1) :: tlist - //println("SymbolicXMLBuilder::handleNamespaceBinding:") - //println(t.toString()) + val uri1 = attrMap(z) match { + case Apply(_, List(uri @ Literal(Constant(_)))) => mkAssign(uri) + case Select(_, nme.Nil) => mkAssign(const(null)) // allow for xmlns="" -- bug #1626 + case x => mkAssign(x) } + attrMap -= z + uri1 } - /* DEBUG */ - val attrIt = attrMap.keysIterator - 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)) + /** Extract all the namespaces from the attribute map. */ + val namespaces: List[Tree] = + for (z <- attrMap.keys.toList ; if z startsWith xmlns) yield { + val ns = splitPrefix(z) match { + case (Some(_), rest) => rest + case _ => null } - attrMap -= z + handleNamespaceBinding(ns, 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()); + val (pre, newlabel) = splitPrefix(qname) match { + case (Some(p), x) => (p, x) + case (None, x) => (null, x) } - 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 - } + def mkAttributeTree(pre: String, key: String, value: Tree) = atPos(pos) { + // XXX this is where we'd like to put Select(value, nme.toString_) for #1787 + // after we resolve the Some(foo) situation. + val baseArgs = List(const(key), value, Ident(_md)) + val (clazz, attrArgs) = + if (pre == null) (_scala_xml_UnprefixedAttribute, baseArgs) + else (_scala_xml_PrefixedAttribute , const(pre) :: baseArgs) - var it = attrMap.iterator - 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) - } + Assign(Ident(_md), New(clazz, LL(attrArgs: _*))) } - // attrs - - val moreAttributes = (0 < tlist2.length) - var ts: List[Tree] = tlist - var ts2: List[Tree] = List() + def handlePrefixedAttribute(pre: String, key: String, value: Tree) = mkAttributeTree(pre, key, value) + def handleUnprefixedAttribute(key: String, value: Tree) = mkAttributeTree(null, key, value) - 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 + val attributes: List[Tree] = + for ((k, v) <- attrMap.toList.reverse) yield splitPrefix(k) match { + case (Some(pre), rest) => handlePrefixedAttribute(pre, rest, v) + case _ => handleUnprefixedAttribute(k, v) + } - var t = mkXML(pos, - false, - Literal(Constant(pre)) /* can be null */ , - Literal(Constant(newlabel)): Tree, - makeSymbolicAttrs, - Ident(_scope), - args); + lazy val scopeDef = atPos(pos)(ValDef(NoMods, _scope, _scala_xml_NamespaceBinding, Ident(_tmpscope))) + lazy val tmpScopeDef = atPos(pos)(ValDef(Modifiers(MUTABLE), _tmpscope, _scala_xml_NamespaceBinding, Ident(_scope))) + lazy val metadataDef = atPos(pos)(ValDef(Modifiers(MUTABLE), _md, _scala_xml_MetaData, _scala_xml_Null)) + val makeSymbolicAttrs = if (!attributes.isEmpty) Ident(_md) else _scala_xml_Null + + val (attrResult, nsResult) = + (attributes.isEmpty, namespaces.isEmpty) match { + case (true , true) => (Nil, Nil) + case (true , false) => (scopeDef :: Nil, tmpScopeDef :: namespaces) + case (false, true) => (metadataDef :: attributes, Nil) + case (false, false) => (scopeDef :: metadataDef :: attributes, tmpScopeDef :: namespaces) + } - atPos(pos) { Block(ts, Block(ts2, t)) } + val body = mkXML( + pos, + false, + const(pre), + const(newlabel), + makeSymbolicAttrs, + Ident(_scope), + args + ) + + atPos(pos)( Block(nsResult, Block(attrResult, body)) ) } } - -- cgit v1.2.3