diff --git a/build.sbt b/build.sbt
index 85bf1ef87..c2b77d152 100644
--- a/build.sbt
+++ b/build.sbt
@@ -12,10 +12,10 @@ scalaVersionsByJvm in ThisBuild := {
}
lazy val root = project.in(file("."))
- .aggregate(xmlJS, xmlJVM)
+ .aggregate(xmlJS, xmlJVM, xmlquote)
.settings(publish := {}, publishLocal := {})
-lazy val xml = crossProject.in(file("."))
+lazy val xml = crossProject.in(file("xml"))
.settings(
name := "scala-xml",
version := "1.0.7-SNAPSHOT",
@@ -54,3 +54,20 @@ lazy val xml = crossProject.in(file("."))
lazy val xmlJVM = xml.jvm
lazy val xmlJS = xml.js
+
+lazy val xmlquote = project.in(file("quote"))
+ .dependsOn(xmlJVM)
+ .settings(
+ name := "scala-xml-quote",
+ scalacOptions ++= Seq(
+ "-deprecation",
+ "-feature",
+ "-unchecked",
+ "-Xlint"
+ ),
+ libraryDependencies ++= Seq(
+ "org.scala-lang" % "scala-reflect" % scalaVersion.value,
+ "com.lihaoyi" %% "fastparse" % "0.4.3",
+ "org.scalatest" %% "scalatest" % "3.0.1" % "test"
+ )
+ )
diff --git a/quote/src/main/scala/scala/xml/quote/internal/Hole.scala b/quote/src/main/scala/scala/xml/quote/internal/Hole.scala
new file mode 100644
index 000000000..6ec382143
--- /dev/null
+++ b/quote/src/main/scala/scala/xml/quote/internal/Hole.scala
@@ -0,0 +1,12 @@
+package scala.xml.quote.internal
+
+import fastparse.all._
+
+private[internal] object Hole {
+ // withing private use area
+ private val HoleStart = 0xE000.toChar.toString
+ private val HoleChar = 0xE001.toChar.toString
+
+ def encode(i: Int) = HoleStart + HoleChar * i
+ val Parser: P[Int] = P( HoleStart ~ HoleChar.rep ).!.map(_.length - 1)
+}
diff --git a/quote/src/main/scala/scala/xml/quote/internal/Liftables.scala b/quote/src/main/scala/scala/xml/quote/internal/Liftables.scala
new file mode 100644
index 000000000..73890bfb7
--- /dev/null
+++ b/quote/src/main/scala/scala/xml/quote/internal/Liftables.scala
@@ -0,0 +1,192 @@
+package scala.xml.quote.internal
+
+import scala.xml.quote.internal.ast._
+
+/** Lift `ast.Node` to `c.universe.Tree`.
+ *
+ * At this point, `Node` are expected to be valid.
+ *
+ * Note: `$_scope` is used as a scope name because `$scope` is already taken.
+ */
+private[internal] trait Liftables { self: QuoteImpl =>
+ import Liftables.{Scope, TopScope}
+ import self.c.universe._
+
+ def lift(nodes: Seq[Node]): Tree = {
+ val tree =
+ if (nodes.size == 1) liftNode(TopScope)(nodes.head)
+ else liftNodes(TopScope)(nodes)
+ fixScopes(tree)
+ }
+
+
+ /** When we lift, we don't know if we are within an enclosing xml element
+ * which defines a scope. In some cases we will have to fix the scope.
+ *
+ * E.g:
+ * {{{
+ * xml"""${ xml"" }"""
+ * }}}
+ * Here the scope of `` is `TopScope` but should be `scope0`
+ */
+ private def fixScopes(tree: Tree): Tree = {
+ val typed = c.typecheck(tree)
+
+ var scopeSym = NoSymbol
+ c.internal.typingTransform(typed)((tree, api) => tree match {
+ case q"$_.TopScope" if scopeSym != NoSymbol =>
+ api.typecheck(q"$scopeSym")
+ case q"val $$_scope = $_" => // this assignment is only here when creating new scope
+ scopeSym = tree.symbol
+ tree
+ case _ =>
+ api.default(tree)
+ })
+ }
+
+ private val sx = q"_root_.scala.xml"
+
+ private implicit def liftNode(implicit outer: Scope): Liftable[Node] =
+ Liftable {
+ case n: Group => liftGroup(outer)(n)
+ case n: Elem => liftElem(outer)(n)
+ case n: Text => liftText(n)
+ case n: Placeholder => liftPlaceholder(n)
+ case n: Comment => liftComment(n)
+ case n: PCData => liftPCData(n)
+ case n: ProcInstr => liftProcInstr(n)
+ case n: Unparsed => liftUnparsed(n)
+ case n: EntityRef => liftEntityRef(n)
+ }
+
+ private implicit def liftNodes(implicit outer: Scope): Liftable[Seq[Node]] = Liftable { nodes =>
+ val additions = nodes.map(node => q"$$buf &+ $node")
+ q"""
+ {
+ val $$buf = new $sx.NodeBuffer
+ ..$additions
+ $$buf
+ }
+ """
+ }
+
+ private def liftGroup(implicit outer: Scope) = Liftable { gr: Group =>
+ q"new $sx.Group(${gr.nodes})"
+ }
+
+ private def liftElem(implicit outer: Scope) = Liftable { e: Elem =>
+ def outerScope =
+ if (outer.isTopScope) q"$sx.TopScope"
+ else q"$$_scope"
+
+ def liftAttributes(atts: Seq[Attribute]): Seq[Tree] = {
+ val metas = atts.reverse.map { a =>
+ val value = a.value match {
+ case Seq(v) => q"$v"
+ case vs => q"$vs"
+ }
+
+ val att =
+ if (a.prefix.isEmpty) q"new $sx.UnprefixedAttribute(${a.key}, $value, $$md)"
+ else q"new $sx.PrefixedAttribute(${a.prefix}, ${a.key}, $value, $$md)"
+
+ q"$$md = $att"
+ }
+
+ val init: Tree = q"var $$md: $sx.MetaData = $sx.Null"
+ init +: metas
+ }
+
+ def liftNameSpaces(nss: Seq[Attribute]): Seq[Tree] = {
+ val init: Tree = q"var $$tmpscope: $sx.NamespaceBinding = $outerScope"
+
+ val scopes = nss.map { ns =>
+ val prefix = if (ns.prefix.nonEmpty) q"${ns.key}" else q"null: String"
+ val uri = ns.value.head match {
+ case Text(text, _) => q"$text"
+ case scalaExpr => q"$scalaExpr"
+ }
+ q"$$tmpscope = new $sx.NamespaceBinding($prefix, $uri, $$tmpscope)"
+ }
+
+ init +: scopes
+ }
+
+ val (nss, atts) = e.attributes.partition(_.isNamespace)
+
+ val prefix: Tree =
+ if (e.prefix.isEmpty) q"null: String"
+ else q"${e.prefix}"
+
+ val label = q"${e.label}"
+
+ val (metapre, metaval) =
+ if (atts.isEmpty) (Nil, q"$sx.Null")
+ else (liftAttributes(atts), q"$$md")
+
+ val minimizeEmpty = q"${e.minimizeEmpty}"
+
+ def children = {
+ val newScope = new Scope(outer.isTopScope && nss.isEmpty)
+ liftNodes(newScope)(e.children)
+ }
+
+ def newElem(scope: Tree) =
+ if (e.children.isEmpty) q"new $sx.Elem($prefix, $label, $metaval, $scope, $minimizeEmpty)"
+ else q"new $sx.Elem($prefix, $label, $metaval, $scope, $minimizeEmpty, $children: _*)"
+
+ if (nss.isEmpty) {
+ q"""
+ {
+ ..$metapre
+ ${newElem(outerScope)}
+ }
+ """
+ } else {
+ val scopepre = liftNameSpaces(nss)
+ q"""
+ {
+ ..$scopepre;
+ {
+ val $$_scope = $$tmpscope
+ ..$metapre
+ ${newElem(q"$$_scope")}
+ }
+ }
+ """
+ }
+ }
+
+ private val liftText = Liftable { t: Text =>
+ q"new $sx.Text(${t.text})"
+ }
+
+ private val liftPlaceholder = Liftable { p: Placeholder =>
+ self.arg(p.id)
+ }
+
+ private val liftComment = Liftable { c: Comment =>
+ q"new $sx.Comment(${c.text})"
+ }
+
+ private val liftPCData = Liftable { pcd: PCData =>
+ q"new $sx.PCData(${pcd.data})"
+ }
+
+ private val liftProcInstr = Liftable { pi: ProcInstr =>
+ q"new $sx.ProcInstr(${pi.target}, ${pi.proctext})"
+ }
+
+ private val liftUnparsed = Liftable { u: Unparsed =>
+ q"new $sx.Unparsed(${u.data})"
+ }
+
+ private val liftEntityRef = Liftable { er: EntityRef =>
+ q"new $sx.EntityRef(${er.name})"
+ }
+}
+
+private object Liftables {
+ class Scope(val isTopScope: Boolean) extends AnyVal
+ final val TopScope = new Scope(true)
+}
diff --git a/quote/src/main/scala/scala/xml/quote/internal/QuoteImpl.scala b/quote/src/main/scala/scala/xml/quote/internal/QuoteImpl.scala
new file mode 100644
index 000000000..c358b69df
--- /dev/null
+++ b/quote/src/main/scala/scala/xml/quote/internal/QuoteImpl.scala
@@ -0,0 +1,86 @@
+package scala.xml.quote.internal
+
+import fastparse.all._
+
+import scala.collection.mutable.ArrayBuffer
+import scala.reflect.macros.whitebox
+import scala.xml.quote.internal.QuoteImpl._
+
+class QuoteImpl(val c: whitebox.Context) extends Liftables with Transform {
+ import c.universe._
+
+ private lazy val q"$_($_(..$parts)).xml.apply[..$_](..$args)" = c.macroApplication
+
+ def apply[T](args: Tree*): Tree = {
+ val nodes = transform(parsedXml)
+ lift(nodes)
+ }
+
+ private[internal] def arg(i: Int): Tree = args(i)
+
+ private[internal] def abort(offset: Int, msg: String): Nothing = {
+ val pos = correspondingPosition(offset)
+ c.abort(pos, msg)
+ }
+
+ private lazy val (xmlStr, offsets) = {
+ val sb = new StringBuilder
+ val poss = ArrayBuffer.empty[Int]
+
+ def appendPart(part: Tree) = {
+ val q"${value: String}" = part
+ poss += sb.length
+ sb ++= value
+ poss += sb.length
+ }
+
+ def appendHole(i: Int) =
+ sb ++= Hole.encode(i)
+
+ for ((part, i) <- parts.init.zipWithIndex) {
+ appendPart(part)
+ appendHole(i)
+ }
+ appendPart(parts.last)
+
+ (sb.toString, poss.toArray)
+ }
+
+ /** Given an offset in the xmlString computes the corresponding position */
+ private def correspondingPosition(offset: Int): Position = {
+ val index = offsets.lastIndexWhere(offset >= _)
+ val isWithinHoleOrAtTheEnd = index % 2 != 0
+
+ if (isWithinHoleOrAtTheEnd) {
+ val prevPartIndex = (index - 1) / 2
+ val pos = parts(prevPartIndex).pos
+ val posOffset = offset - offsets(index - 1)
+ pos.withPoint(pos.point + posOffset)
+ } else {
+ val partIndex = index / 2
+ val pos = parts(partIndex).pos
+ val posOffset = offset - offsets(index)
+ pos.withPoint(pos.point + posOffset)
+ }
+ }
+
+ private def parsedXml: Seq[ast.Node] = {
+ xmlParser.XmlExpr.parse(xmlStr) match {
+ case Parsed.Success(nodes, _) => nodes
+ case Parsed.Failure(expected, offset, _) =>
+ abort(offset, s"expected: $expected")
+ }
+ }
+
+ def pp[T <: Tree](t: T): T = {
+ println(showCode(t, printIds = true))
+ t
+ }
+}
+
+private object QuoteImpl {
+ val xmlParser = {
+ val Placeholder = P( Index ~ Hole.Parser ).map { case (pos, id) => ast.Placeholder(id, pos) }
+ new XmlParser(Placeholder)
+ }
+}
diff --git a/quote/src/main/scala/scala/xml/quote/internal/Transform.scala b/quote/src/main/scala/scala/xml/quote/internal/Transform.scala
new file mode 100644
index 000000000..a0d7f7348
--- /dev/null
+++ b/quote/src/main/scala/scala/xml/quote/internal/Transform.scala
@@ -0,0 +1,110 @@
+package scala.xml.quote.internal
+
+import ast._
+import scala.collection.mutable.ListBuffer
+
+/** Apply transformations and validity checks to the xml tree.
+ */
+private[internal] trait Transform { self: QuoteImpl =>
+
+ def transform(nodes: Seq[Node]): Seq[Node] =
+ nodes.map(transform)
+
+ def transform(node: Node): Node = node match {
+ case elem: Elem =>
+ validateAttributes(elem.attributes)
+
+ var children = elem.children.map(transform)
+ if (XmlSettings.isCoalescing) children = coalesce(children)
+
+ val isGroup = elem.name == "xml:group" && !elem.minimizeEmpty // is Elem in scalac
+ if (isGroup) Group(children, elem.pos)
+ else elem.copy(children = children)
+
+ case _ =>
+ node
+ }
+
+ /** Merge text sections */
+ private def coalesce(nodes: Seq[Node]): Seq[Node] = {
+ val buf = new ListBuffer[Node]
+ val sb = new StringBuilder
+ var pos = -1
+
+ def purgeText() = {
+ if (sb.nonEmpty) {
+ buf += Text(sb.result(), pos)
+ pos = -1
+ sb.clear()
+ }
+ }
+
+ def setPos(newPos: Position) = {
+ if (pos < 0) pos = newPos
+ }
+
+ nodes.foreach {
+ case Text(text, pos) =>
+ setPos(pos)
+ sb ++= text
+ case PCData(data, pos) =>
+ setPos(pos)
+ sb ++= data
+ case n =>
+ purgeText()
+ buf += n
+ }
+
+ purgeText()
+ buf.toList
+ }
+
+ import self.c.{Type, typeOf}
+ private val StringTpe = typeOf[String]
+ private val SeqOfNodeTpe = typeOf[Seq[scala.xml.Node]]
+ private val OptionOfSeqOfNodeTpe = typeOf[Option[Seq[scala.xml.Node]]]
+
+ private def validateAttributes(atts: Seq[Attribute]): Unit = {
+ val duplicates = atts
+ .groupBy(_.name)
+ .collect { case (_, as) if as.size > 1 => as.head }
+
+ duplicates.foreach { dup =>
+ val msg = s"attribute ${dup.name} may only be defined once"
+ self.abort(dup.pos, msg)
+ }
+
+ // constructors overload resolution
+ atts.foreach { att =>
+ att.value match {
+ case Seq(p: Placeholder) =>
+ val expected =
+ if (att.isNamespace) Seq(StringTpe)
+ else Seq(StringTpe, SeqOfNodeTpe, OptionOfSeqOfNodeTpe)
+ typeCheck(p, expected)
+
+ case nodeSeq if nodeSeq.size > 1 && att.isNamespace =>
+ typeMismatch(nodeSeq.head.pos, "scala.xml.NodeBuffer", "String")
+
+ case _ =>
+ }
+ }
+ }
+
+ private def typeCheck(p: Placeholder, expected: Seq[Type]): Unit = {
+ val tpe = self.arg(p.id).tpe
+
+ if (!expected.exists(tpe <:< _)) {
+ typeMismatch(p.pos, tpe.toString, expected.mkString(" | "))
+ }
+ }
+
+ private def typeMismatch(pos: Position, found: String, required: String): Unit = {
+ val msg =
+ s"""type mismatch;
+ | found : $found
+ | required: $required
+ """.stripMargin
+ self.abort(pos, msg)
+ }
+}
diff --git a/quote/src/main/scala/scala/xml/quote/internal/XmlParser.scala b/quote/src/main/scala/scala/xml/quote/internal/XmlParser.scala
new file mode 100644
index 000000000..acb4e4286
--- /dev/null
+++ b/quote/src/main/scala/scala/xml/quote/internal/XmlParser.scala
@@ -0,0 +1,128 @@
+package scala.xml.quote
+package internal
+
+import fastparse.all._
+
+import scala.xml.parsing.TokenTests
+import internal.{ast => p}
+
+private[internal] class XmlParser(Hole: P[p.Placeholder]) extends TokenTests {
+ import XmlParser._
+
+ private val S = CharsWhile(isSpace).opaque("whitespace")
+
+ val XmlExpr: P[Seq[p.Node]] = P( S.? ~ Xml.XmlContent.rep(min = 1, sep = S.?) ~ S.? ~ End )
+ val XmlPattern: P[p.Node] = P( S.? ~ Xml.ElemPattern ~ S.? ~ End )
+
+ private[this] object Xml {
+
+ val Elem: P[p.Node] = P( Index ~ TagHeader ~/ TagRest ).map {
+ case (pos, (name, atts), children: Seq[p.Node @unchecked]) =>
+ p.Elem(name, atts, minimizeEmpty = false, children, pos)
+ case (pos, (name, atts), _) =>
+ p.Elem(name, atts, minimizeEmpty = true, Nil, pos)
+ }
+
+ val TagHeader = P( "<" ~ Name ~/ (S ~ Attribute).rep ~/ S.? )
+ val TagRest = P( "/>" | ">" ~/ Content ~/ ETag ): P[Any] // P[Unit | Seq[p.Node]]
+ val ETag = P( "" ~ Name ~ S.? ~ ">" ).toP0
+
+// // This parser respect tag's balance but reports wrong positions on failure
+// val Elem = P(
+// for {
+// pos <- Index
+// (name, atts) <- TagHeader
+// children <- TagRest(name)
+// } yield children match {
+// case cs: Seq[p.Node @unchecked] => p.Elem(name, atts, minimizeEmpty = false, cs, 0)
+// case _ => p.Elem(name, atts, minimizeEmpty = false, Nil, 0)
+// }
+// )
+//
+// val TagHeader = P( "<" ~ Name ~/ (WL ~ Attribute).rep ~/ WL.? )
+// def TagRest(name: String) = P( "/>" | ">" ~/ Content ~/ ETag(name) ): P[Any] // P[Unit | Seq[p.Node]]
+// def ETag(name: String) = P( "" ~ name ~ WL.? ~ ">" )
+
+ val Attribute = P( Index ~ Name ~/ Eq ~/ AttValue ).map {
+ case (pos, name, value) => p.Attribute(name, value, pos)
+ }
+ val Eq = P( S.? ~ "=" ~ S.? )
+ val AttValue = P(
+ "\"" ~/ (CharQ | Reference).rep.!.map(Left.apply) ~ "\"" |
+ "'" ~/ (CharA | Reference).rep.!.map(Left.apply) ~ "'" |
+ ScalaExpr.map(Right.apply)
+ ): P[p.Attribute.AttValue]
+
+ val Content = P( (CharData | Reference | ScalaExpr | XmlContent).rep )
+ val XmlContent: P[p.Node] = P( Unparsed | CDSect | PI | Comment | Elem )
+
+ val ScalaExpr = Hole
+
+ val Unparsed = P( Index ~ UnpStart ~/ UnpData.! ~ UnpEnd ).map { case (pos, data) => p.Unparsed(data, pos) }
+ val UnpStart = P( "" ).toP0
+ val UnpEnd = P( "" )
+ val UnpData = P( (!UnpEnd ~ Char).rep )
+
+ val CDSect = P( Index ~ CDStart ~/ CData.! ~ CDEnd ).map { case (pos, data) => p.PCData(data, pos) }
+ val CDStart = P( "" ~ Char).rep )
+ val CDEnd = P( "]]>" )
+
+ val Comment = P( Index ~ "" ).map { case (pos, text) => p.Comment(text, pos) }
+ val ComText = P( (!"-->" ~ Char).rep )
+
+ val PI = P( Index ~ "" ~ Name ~ S.? ~ PIProcText.! ~ "?>" ).map {
+ case (pos, target, text) => p.ProcInstr(target, text, pos)
+ }
+ val PIProcText = P( (!"?>" ~ Char).rep )
+
+ val Reference = P( EntityRef | CharRef )
+ val EntityRef = P( Index ~ "&" ~ Name ~/ ";" ).map { case (pos, name) => p.EntityRef(name, pos) }
+ val CharRef = P( Index ~ ("" ~ Num ~ ";" | "" ~ HexNum ~ ";") ).map {
+ case (pos, cr) => p.Text(cr.toString, pos)
+ }
+
+ val Num = P( CharIn('0' to '9').rep.! ).map(n => charValueOf(n))
+ val HexNum = P( CharIn('0' to '9', 'a' to 'f', 'A' to 'F').rep.! ).map(n => charValueOf(n, 16))
+
+ val CharData = P( Index ~ Char1.rep(1).! ).map { case (pos, text) => p.Text(text, pos) }
+
+ val Char = P( !Hole ~ AnyChar )
+ val Char1 = P( !("<" | "&") ~ Char )
+ val CharQ = P( !"\"" ~ Char1 )
+ val CharA = P( !"'" ~ Char1 )
+
+ val Name = P( NameStart ~ NameChar.rep ).!.filter(_.last != ':').opaque("Name")
+ val NameStart = P( CharPred(isNameStart) )
+ val NameChar = P( CharPred(isNameChar) )
+
+ val ElemPattern: P[p.Node] = P( Index ~ TagPHeader ~ TagPRest ).map {
+ case (pos, name, children: Seq[p.Node @unchecked]) =>
+ p.Elem(name, Nil, minimizeEmpty = false, children, pos)
+ case (pos, name, _) =>
+ p.Elem(name, Nil, minimizeEmpty = true, Nil, pos)
+ }
+
+ val TagPHeader = P( "<" ~ Name ~/ S.? )
+ val TagPRest = P( "/>" | ">" ~/ ContentP ~/ ETag ): P[Any] // P[Unit | Seq[p.Node]]
+
+ val ContentP = P( (ScalaPatterns | ElemPattern | CharDataP ).rep )
+ // matches weirdness of scalac parser on xml reference.
+ val CharDataP = P( Index ~ ("&" ~ CharData.? | CharData).! ).map { case (pos, text) => p.Text(text, pos) }
+
+ val ScalaPatterns = ScalaExpr
+ }
+}
+
+
+private[internal] object XmlParser {
+
+ def charValueOf(cr: String, radix: Int = 10): Char =
+ if (cr.isEmpty) 0.toChar
+ else java.lang.Integer.parseInt(cr, radix).toChar
+
+ private implicit class ParserOps[T](val self: P[T]) extends AnyVal {
+ /** Discard the result of this parser */
+ def toP0: P0 = self.map(_ => Unit)
+ }
+}
diff --git a/quote/src/main/scala/scala/xml/quote/internal/XmlSettings.scala b/quote/src/main/scala/scala/xml/quote/internal/XmlSettings.scala
new file mode 100644
index 000000000..7bf3fca31
--- /dev/null
+++ b/quote/src/main/scala/scala/xml/quote/internal/XmlSettings.scala
@@ -0,0 +1,12 @@
+package scala.xml.quote.internal
+
+private[internal] object XmlSettings {
+
+ /** Convert PCData to Text and coalesce sibling nodes
+ *
+ * Coalescing defaults to false from scala 2.12.
+ * See [[https://github.com/scala/scala/commit/be9450b2cffe3b1ee723fc7e2f5df83644b35a66]]
+ */
+ def isCoalescing: Boolean =
+ util.Properties.versionNumberString < "2.12"
+}
diff --git a/quote/src/main/scala/scala/xml/quote/internal/ast.scala b/quote/src/main/scala/scala/xml/quote/internal/ast.scala
new file mode 100644
index 000000000..aebfe3dd0
--- /dev/null
+++ b/quote/src/main/scala/scala/xml/quote/internal/ast.scala
@@ -0,0 +1,130 @@
+package scala.xml.quote.internal
+
+import scala.collection.mutable.ListBuffer
+
+private[internal] object ast {
+
+ type Position = Int
+ trait Positioned {
+ def pos: Position
+ }
+
+ abstract class Node extends Positioned
+
+ /** */
+ final case class Group(nodes: Seq[Node], pos: Position) extends Node
+
+ /**
+ *
+ *
+ *
+ */
+ final case class Elem(name: String,
+ attributes: Seq[Attribute],
+ minimizeEmpty: Boolean,
+ children: Seq[Node],
+ pos: Position) extends Node {
+ def prefix: String = name.take(prefixEnd)
+ def label: String = name.drop(prefixEnd + 1)
+ private def prefixEnd = name.indexOf(':')
+ }
+
+ /** text */
+ final case class Text(text: String, pos: Position) extends Node
+
+ final case class Placeholder(id: Int, pos: Position) extends Node
+
+ /** */
+ final case class Comment(text: String, pos: Position) extends Node
+
+ /** */
+ final case class PCData(data: String, pos: Position) extends Node
+
+ /** */
+ final case class ProcInstr(target: String, proctext: String, pos: Position) extends Node
+
+ /** data */
+ final case class Unparsed(data: String, pos: Position) extends Node
+
+ /** &entityName; */
+ final case class EntityRef(name: String, pos: Position) extends Node
+
+ /**
+ *
+ * @param value is `Text` or `{scalaExpression}`
+ */
+ final case class Attribute(name: String, value: Seq[Node], pos: Position) extends Positioned {
+ def prefix: String = name.take(prefixEnd)
+ def key: String = name.drop(prefixEnd + 1)
+ // wrong but like scalac (e.g. xmlnsfoo is a namespace)
+ def isNamespace = name.startsWith("xmlns")
+ private def prefixEnd = name.indexOf(':')
+ }
+
+ object Attribute {
+
+ type AttValue = Either[String, Placeholder]
+
+ def apply(name: String, value0: AttValue, pos: Position): Attribute = {
+ val value = value0 match {
+ case Left(s) => normalizeAttValue(s, pos)
+ case Right(p) => Seq(p)
+ }
+ Attribute(name, value, pos)
+ }
+
+ /** Replaces character and entity references */
+ private def normalizeAttValue(value: String, pos0: Position): Seq[Node] = {
+ def ref(it : Iterator[Char]) = it.takeWhile(_ != ';').mkString
+
+ val it = value.iterator.buffered
+ val buf = new ListBuffer[Node]
+ val sb = new StringBuilder
+ var pos = pos0
+
+ def purgeText() = {
+ if (sb.nonEmpty) {
+ buf += Text(sb.result(), pos)
+ sb.clear()
+ }
+ }
+
+ while (it.hasNext) { pos += 1; it.next() } match {
+ case ' ' | '\t' | '\n' | '\r' =>
+ sb += ' '
+
+ case '&' if it.head == '#' =>
+ it.next()
+ val radix =
+ if (it.head == 'x') { it.next(); 16 }
+ else 10
+ sb += XmlParser.charValueOf(ref(it), radix)
+
+ case '&' =>
+ val name = ref(it)
+ attrUnescape.get(name) match {
+ case Some(c) =>
+ sb += c
+ case _ =>
+ purgeText()
+ buf += EntityRef(name, pos)
+ }
+
+ case c =>
+ sb += c
+
+ }
+
+ purgeText()
+ buf.result()
+ }
+
+ private val attrUnescape = Map(
+ "lt" -> '<',
+ "gt" -> '>',
+ "apos" -> '\'',
+ "quot" -> '"',
+ "quote" -> '"'
+ )
+ }
+}
diff --git a/quote/src/main/scala/scala/xml/quote/quote.scala b/quote/src/main/scala/scala/xml/quote/quote.scala
new file mode 100644
index 000000000..424699adc
--- /dev/null
+++ b/quote/src/main/scala/scala/xml/quote/quote.scala
@@ -0,0 +1,12 @@
+package scala.xml
+
+import scala.language.experimental.macros
+import scala.xml.quote.internal.QuoteImpl
+
+package object quote {
+ implicit class XmlQuote(ctx: StringContext) {
+ object xml {
+ def apply[T](args: T*): Seq[Node] = macro QuoteImpl.apply[T]
+ }
+ }
+}
diff --git a/quote/src/test/scala/scala/xml/quote/NamespaceSuite.scala b/quote/src/test/scala/scala/xml/quote/NamespaceSuite.scala
new file mode 100644
index 000000000..160a344ac
--- /dev/null
+++ b/quote/src/test/scala/scala/xml/quote/NamespaceSuite.scala
@@ -0,0 +1,42 @@
+package scala.xml.quote
+
+class NamespaceSuite extends XmlQuoteSuite {
+
+ test("reconstruct not prefixed namespaced elem") {
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct namespaced elem") {
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct multi-namespaced elem") {
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct nested namespaced elem") {
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct shadowed namespaced elem") {
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct nested unquoted elems") {
+ assert(xml"""${ xml"" }""" ≈
+ { })
+
+ assert(xml"""${ xml"""""" }""" ≈
+ { })
+
+ val b =
+ assert(xml"""${ xml"" }""" !≈
+ xml"""$b""")
+
+ val _ = xml"""${ () => xml"" }""" // should compile
+ }
+
+ test("invalid namespace") {
+ " xml\"\"\"\"\"\" " shouldNot typeCheck
+ }
+}
diff --git a/quote/src/test/scala/scala/xml/quote/ScalacBugParitySuite.scala b/quote/src/test/scala/scala/xml/quote/ScalacBugParitySuite.scala
new file mode 100644
index 000000000..f62915dc4
--- /dev/null
+++ b/quote/src/test/scala/scala/xml/quote/ScalacBugParitySuite.scala
@@ -0,0 +1,25 @@
+package scala.xml.quote
+
+class ScalacBugParitySuite extends XmlQuoteSuite {
+
+ test("empty CharRef") {
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ }
+
+ test("closing PCData tag in text") {
+ assert(xml"""]]> """ ≈ ]]> )
+ }
+
+ test("minimized empty group is not a group") {
+ assert(xml"" ≈ )
+ assert(xml"" !≈ xml"")
+ assert(xml"".isInstanceOf[xml.Elem])
+ }
+
+ test("malformed namespace") {
+ assert(xml"""""" ≈ )
+ }
+}
diff --git a/quote/src/test/scala/scala/xml/quote/SimpleNodeSuite.scala b/quote/src/test/scala/scala/xml/quote/SimpleNodeSuite.scala
new file mode 100644
index 000000000..14aee92c2
--- /dev/null
+++ b/quote/src/test/scala/scala/xml/quote/SimpleNodeSuite.scala
@@ -0,0 +1,124 @@
+package scala.xml.quote
+
+class SimpleNodeSuite extends XmlQuoteSuite {
+
+ test("reconstruct sequence of nodes") {
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct minimized elem") {
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct maximized elem") {
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct prefixed elem") {
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct nested elem") {
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct elem with unprefixed attributes") {
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct elem with prefixed attributes") {
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct elem with attributes") {
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct Text") {
+ assert(xml"Hello" ≈ Hello)
+ assert(xml">" ≈ >)
+ assert(xml"{" ≈ {{)
+ assert(xml"}" ≈ }})
+ }
+
+ test("reconstruct EntityRef") {
+ assert(xml"&name;" ≈ &name;)
+ assert(xml"<" ≈ <)
+ assert(xml"Hello &name;!" ≈ Hello &name;!)
+ assert(xml"&na:me;" ≈ &na:me;)
+
+ // In attribute position
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct CharRef") {
+ assert(xml"Ӓ" ≈ Ӓ)
+ assert(xml"ሴ" ≈ ሴ)
+ assert(xml"HelloሴAllan" ≈ HelloሴAllan)
+
+ // In attribute position
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ assert(xml"""""" ≈ )
+ }
+
+ test("reconstruct group") {
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct Comment") {
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct PCData") {
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+
+ assert(xml"]]>" ≈ ]]>)
+ assert(xml"]]>" ≈ ]]>)
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct ProcInstr") {
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ assert(xml"" ≈ )
+ }
+
+ test("reconstruct unparsed") {
+ assert(xml"foo" ≈ foo)
+ assert(xml"{" ≈ {)
+ assert(xml"<" ≈ <)
+ }
+
+ test("reconstruct coalescing elems") {
+ assert(xml"" ≈ )
+
+ assert(xml"" ≈
+ )
+
+ assert(xml"x" ≈
+ x)
+
+ assert(xml"" ≈
+ )
+
+ assert(xml"" ≈
+ )
+
+ assert(xml"startworldstuff" ≈
+ startworldstuff)
+ }
+}
diff --git a/quote/src/test/scala/scala/xml/quote/TrailingWhiteSpaceSuite.scala b/quote/src/test/scala/scala/xml/quote/TrailingWhiteSpaceSuite.scala
new file mode 100644
index 000000000..9d1447ed1
--- /dev/null
+++ b/quote/src/test/scala/scala/xml/quote/TrailingWhiteSpaceSuite.scala
@@ -0,0 +1,30 @@
+package scala.xml.quote
+
+class TrailingWhiteSpaceSuite extends XmlQuoteSuite {
+
+ test("discard outer trailing whitespace") {
+ assert(xml" " ≈ )
+ assert(xml" " ≈ )
+ assert(xml" " ≈ )
+ }
+
+ test("keep trailing whitespaces in elem content") {
+ assert(xml" " ≈ )
+ assert(xml" " ≈ )
+ }
+
+ test("reconstruct multiline element") {
+ val xml1 = xml"""
+
+
+
+ """
+
+ val xml2 =
+
+
+
+
+ assert(xml1 ≈ xml2)
+ }
+}
diff --git a/quote/src/test/scala/scala/xml/quote/UnquoteSuite.scala b/quote/src/test/scala/scala/xml/quote/UnquoteSuite.scala
new file mode 100644
index 000000000..8f703bc81
--- /dev/null
+++ b/quote/src/test/scala/scala/xml/quote/UnquoteSuite.scala
@@ -0,0 +1,44 @@
+package scala.xml.quote
+
+class UnquoteSuite extends XmlQuoteSuite {
+
+ test("unquote within elem") {
+ assert(xml"${2}" ≈ {2})
+ assert(xml"${"bar"}" ≈ {"bar"})
+
+ assert(xml"1" !≈ xml"${1}")
+
+ assert(xml"${1}${2}" ≈ {1}{2})
+
+ assert(xml"${}" ≈ {})
+ assert(xml"${}" ≈ {})
+ }
+
+ test("unquote within attribute") {
+ assert(xml"" ≈ )
+ assert(xml"}/>" ≈ }/>)
+ assert(xml"}/>" ≈ }/>)
+ assert(xml"" ≈ )
+
+ """ xml"" """ shouldNot typeCheck
+ }
+
+ test("unquote iterable") {
+ assert(xml"${ List(1, 2) }" ≈ { List(1, 2) })
+ }
+
+ test("nested unquote") {
+ assert(xml"${xml"${1}"}" ≈ {{1}})
+ }
+
+ test("unquote unit") {
+ assert(xml"${}" ≈ {})
+ }
+
+ test("unquote within namespace") {
+ assert(xml"" ≈ )
+
+ """ xml"} />" """ shouldNot typeCheck
+ """ xml"" """ shouldNot typeCheck
+ }
+}
diff --git a/quote/src/test/scala/scala/xml/quote/XmlQuoteSuite.scala b/quote/src/test/scala/scala/xml/quote/XmlQuoteSuite.scala
new file mode 100644
index 000000000..a83667ab0
--- /dev/null
+++ b/quote/src/test/scala/scala/xml/quote/XmlQuoteSuite.scala
@@ -0,0 +1,41 @@
+package scala.xml.quote
+
+import org.scalatest.{FunSuite, Matchers}
+
+abstract class XmlQuoteSuite extends FunSuite with Matchers {
+
+ implicit class NodeOps(val self: xml.Node) {
+ /** Like `==` with scope comparison */
+ def ≈(that: xml.Node): Boolean =
+ self == that && hasSameScope(self, that)
+
+ def !≈(that: xml.Node): Boolean = !(self ≈ that)
+
+ private def hasSameScope(self: xml.Node, that: xml.Node): Boolean =
+ self.scope == that.scope && {
+ val zipped = (self, that) match {
+ case (g1: xml.Group, g2: xml.Group) => (g1.nodes, g2.nodes).zipped
+ case (n1, n2) => (n1.child, n2.child).zipped
+ }
+ zipped.forall(hasSameScope)
+ }
+ }
+
+ implicit class NodeBufferOps(val self: xml.NodeBuffer) {
+ /** Like `==` with scope comparison */
+ def ≈(that: xml.NodeBuffer): Boolean = {
+ val selfIt = self.iterator
+ val thatIt = that.iterator
+
+ while (selfIt.hasNext && thatIt.hasNext) {
+ if (!(selfIt.next() ≈ thatIt.next())) {
+ return false
+ }
+ }
+
+ selfIt.isEmpty && thatIt.isEmpty
+ }
+
+ def !≈(that: xml.NodeBuffer): Boolean = !(self ≈ that)
+ }
+}
diff --git a/jvm/src/test/scala/scala/xml/CompilerErrors.scala b/xml/jvm/src/test/scala/scala/xml/CompilerErrors.scala
similarity index 100%
rename from jvm/src/test/scala/scala/xml/CompilerErrors.scala
rename to xml/jvm/src/test/scala/scala/xml/CompilerErrors.scala
diff --git a/jvm/src/test/scala/scala/xml/ReuseNodesTest.scala b/xml/jvm/src/test/scala/scala/xml/ReuseNodesTest.scala
similarity index 100%
rename from jvm/src/test/scala/scala/xml/ReuseNodesTest.scala
rename to xml/jvm/src/test/scala/scala/xml/ReuseNodesTest.scala
diff --git a/jvm/src/test/scala/scala/xml/XMLSyntaxTest.scala b/xml/jvm/src/test/scala/scala/xml/XMLSyntaxTest.scala
similarity index 100%
rename from jvm/src/test/scala/scala/xml/XMLSyntaxTest.scala
rename to xml/jvm/src/test/scala/scala/xml/XMLSyntaxTest.scala
diff --git a/jvm/src/test/scala/scala/xml/XMLTest.scala b/xml/jvm/src/test/scala/scala/xml/XMLTest.scala
similarity index 100%
rename from jvm/src/test/scala/scala/xml/XMLTest.scala
rename to xml/jvm/src/test/scala/scala/xml/XMLTest.scala
diff --git a/jvm/src/test/scala/scala/xml/parsing/ConstructingParserTest.scala b/xml/jvm/src/test/scala/scala/xml/parsing/ConstructingParserTest.scala
similarity index 100%
rename from jvm/src/test/scala/scala/xml/parsing/ConstructingParserTest.scala
rename to xml/jvm/src/test/scala/scala/xml/parsing/ConstructingParserTest.scala
diff --git a/jvm/src/test/scala/scala/xml/parsing/PiParsingTest.scala b/xml/jvm/src/test/scala/scala/xml/parsing/PiParsingTest.scala
similarity index 100%
rename from jvm/src/test/scala/scala/xml/parsing/PiParsingTest.scala
rename to xml/jvm/src/test/scala/scala/xml/parsing/PiParsingTest.scala
diff --git a/jvm/src/test/scala/scala/xml/parsing/Ticket0632Test.scala b/xml/jvm/src/test/scala/scala/xml/parsing/Ticket0632Test.scala
similarity index 100%
rename from jvm/src/test/scala/scala/xml/parsing/Ticket0632Test.scala
rename to xml/jvm/src/test/scala/scala/xml/parsing/Ticket0632Test.scala
diff --git a/jvm/src/test/scala/scala/xml/pull/XMLEventReaderTest.scala b/xml/jvm/src/test/scala/scala/xml/pull/XMLEventReaderTest.scala
similarity index 100%
rename from jvm/src/test/scala/scala/xml/pull/XMLEventReaderTest.scala
rename to xml/jvm/src/test/scala/scala/xml/pull/XMLEventReaderTest.scala
diff --git a/shared/src/main/scala/scala/xml/Atom.scala b/xml/shared/src/main/scala/scala/xml/Atom.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Atom.scala
rename to xml/shared/src/main/scala/scala/xml/Atom.scala
diff --git a/shared/src/main/scala/scala/xml/Attribute.scala b/xml/shared/src/main/scala/scala/xml/Attribute.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Attribute.scala
rename to xml/shared/src/main/scala/scala/xml/Attribute.scala
diff --git a/shared/src/main/scala/scala/xml/Comment.scala b/xml/shared/src/main/scala/scala/xml/Comment.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Comment.scala
rename to xml/shared/src/main/scala/scala/xml/Comment.scala
diff --git a/shared/src/main/scala/scala/xml/Document.scala b/xml/shared/src/main/scala/scala/xml/Document.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Document.scala
rename to xml/shared/src/main/scala/scala/xml/Document.scala
diff --git a/shared/src/main/scala/scala/xml/Elem.scala b/xml/shared/src/main/scala/scala/xml/Elem.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Elem.scala
rename to xml/shared/src/main/scala/scala/xml/Elem.scala
diff --git a/shared/src/main/scala/scala/xml/EntityRef.scala b/xml/shared/src/main/scala/scala/xml/EntityRef.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/EntityRef.scala
rename to xml/shared/src/main/scala/scala/xml/EntityRef.scala
diff --git a/shared/src/main/scala/scala/xml/Equality.scala b/xml/shared/src/main/scala/scala/xml/Equality.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Equality.scala
rename to xml/shared/src/main/scala/scala/xml/Equality.scala
diff --git a/shared/src/main/scala/scala/xml/Group.scala b/xml/shared/src/main/scala/scala/xml/Group.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Group.scala
rename to xml/shared/src/main/scala/scala/xml/Group.scala
diff --git a/shared/src/main/scala/scala/xml/MalformedAttributeException.scala b/xml/shared/src/main/scala/scala/xml/MalformedAttributeException.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/MalformedAttributeException.scala
rename to xml/shared/src/main/scala/scala/xml/MalformedAttributeException.scala
diff --git a/shared/src/main/scala/scala/xml/MetaData.scala b/xml/shared/src/main/scala/scala/xml/MetaData.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/MetaData.scala
rename to xml/shared/src/main/scala/scala/xml/MetaData.scala
diff --git a/shared/src/main/scala/scala/xml/NamespaceBinding.scala b/xml/shared/src/main/scala/scala/xml/NamespaceBinding.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/NamespaceBinding.scala
rename to xml/shared/src/main/scala/scala/xml/NamespaceBinding.scala
diff --git a/shared/src/main/scala/scala/xml/Node.scala b/xml/shared/src/main/scala/scala/xml/Node.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Node.scala
rename to xml/shared/src/main/scala/scala/xml/Node.scala
diff --git a/shared/src/main/scala/scala/xml/NodeBuffer.scala b/xml/shared/src/main/scala/scala/xml/NodeBuffer.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/NodeBuffer.scala
rename to xml/shared/src/main/scala/scala/xml/NodeBuffer.scala
diff --git a/shared/src/main/scala/scala/xml/NodeSeq.scala b/xml/shared/src/main/scala/scala/xml/NodeSeq.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/NodeSeq.scala
rename to xml/shared/src/main/scala/scala/xml/NodeSeq.scala
diff --git a/shared/src/main/scala/scala/xml/Null.scala b/xml/shared/src/main/scala/scala/xml/Null.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Null.scala
rename to xml/shared/src/main/scala/scala/xml/Null.scala
diff --git a/shared/src/main/scala/scala/xml/PCData.scala b/xml/shared/src/main/scala/scala/xml/PCData.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/PCData.scala
rename to xml/shared/src/main/scala/scala/xml/PCData.scala
diff --git a/shared/src/main/scala/scala/xml/PrefixedAttribute.scala b/xml/shared/src/main/scala/scala/xml/PrefixedAttribute.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/PrefixedAttribute.scala
rename to xml/shared/src/main/scala/scala/xml/PrefixedAttribute.scala
diff --git a/shared/src/main/scala/scala/xml/PrettyPrinter.scala b/xml/shared/src/main/scala/scala/xml/PrettyPrinter.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/PrettyPrinter.scala
rename to xml/shared/src/main/scala/scala/xml/PrettyPrinter.scala
diff --git a/shared/src/main/scala/scala/xml/ProcInstr.scala b/xml/shared/src/main/scala/scala/xml/ProcInstr.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/ProcInstr.scala
rename to xml/shared/src/main/scala/scala/xml/ProcInstr.scala
diff --git a/shared/src/main/scala/scala/xml/QNode.scala b/xml/shared/src/main/scala/scala/xml/QNode.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/QNode.scala
rename to xml/shared/src/main/scala/scala/xml/QNode.scala
diff --git a/shared/src/main/scala/scala/xml/SpecialNode.scala b/xml/shared/src/main/scala/scala/xml/SpecialNode.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/SpecialNode.scala
rename to xml/shared/src/main/scala/scala/xml/SpecialNode.scala
diff --git a/shared/src/main/scala/scala/xml/Text.scala b/xml/shared/src/main/scala/scala/xml/Text.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Text.scala
rename to xml/shared/src/main/scala/scala/xml/Text.scala
diff --git a/shared/src/main/scala/scala/xml/TextBuffer.scala b/xml/shared/src/main/scala/scala/xml/TextBuffer.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/TextBuffer.scala
rename to xml/shared/src/main/scala/scala/xml/TextBuffer.scala
diff --git a/shared/src/main/scala/scala/xml/TopScope.scala b/xml/shared/src/main/scala/scala/xml/TopScope.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/TopScope.scala
rename to xml/shared/src/main/scala/scala/xml/TopScope.scala
diff --git a/shared/src/main/scala/scala/xml/TypeSymbol.scala b/xml/shared/src/main/scala/scala/xml/TypeSymbol.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/TypeSymbol.scala
rename to xml/shared/src/main/scala/scala/xml/TypeSymbol.scala
diff --git a/shared/src/main/scala/scala/xml/Unparsed.scala b/xml/shared/src/main/scala/scala/xml/Unparsed.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Unparsed.scala
rename to xml/shared/src/main/scala/scala/xml/Unparsed.scala
diff --git a/shared/src/main/scala/scala/xml/UnprefixedAttribute.scala b/xml/shared/src/main/scala/scala/xml/UnprefixedAttribute.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/UnprefixedAttribute.scala
rename to xml/shared/src/main/scala/scala/xml/UnprefixedAttribute.scala
diff --git a/shared/src/main/scala/scala/xml/Utility.scala b/xml/shared/src/main/scala/scala/xml/Utility.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Utility.scala
rename to xml/shared/src/main/scala/scala/xml/Utility.scala
diff --git a/shared/src/main/scala/scala/xml/XML.scala b/xml/shared/src/main/scala/scala/xml/XML.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/XML.scala
rename to xml/shared/src/main/scala/scala/xml/XML.scala
diff --git a/shared/src/main/scala/scala/xml/Xhtml.scala b/xml/shared/src/main/scala/scala/xml/Xhtml.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/Xhtml.scala
rename to xml/shared/src/main/scala/scala/xml/Xhtml.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/ContentModel.scala b/xml/shared/src/main/scala/scala/xml/dtd/ContentModel.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/ContentModel.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/ContentModel.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/ContentModelParser.scala b/xml/shared/src/main/scala/scala/xml/dtd/ContentModelParser.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/ContentModelParser.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/ContentModelParser.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/DTD.scala b/xml/shared/src/main/scala/scala/xml/dtd/DTD.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/DTD.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/DTD.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/Decl.scala b/xml/shared/src/main/scala/scala/xml/dtd/Decl.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/Decl.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/Decl.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/DocType.scala b/xml/shared/src/main/scala/scala/xml/dtd/DocType.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/DocType.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/DocType.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/ElementValidator.scala b/xml/shared/src/main/scala/scala/xml/dtd/ElementValidator.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/ElementValidator.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/ElementValidator.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/ExternalID.scala b/xml/shared/src/main/scala/scala/xml/dtd/ExternalID.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/ExternalID.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/ExternalID.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/Scanner.scala b/xml/shared/src/main/scala/scala/xml/dtd/Scanner.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/Scanner.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/Scanner.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/Tokens.scala b/xml/shared/src/main/scala/scala/xml/dtd/Tokens.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/Tokens.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/Tokens.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/ValidationException.scala b/xml/shared/src/main/scala/scala/xml/dtd/ValidationException.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/ValidationException.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/ValidationException.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/Base.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/Base.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/Base.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/Base.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/BaseBerrySethi.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/BaseBerrySethi.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/BaseBerrySethi.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/BaseBerrySethi.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/DetWordAutom.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/DetWordAutom.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/DetWordAutom.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/DetWordAutom.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/Inclusion.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/Inclusion.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/Inclusion.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/Inclusion.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/NondetWordAutom.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/NondetWordAutom.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/NondetWordAutom.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/NondetWordAutom.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/PointedHedgeExp.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/PointedHedgeExp.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/PointedHedgeExp.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/PointedHedgeExp.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/SubsetConstruction.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/SubsetConstruction.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/SubsetConstruction.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/SubsetConstruction.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/SyntaxError.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/SyntaxError.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/SyntaxError.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/SyntaxError.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/WordBerrySethi.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/WordBerrySethi.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/WordBerrySethi.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/WordBerrySethi.scala
diff --git a/shared/src/main/scala/scala/xml/dtd/impl/WordExp.scala b/xml/shared/src/main/scala/scala/xml/dtd/impl/WordExp.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/dtd/impl/WordExp.scala
rename to xml/shared/src/main/scala/scala/xml/dtd/impl/WordExp.scala
diff --git a/shared/src/main/scala/scala/xml/factory/Binder.scala b/xml/shared/src/main/scala/scala/xml/factory/Binder.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/factory/Binder.scala
rename to xml/shared/src/main/scala/scala/xml/factory/Binder.scala
diff --git a/shared/src/main/scala/scala/xml/factory/LoggedNodeFactory.scala b/xml/shared/src/main/scala/scala/xml/factory/LoggedNodeFactory.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/factory/LoggedNodeFactory.scala
rename to xml/shared/src/main/scala/scala/xml/factory/LoggedNodeFactory.scala
diff --git a/shared/src/main/scala/scala/xml/factory/NodeFactory.scala b/xml/shared/src/main/scala/scala/xml/factory/NodeFactory.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/factory/NodeFactory.scala
rename to xml/shared/src/main/scala/scala/xml/factory/NodeFactory.scala
diff --git a/shared/src/main/scala/scala/xml/factory/XMLLoader.scala b/xml/shared/src/main/scala/scala/xml/factory/XMLLoader.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/factory/XMLLoader.scala
rename to xml/shared/src/main/scala/scala/xml/factory/XMLLoader.scala
diff --git a/shared/src/main/scala/scala/xml/include/CircularIncludeException.scala b/xml/shared/src/main/scala/scala/xml/include/CircularIncludeException.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/include/CircularIncludeException.scala
rename to xml/shared/src/main/scala/scala/xml/include/CircularIncludeException.scala
diff --git a/shared/src/main/scala/scala/xml/include/UnavailableResourceException.scala b/xml/shared/src/main/scala/scala/xml/include/UnavailableResourceException.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/include/UnavailableResourceException.scala
rename to xml/shared/src/main/scala/scala/xml/include/UnavailableResourceException.scala
diff --git a/shared/src/main/scala/scala/xml/include/XIncludeException.scala b/xml/shared/src/main/scala/scala/xml/include/XIncludeException.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/include/XIncludeException.scala
rename to xml/shared/src/main/scala/scala/xml/include/XIncludeException.scala
diff --git a/shared/src/main/scala/scala/xml/include/sax/EncodingHeuristics.scala b/xml/shared/src/main/scala/scala/xml/include/sax/EncodingHeuristics.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/include/sax/EncodingHeuristics.scala
rename to xml/shared/src/main/scala/scala/xml/include/sax/EncodingHeuristics.scala
diff --git a/shared/src/main/scala/scala/xml/include/sax/XIncludeFilter.scala b/xml/shared/src/main/scala/scala/xml/include/sax/XIncludeFilter.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/include/sax/XIncludeFilter.scala
rename to xml/shared/src/main/scala/scala/xml/include/sax/XIncludeFilter.scala
diff --git a/shared/src/main/scala/scala/xml/include/sax/XIncluder.scala b/xml/shared/src/main/scala/scala/xml/include/sax/XIncluder.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/include/sax/XIncluder.scala
rename to xml/shared/src/main/scala/scala/xml/include/sax/XIncluder.scala
diff --git a/shared/src/main/scala/scala/xml/package.scala b/xml/shared/src/main/scala/scala/xml/package.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/package.scala
rename to xml/shared/src/main/scala/scala/xml/package.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/ConstructingHandler.scala b/xml/shared/src/main/scala/scala/xml/parsing/ConstructingHandler.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/ConstructingHandler.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/ConstructingHandler.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/ConstructingParser.scala b/xml/shared/src/main/scala/scala/xml/parsing/ConstructingParser.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/ConstructingParser.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/ConstructingParser.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/DefaultMarkupHandler.scala b/xml/shared/src/main/scala/scala/xml/parsing/DefaultMarkupHandler.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/DefaultMarkupHandler.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/DefaultMarkupHandler.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/ExternalSources.scala b/xml/shared/src/main/scala/scala/xml/parsing/ExternalSources.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/ExternalSources.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/ExternalSources.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala b/xml/shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/FatalError.scala b/xml/shared/src/main/scala/scala/xml/parsing/FatalError.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/FatalError.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/FatalError.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/MarkupHandler.scala b/xml/shared/src/main/scala/scala/xml/parsing/MarkupHandler.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/MarkupHandler.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/MarkupHandler.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala b/xml/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/MarkupParser.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala b/xml/shared/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala b/xml/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/TokenTests.scala b/xml/shared/src/main/scala/scala/xml/parsing/TokenTests.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/TokenTests.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/TokenTests.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/ValidatingMarkupHandler.scala b/xml/shared/src/main/scala/scala/xml/parsing/ValidatingMarkupHandler.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/ValidatingMarkupHandler.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/ValidatingMarkupHandler.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/XhtmlEntities.scala b/xml/shared/src/main/scala/scala/xml/parsing/XhtmlEntities.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/XhtmlEntities.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/XhtmlEntities.scala
diff --git a/shared/src/main/scala/scala/xml/parsing/XhtmlParser.scala b/xml/shared/src/main/scala/scala/xml/parsing/XhtmlParser.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/parsing/XhtmlParser.scala
rename to xml/shared/src/main/scala/scala/xml/parsing/XhtmlParser.scala
diff --git a/shared/src/main/scala/scala/xml/persistent/CachedFileStorage.scala b/xml/shared/src/main/scala/scala/xml/persistent/CachedFileStorage.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/persistent/CachedFileStorage.scala
rename to xml/shared/src/main/scala/scala/xml/persistent/CachedFileStorage.scala
diff --git a/shared/src/main/scala/scala/xml/persistent/Index.scala b/xml/shared/src/main/scala/scala/xml/persistent/Index.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/persistent/Index.scala
rename to xml/shared/src/main/scala/scala/xml/persistent/Index.scala
diff --git a/shared/src/main/scala/scala/xml/persistent/SetStorage.scala b/xml/shared/src/main/scala/scala/xml/persistent/SetStorage.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/persistent/SetStorage.scala
rename to xml/shared/src/main/scala/scala/xml/persistent/SetStorage.scala
diff --git a/shared/src/main/scala/scala/xml/pull/XMLEvent.scala b/xml/shared/src/main/scala/scala/xml/pull/XMLEvent.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/pull/XMLEvent.scala
rename to xml/shared/src/main/scala/scala/xml/pull/XMLEvent.scala
diff --git a/shared/src/main/scala/scala/xml/pull/XMLEventReader.scala b/xml/shared/src/main/scala/scala/xml/pull/XMLEventReader.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/pull/XMLEventReader.scala
rename to xml/shared/src/main/scala/scala/xml/pull/XMLEventReader.scala
diff --git a/shared/src/main/scala/scala/xml/pull/package.scala b/xml/shared/src/main/scala/scala/xml/pull/package.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/pull/package.scala
rename to xml/shared/src/main/scala/scala/xml/pull/package.scala
diff --git a/shared/src/main/scala/scala/xml/transform/BasicTransformer.scala b/xml/shared/src/main/scala/scala/xml/transform/BasicTransformer.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/transform/BasicTransformer.scala
rename to xml/shared/src/main/scala/scala/xml/transform/BasicTransformer.scala
diff --git a/shared/src/main/scala/scala/xml/transform/RewriteRule.scala b/xml/shared/src/main/scala/scala/xml/transform/RewriteRule.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/transform/RewriteRule.scala
rename to xml/shared/src/main/scala/scala/xml/transform/RewriteRule.scala
diff --git a/shared/src/main/scala/scala/xml/transform/RuleTransformer.scala b/xml/shared/src/main/scala/scala/xml/transform/RuleTransformer.scala
similarity index 100%
rename from shared/src/main/scala/scala/xml/transform/RuleTransformer.scala
rename to xml/shared/src/main/scala/scala/xml/transform/RuleTransformer.scala
diff --git a/shared/src/test/scala/scala/xml/AttributeTest.scala b/xml/shared/src/test/scala/scala/xml/AttributeTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/AttributeTest.scala
rename to xml/shared/src/test/scala/scala/xml/AttributeTest.scala
diff --git a/shared/src/test/scala/scala/xml/JUnitAssertsForXML.scala b/xml/shared/src/test/scala/scala/xml/JUnitAssertsForXML.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/JUnitAssertsForXML.scala
rename to xml/shared/src/test/scala/scala/xml/JUnitAssertsForXML.scala
diff --git a/shared/src/test/scala/scala/xml/MetaDataTest.scala b/xml/shared/src/test/scala/scala/xml/MetaDataTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/MetaDataTest.scala
rename to xml/shared/src/test/scala/scala/xml/MetaDataTest.scala
diff --git a/shared/src/test/scala/scala/xml/NodeBufferTest.scala b/xml/shared/src/test/scala/scala/xml/NodeBufferTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/NodeBufferTest.scala
rename to xml/shared/src/test/scala/scala/xml/NodeBufferTest.scala
diff --git a/shared/src/test/scala/scala/xml/PatternMatching.scala b/xml/shared/src/test/scala/scala/xml/PatternMatching.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/PatternMatching.scala
rename to xml/shared/src/test/scala/scala/xml/PatternMatching.scala
diff --git a/shared/src/test/scala/scala/xml/PrintEmptyElementsTest.scala b/xml/shared/src/test/scala/scala/xml/PrintEmptyElementsTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/PrintEmptyElementsTest.scala
rename to xml/shared/src/test/scala/scala/xml/PrintEmptyElementsTest.scala
diff --git a/shared/src/test/scala/scala/xml/ShouldCompile.scala b/xml/shared/src/test/scala/scala/xml/ShouldCompile.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/ShouldCompile.scala
rename to xml/shared/src/test/scala/scala/xml/ShouldCompile.scala
diff --git a/shared/src/test/scala/scala/xml/Transformers.scala b/xml/shared/src/test/scala/scala/xml/Transformers.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/Transformers.scala
rename to xml/shared/src/test/scala/scala/xml/Transformers.scala
diff --git a/shared/src/test/scala/scala/xml/UtilityTest.scala b/xml/shared/src/test/scala/scala/xml/UtilityTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/UtilityTest.scala
rename to xml/shared/src/test/scala/scala/xml/UtilityTest.scala
diff --git a/shared/src/test/scala/scala/xml/XMLEmbeddingTest.scala b/xml/shared/src/test/scala/scala/xml/XMLEmbeddingTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/XMLEmbeddingTest.scala
rename to xml/shared/src/test/scala/scala/xml/XMLEmbeddingTest.scala
diff --git a/shared/src/test/scala/scala/xml/XMLSyntaxTest.scala b/xml/shared/src/test/scala/scala/xml/XMLSyntaxTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/XMLSyntaxTest.scala
rename to xml/shared/src/test/scala/scala/xml/XMLSyntaxTest.scala
diff --git a/shared/src/test/scala/scala/xml/XMLTest.scala b/xml/shared/src/test/scala/scala/xml/XMLTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/XMLTest.scala
rename to xml/shared/src/test/scala/scala/xml/XMLTest.scala
diff --git a/shared/src/test/scala/scala/xml/parsing/PiParsingTest.scala b/xml/shared/src/test/scala/scala/xml/parsing/PiParsingTest.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/parsing/PiParsingTest.scala
rename to xml/shared/src/test/scala/scala/xml/parsing/PiParsingTest.scala
diff --git a/shared/src/test/scala/scala/xml/parsing/Ticket0632Test.scala b/xml/shared/src/test/scala/scala/xml/parsing/Ticket0632Test.scala
similarity index 100%
rename from shared/src/test/scala/scala/xml/parsing/Ticket0632Test.scala
rename to xml/shared/src/test/scala/scala/xml/parsing/Ticket0632Test.scala