Skip to content

Commit ebdd2f5

Browse files
committed
Use toVector for XML literal sequences
In `<a><b/><c/><a>`, a `NodeBuffer` (which extends `ArrayBuffer`) is used to accumulate the children. The buffer is passed to `new Elem($buf: _*)`, which only works thanks to the implicit `collection.Seq[Node] => NodeSeq` declared in scala-xml. With `-Vprint:typer`: ```scala scala> <a><b/></a> [[syntax trees at end of typer]] // rs$line$1 val res0: scala.xml.Elem = { new _root_.scala.xml.Elem(null, "a", _root_.scala.xml.Null, scala.xml.TopScope, false, { val $buf: scala.xml.NodeBuffer = new _root_.scala.xml.NodeBuffer() $buf.&+( { { new _root_.scala.xml.Elem(null, "b", _root_.scala.xml.Null, scala.xml.TopScope, true, [ : scala.xml.Node]*) } } ) scala.xml.NodeSeq.seqToNodeSeq($buf) }* ) } ``` The implicit was not inserted in 2.12 because the varargs parameter of Elem accepted a `collection.Seq`.
1 parent d5ca220 commit ebdd2f5

File tree

3 files changed

+30
-11
lines changed

3 files changed

+30
-11
lines changed

compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ object MarkupParsers {
376376
content_LT(ts)
377377
charComingAfter(xSpaceOpt()) == '<'
378378
} do ()
379-
handle.makeXMLseq(Span(start, curOffset, start), ts)
379+
handle.makeXMLseq(Span(start, curOffset, start), ts, toVector = false)
380380
}
381381
else {
382382
assert(ts.length == 1, "Require one tree")

compiler/src/dotty/tools/dotc/parsing/xml/SymbolicXMLBuilder.scala

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,13 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(using Context) {
5959
val _plus: TermName = "&+"
6060
val _tmpscope: TermName = "$tmpscope"
6161
val _xml: TermName = "xml"
62+
val _toVector: TermName = "toVector"
6263
}
6364

6465
import xmltypes.{_Comment, _Elem, _EntityRef, _Group, _MetaData, _NamespaceBinding, _NodeBuffer,
6566
_PrefixedAttribute, _ProcInstr, _Text, _Unparsed, _UnprefixedAttribute}
6667

67-
import xmlterms.{_Null, __Elem, __Text, _buf, _md, _plus, _scope, _tmpscope, _xml}
68+
import xmlterms.{_Null, __Elem, __Text, _buf, _md, _plus, _scope, _tmpscope, _xml, _toVector}
6869

6970
// convenience methods
7071
private def LL[A](x: A*): List[List[A]] = List(x.toList)
@@ -103,7 +104,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(using Context) {
103104
{
104105
def starArgs =
105106
if (children.isEmpty) Nil
106-
else List(Typed(makeXMLseq(span, children), wildStar))
107+
else List(Typed(makeXMLseq(span, children, toVector = true), wildStar))
107108

108109
def pat = Apply(_scala_xml__Elem, List(pre, label, wild, wild) ::: convertToTextPat(children))
109110
def nonpat = New(_scala_xml_Elem, List(List(pre, label, attrs, scope, if (empty) Literal(Constant(true)) else Literal(Constant(false))) ::: starArgs))
@@ -152,7 +153,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(using Context) {
152153
ts match {
153154
case Nil => TypedSplice(tpd.ref(defn.NilModule).withSpan(span))
154155
case t :: Nil => t
155-
case _ => makeXMLseq(span, ts)
156+
case _ => makeXMLseq(span, ts, toVector = true)
156157
}
157158
}
158159

@@ -162,11 +163,12 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(using Context) {
162163
}
163164

164165
/** could optimize if args.length == 0, args.length == 1 AND args(0) is <: Node. */
165-
def makeXMLseq(span: Span, args: collection.Seq[Tree]): Block = {
166+
def makeXMLseq(span: Span, args: collection.Seq[Tree], toVector: Boolean): Block = {
166167
val buffer = ValDef(_buf, TypeTree(), New(_scala_xml_NodeBuffer, ListOfNil))
167168
val applies = args filterNot isEmptyText map (t => Apply(Select(Ident(_buf), _plus), List(t)))
168169

169-
atSpan(span)(new XMLBlock(buffer :: applies.toList, Ident(_buf)) )
170+
val res = if (toVector) Select(Ident(_buf), _toVector) else Ident(_buf)
171+
atSpan(span)(new XMLBlock(buffer :: applies.toList, res))
170172
}
171173

172174
/** Returns (Some(prefix) | None, rest) based on position of ':' */
@@ -177,7 +179,7 @@ class SymbolicXMLBuilder(parser: Parser, preserveWS: Boolean)(using Context) {
177179

178180
/** Various node constructions. */
179181
def group(span: Span, args: collection.Seq[Tree]): Tree =
180-
atSpan(span)( New(_scala_xml_Group, LL(makeXMLseq(span, args))) )
182+
atSpan(span)( New(_scala_xml_Group, LL(makeXMLseq(span, args, toVector = true))) )
181183

182184
def unparsed(span: Span, str: String): Tree =
183185
atSpan(span)( New(_scala_xml_Unparsed, LL(const(str))) )

tests/run/xml.scala

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11

22
object Test {
3-
import scala.xml.NodeBuffer
3+
import scala.xml._
44

55
def main(args: Array[String]): Unit = {
66
val xml = <hello>world</hello>
77
assert(xml.toString == "helloworld")
8-
val nodeBuffer: NodeBuffer = <hello/><world/>
9-
assert(nodeBuffer.mkString == "helloworld")
8+
val sq: NodeBuffer = <hello/><world/>
9+
assert(sq.mkString == "helloworld")
10+
11+
val subSq: Node = <a><b/><c/></a>
12+
assert(subSq.child.toString == "Vector(b, c)") // implementation detail
13+
14+
val attrSeq: Elem = <a foo="txt&entityref;txt"/>
15+
assert(attrSeq.attributes.asInstanceOf[UnprefixedAttribute].value.toString == "Vector(txt, &entityref;, txt)")
16+
17+
val g: Group = <xml:group><a/><b/><c/></xml:group>
18+
assert(g.nodes.toString == "Vector(a, b, c)")
1019
}
1120
}
1221
package scala.xml {
@@ -20,7 +29,7 @@ package scala.xml {
2029
def child: Seq[Node]
2130
override def toString = label + child.mkString
2231
}
23-
class Elem(prefix: String, val label: String, attributes1: MetaData, scope: NamespaceBinding, minimizeEmpty: Boolean, val child: Node*) extends Node
32+
class Elem(prefix: String, val label: String, val attributes: MetaData, scope: NamespaceBinding, minimizeEmpty: Boolean, val child: Node*) extends Node
2433
class NodeBuffer extends Seq[Node] {
2534
val nodes = scala.collection.mutable.ArrayBuffer.empty[Node]
2635
def &+(o: Any): NodeBuffer =
@@ -39,4 +48,12 @@ package scala.xml {
3948
def label = t.text
4049
def child = Nil
4150
}
51+
52+
case class UnprefixedAttribute(key: String, value: Seq[Node], next: MetaData)
53+
case class EntityRef(entityName: String) extends Node {
54+
def label = s"&$entityName;"
55+
def child = Nil
56+
}
57+
58+
case class Group(nodes: Seq[Node])
4259
}

0 commit comments

Comments
 (0)