Skip to content

Commit 8e94c6d

Browse files
authored
Merge pull request #164 from ashawley/stack-expunged
Expunge mutable.Stack
2 parents e78456f + 2740495 commit 8e94c6d

File tree

6 files changed

+78
-35
lines changed

6 files changed

+78
-35
lines changed

build.sbt

+13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ lazy val xml = crossProject(JSPlatform, JVMPlatform)
2424
mimaPreviousVersion := {
2525
Some("1.2.0")
2626
},
27+
mimaBinaryIssueFilters ++= {
28+
import com.typesafe.tools.mima.core._
29+
import com.typesafe.tools.mima.core.ProblemFilters._
30+
Seq(
31+
// Scala 2.12 deprecated mutable.Stack, so we broke
32+
// binary compatibility for 1.1.0 in the following way:
33+
exclude[IncompatibleMethTypeProblem]("scala.xml.parsing.FactoryAdapter.scopeStack_="),
34+
exclude[IncompatibleResultTypeProblem]("scala.xml.parsing.FactoryAdapter.hStack"),
35+
exclude[IncompatibleResultTypeProblem]("scala.xml.parsing.FactoryAdapter.scopeStack"),
36+
exclude[IncompatibleResultTypeProblem]("scala.xml.parsing.FactoryAdapter.attribStack"),
37+
exclude[IncompatibleResultTypeProblem]("scala.xml.parsing.FactoryAdapter.tagStack")
38+
)
39+
},
2740

