summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-05-30 19:24:25 +0000
committerPaul Phillips <paulp@improving.org>2009-05-30 19:24:25 +0000
commit761d162a7a86bf4c7633220729811412744d8982 (patch)
treecf7e144d20d13bec94a70ba7167a34c51f2999bc /src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
parentc6cf4fc02204d20f792bd493641d8ccd12421800 (diff)
downloadscala-761d162a7a86bf4c7633220729811412744d8982.tar.gz
scala-761d162a7a86bf4c7633220729811412744d8982.tar.bz2
scala-761d162a7a86bf4c7633220729811412744d8982.zip
Jumbo sized rewrite/cleanup of SymbolicXMLBuilder.
Diffstat (limited to 'src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala')
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala434
1 files changed, 158 insertions, 276 deletions
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 <code>Tree</code> 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<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)}
+ def makeXMLpat(pos: Position, n: String, args: Seq[Tree]): Tree = {
+ val (prepat, labpat) = splitPrefix(n) match {
+ case (Some(pre), rest) => (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)) )
}
}
-