2841
unmanagedSourceDirectories in Compile ++= {
2942
(unmanagedSourceDirectories in Compile).value.map { dir =>

jvm/src/test/scala/scala/xml/XMLTest.scala

+8-8
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class XMLTestJVM {
4141
override def text = ""
4242
}
4343

44-
assertTrue(c == parsedxml11)
45-
assertTrue(parsedxml1 == parsedxml11)
44+
assertEquals(c, parsedxml11)
45+
assertEquals(parsedxml1, parsedxml11)
4646
assertTrue(List(parsedxml1) sameElements List(parsedxml11))
4747
assertTrue(Array(parsedxml1).toList sameElements List(parsedxml11))
4848

@@ -51,10 +51,10 @@ class XMLTestJVM {
5151
val i = new InputSource(new StringReader(x2))
5252
val x2p = scala.xml.XML.load(i)
5353

54-
assertTrue(x2p == Elem(null, "book", e, sc,
54+
assertEquals(Elem(null, "book", e, sc,
5555
Elem(null, "author", e, sc, Text("Peter Buneman")),
5656
Elem(null, "author", e, sc, Text("Dan Suciu")),
57-
Elem(null, "title", e, sc, Text("Data on ze web"))))
57+
Elem(null, "title", e, sc, Text("Data on ze web"))), x2p)
5858

5959
}
6060

@@ -455,16 +455,16 @@ class XMLTestJVM {
455455
@UnitTest
456456
def t6939 = {
457457
val foo = <x:foo xmlns:x="http://foo.com/"><x:bar xmlns:x="http://bar.com/"><x:baz/></x:bar></x:foo>
458-
assertTrue(foo.child.head.scope.toString == """ xmlns:x="http://bar.com/"""")
458+
assertEquals(foo.child.head.scope.toString, """ xmlns:x="http://bar.com/"""")
459459

460460
val fooDefault = <foo xmlns="http://foo.com/"><bar xmlns="http://bar.com/"><baz/></bar></foo>
461-
assertTrue(fooDefault.child.head.scope.toString == """ xmlns="http://bar.com/"""")
461+
assertEquals(fooDefault.child.head.scope.toString, """ xmlns="http://bar.com/"""")
462462

463463
val foo2 = scala.xml.XML.loadString("""<x:foo xmlns:x="http://foo.com/"><x:bar xmlns:x="http://bar.com/"><x:baz/></x:bar></x:foo>""")
464-
assertTrue(foo2.child.head.scope.toString == """ xmlns:x="http://bar.com/"""")
464+
assertEquals(foo2.child.head.scope.toString, """ xmlns:x="http://bar.com/"""")
465465

466466
val foo2Default = scala.xml.XML.loadString("""<foo xmlns="http://foo.com/"><bar xmlns="http://bar.com/"><baz/></bar></foo>""")
467-
assertTrue(foo2Default.child.head.scope.toString == """ xmlns="http://bar.com/"""")
467+
assertEquals(foo2Default.child.head.scope.toString, """ xmlns="http://bar.com/"""")
468468
}
469469

470470
@UnitTest

shared/src/main/scala/scala/xml/dtd/impl/SubsetConstruction.scala

+5-4
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ private[dtd] class SubsetConstruction[T <: AnyRef](val nfa: NondetWordAutom[T])
3232
val delta = new mutable.HashMap[immutable.BitSet, mutable.HashMap[T, immutable.BitSet]]
3333
val deftrans = mutable.Map(q0 -> sink, sink -> sink) // initial transitions
3434
val finals: mutable.Map[immutable.BitSet, Int] = mutable.Map()
35-
val rest = new mutable.Stack[immutable.BitSet]
35+
var rest = immutable.List.empty[immutable.BitSet]
3636

37-
rest.push(sink, q0)
37+
rest = q0 :: sink :: rest
3838

3939
def addFinal(q: immutable.BitSet): Unit = {
4040
if (nfa containsFinal q)
@@ -43,15 +43,16 @@ private[dtd] class SubsetConstruction[T <: AnyRef](val nfa: NondetWordAutom[T])
4343
def add(Q: immutable.BitSet): Unit = {
4444
if (!states(Q)) {
4545
states += Q
46-
rest push Q
46+
rest = Q :: rest
4747
addFinal(Q)
4848
}
4949
}
5050

5151
addFinal(q0) // initial state may also be a final state
5252

5353
while (!rest.isEmpty) {
54-
val P = rest.pop()
54+
val P = rest.head
55+
rest = rest.tail
5556
// assign a number to this bitset
5657
indexMap(P) = ix
5758
invIndexMap(ix) = P

shared/src/main/scala/scala/xml/factory/XMLLoader.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ trait XMLLoader[T <: Node] {
3737
def loadXML(source: InputSource, parser: SAXParser): T = {
3838
val newAdapter = adapter
3939

40-
newAdapter.scopeStack push TopScope
40+
newAdapter.scopeStack = TopScope :: newAdapter.scopeStack
4141
parser.parse(source, newAdapter)
42-
newAdapter.scopeStack.pop()
42+
newAdapter.scopeStack = newAdapter.scopeStack.tail
4343

4444
newAdapter.rootElem.asInstanceOf[T]
4545
}

shared/src/main/scala/scala/xml/include/sax/XIncluder.scala

+3-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ package scala
1010
package xml
1111
package include.sax
1212

13-
import scala.collection.mutable
1413
import org.xml.sax.{ ContentHandler, Locator, Attributes }
1514
import org.xml.sax.ext.LexicalHandler
1615
import java.io.{ OutputStream, OutputStreamWriter, IOException }
@@ -126,7 +125,7 @@ class XIncluder(outs: OutputStream, encoding: String) extends ContentHandler wit
126125

127126
// LexicalHandler methods
128127
private var inDTD: Boolean = false
129-
private val entities = new mutable.Stack[String]()
128+
private var entities = List.empty[String]
130129

131130
def startDTD(name: String, publicID: String, systemID: String): Unit = {
132131
inDTD = true
@@ -146,11 +145,11 @@ class XIncluder(outs: OutputStream, encoding: String) extends ContentHandler wit
146145
def endDTD(): Unit = {}
147146

148147
def startEntity(name: String): Unit = {
149-
entities push name
148+
entities = name :: entities
150149
}
151150

152151
def endEntity(name: String): Unit = {
153-
entities.pop()
152+
entities = entities.tail
154153
}
155154

156155
def startCDATA(): Unit = {}

shared/src/main/scala/scala/xml/parsing/FactoryAdapter.scala

+47-17
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ package scala
1010
package xml
1111
package parsing
1212

13-
import scala.collection.{ mutable, Iterator }
1413
import scala.collection.Seq
1514
import org.xml.sax.Attributes
1615
import org.xml.sax.helpers.DefaultHandler
@@ -40,10 +39,34 @@ abstract class FactoryAdapter extends DefaultHandler with factory.XMLLoader[Node
4039
var rootElem: Node = null
4140

4241
val buffer = new StringBuilder()
43-
val attribStack = new mutable.Stack[MetaData]
44-
val hStack = new mutable.Stack[Node] // [ element ] contains siblings
45-
val tagStack = new mutable.Stack[String]
46-
var scopeStack = new mutable.Stack[NamespaceBinding]
42+
/** List of attributes
43+
*
44+
* Previously was a mutable [[scala.collection.mutable.Stack Stack]], but is now a mutable reference to an immutable [[scala.collection.immutable.List List]].
45+
*
46+
* @since 1.1.0
47+
*/
48+
var attribStack = List.empty[MetaData]
49+
/** List of elements
50+
*
51+
* Previously was a mutable [[scala.collection.mutable.Stack Stack]], but is now a mutable reference to an immutable [[scala.collection.immutable.List List]].
52+
*
53+
* @since 1.1.0
54+
*/
55+
var hStack = List.empty[Node] // [ element ] contains siblings
56+
/** List of element names
57+
*
58+
* Previously was a mutable [[scala.collection.mutable.Stack Stack]], but is now a mutable reference to an immutable [[scala.collection.immutable.List List]].
59+
*
60+
* @since 1.1.0
61+
*/
62+
var tagStack = List.empty[String]
63+
/** List of namespaces
64+
*
65+
* Previously was a mutable [[scala.collection.mutable.Stack Stack]], but is now a mutable reference to an immutable [[scala.collection.immutable.List List]].
66+
*
67+
* @since 1.1.0
68+
*/
69+
var scopeStack = List.empty[NamespaceBinding]
4770

4871
var curTag: String = null
4972
var capture: Boolean = false
@@ -123,17 +146,17 @@ abstract class FactoryAdapter extends DefaultHandler with factory.XMLLoader[Node
123146
attributes: Attributes): Unit =
124147
{
125148
captureText()
126-
tagStack push curTag
149+
tagStack = curTag :: tagStack
127150
curTag = qname
128151

129152
val localName = splitName(qname)._2
130153
capture = nodeContainsText(localName)
131154

132-
hStack push null
155+
hStack = null :: hStack
133156
var m: MetaData = Null
134157
var scpe: NamespaceBinding =
135158
if (scopeStack.isEmpty) TopScope
136-
else scopeStack.top
159+
else scopeStack.head
137160

138161
for (i <- 0 until attributes.getLength()) {
139162
val qname = attributes getQName i
@@ -148,16 +171,16 @@ abstract class FactoryAdapter extends DefaultHandler with factory.XMLLoader[Node
148171
m = Attribute(Option(pre), key, Text(value), m)
149172
}
150173

151-
scopeStack push scpe
152-
attribStack push m
174+
scopeStack = scpe :: scopeStack
175+
attribStack = m :: attribStack
153176
}
154177

155178
/**
156179
* captures text, possibly normalizing whitespace
157180
*/
158181
def captureText(): Unit = {
159182
if (capture && buffer.length > 0)
160-
hStack push createText(buffer.toString)
183+
hStack = createText(buffer.toString) :: hStack
161184

162185
buffer.clear()
163186
}
@@ -171,17 +194,24 @@ abstract class FactoryAdapter extends DefaultHandler with factory.XMLLoader[Node
171194
*/
172195
override def endElement(uri: String, _localName: String, qname: String): Unit = {
173196
captureText()
174-
val metaData = attribStack.pop()
197+
val metaData = attribStack.head
198+
attribStack = attribStack.tail
175199

176200
// reverse order to get it right
177-
val v = (Iterator continually hStack.pop takeWhile (_ != null)).toList.reverse
201+
val v = hStack.takeWhile(_ != null).reverse
202+
hStack = hStack.dropWhile(_ != null) match {
203+
case null :: hs => hs
204+
case hs => hs
205+
}
178206
val (pre, localName) = splitName(qname)
179-
val scp = scopeStack.pop()
207+
val scp = scopeStack.head
208+
scopeStack = scopeStack.tail
180209

181210
// create element
182211
rootElem = createNode(pre, localName, metaData, scp, v)
183-
hStack push rootElem
184-
curTag = tagStack.pop()
212+
hStack = rootElem :: hStack
213+
curTag = tagStack.head
214+
tagStack = tagStack.tail
185215
capture = curTag != null && nodeContainsText(curTag) // root level
186216
}
187217

@@ -190,6 +220,6 @@ abstract class FactoryAdapter extends DefaultHandler with factory.XMLLoader[Node
190220
*/
191221
override def processingInstruction(target: String, data: String): Unit = {
192222
captureText()
193-
hStack pushAll createProcInstr(target, data)
223+
hStack = hStack.reverse_:::(createProcInstr(target, data).toList)
194224
}
195225
}

0 commit comments

Comments
 (0)