From 1aa05b15659484ab854a5bbcac640f08afea4061 Mon Sep 17 00:00:00 2001 From: Allan Renucci Date: Wed, 28 Jun 2017 19:24:02 +0200 Subject: [PATCH 1/2] Move scala-xml to its own subproject --- build.sbt | 2 +- {jvm => xml/jvm}/src/test/scala/scala/xml/CompilerErrors.scala | 0 {jvm => xml/jvm}/src/test/scala/scala/xml/ReuseNodesTest.scala | 0 {jvm => xml/jvm}/src/test/scala/scala/xml/XMLSyntaxTest.scala | 0 {jvm => xml/jvm}/src/test/scala/scala/xml/XMLTest.scala | 0 .../test/scala/scala/xml/parsing/ConstructingParserTest.scala | 0 .../jvm}/src/test/scala/scala/xml/parsing/PiParsingTest.scala | 0 .../jvm}/src/test/scala/scala/xml/parsing/Ticket0632Test.scala | 0 .../jvm}/src/test/scala/scala/xml/pull/XMLEventReaderTest.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Atom.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Attribute.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Comment.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Document.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Elem.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/EntityRef.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Equality.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Group.scala | 0 .../src/main/scala/scala/xml/MalformedAttributeException.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/MetaData.scala | 0 .../shared}/src/main/scala/scala/xml/NamespaceBinding.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Node.scala | 0 .../shared}/src/main/scala/scala/xml/NodeBuffer.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/NodeSeq.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Null.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/PCData.scala | 0 .../shared}/src/main/scala/scala/xml/PrefixedAttribute.scala | 0 .../shared}/src/main/scala/scala/xml/PrettyPrinter.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/ProcInstr.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/QNode.scala | 0 .../shared}/src/main/scala/scala/xml/SpecialNode.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Text.scala | 0 .../shared}/src/main/scala/scala/xml/TextBuffer.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/TopScope.scala | 0 .../shared}/src/main/scala/scala/xml/TypeSymbol.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Unparsed.scala | 0 .../shared}/src/main/scala/scala/xml/UnprefixedAttribute.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Utility.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/XML.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/Xhtml.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/ContentModel.scala | 0 .../src/main/scala/scala/xml/dtd/ContentModelParser.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/dtd/DTD.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/dtd/Decl.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/DocType.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/ElementValidator.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/ExternalID.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/Scanner.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/Tokens.scala | 0 .../src/main/scala/scala/xml/dtd/ValidationException.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/impl/Base.scala | 0 .../src/main/scala/scala/xml/dtd/impl/BaseBerrySethi.scala | 0 .../src/main/scala/scala/xml/dtd/impl/DetWordAutom.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/impl/Inclusion.scala | 0 .../src/main/scala/scala/xml/dtd/impl/NondetWordAutom.scala | 0 .../src/main/scala/scala/xml/dtd/impl/PointedHedgeExp.scala | 0 .../src/main/scala/scala/xml/dtd/impl/SubsetConstruction.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/impl/SyntaxError.scala | 0 .../src/main/scala/scala/xml/dtd/impl/WordBerrySethi.scala | 0 .../shared}/src/main/scala/scala/xml/dtd/impl/WordExp.scala | 0 .../shared}/src/main/scala/scala/xml/factory/Binder.scala | 0 .../src/main/scala/scala/xml/factory/LoggedNodeFactory.scala | 0 .../shared}/src/main/scala/scala/xml/factory/NodeFactory.scala | 0 .../shared}/src/main/scala/scala/xml/factory/XMLLoader.scala | 0 .../main/scala/scala/xml/include/CircularIncludeException.scala | 0 .../scala/scala/xml/include/UnavailableResourceException.scala | 0 .../src/main/scala/scala/xml/include/XIncludeException.scala | 0 .../main/scala/scala/xml/include/sax/EncodingHeuristics.scala | 0 .../src/main/scala/scala/xml/include/sax/XIncludeFilter.scala | 0 .../src/main/scala/scala/xml/include/sax/XIncluder.scala | 0 {shared => xml/shared}/src/main/scala/scala/xml/package.scala | 0 .../src/main/scala/scala/xml/parsing/ConstructingHandler.scala | 0 .../src/main/scala/scala/xml/parsing/ConstructingParser.scala | 0 .../src/main/scala/scala/xml/parsing/DefaultMarkupHandler.scala | 0 .../src/main/scala/scala/xml/parsing/ExternalSources.scala | 0 .../src/main/scala/scala/xml/parsing/FactoryAdapter.scala | 0 .../shared}/src/main/scala/scala/xml/parsing/FatalError.scala | 0 .../src/main/scala/scala/xml/parsing/MarkupHandler.scala | 0 .../shared}/src/main/scala/scala/xml/parsing/MarkupParser.scala | 0 .../src/main/scala/scala/xml/parsing/MarkupParserCommon.scala | 0 .../main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala | 0 .../shared}/src/main/scala/scala/xml/parsing/TokenTests.scala | 0 .../main/scala/scala/xml/parsing/ValidatingMarkupHandler.scala | 0 .../src/main/scala/scala/xml/parsing/XhtmlEntities.scala | 0 .../shared}/src/main/scala/scala/xml/parsing/XhtmlParser.scala | 0 .../src/main/scala/scala/xml/persistent/CachedFileStorage.scala | 0 .../shared}/src/main/scala/scala/xml/persistent/Index.scala | 0 .../src/main/scala/scala/xml/persistent/SetStorage.scala | 0 .../shared}/src/main/scala/scala/xml/pull/XMLEvent.scala | 0 .../shared}/src/main/scala/scala/xml/pull/XMLEventReader.scala | 0 .../shared}/src/main/scala/scala/xml/pull/package.scala | 0 .../src/main/scala/scala/xml/transform/BasicTransformer.scala | 0 .../src/main/scala/scala/xml/transform/RewriteRule.scala | 0 .../src/main/scala/scala/xml/transform/RuleTransformer.scala | 0 .../shared}/src/test/scala/scala/xml/AttributeTest.scala | 0 .../shared}/src/test/scala/scala/xml/JUnitAssertsForXML.scala | 0 .../shared}/src/test/scala/scala/xml/MetaDataTest.scala | 0 .../shared}/src/test/scala/scala/xml/NodeBufferTest.scala | 0 .../shared}/src/test/scala/scala/xml/PatternMatching.scala | 0 .../src/test/scala/scala/xml/PrintEmptyElementsTest.scala | 0 .../shared}/src/test/scala/scala/xml/ShouldCompile.scala | 0 .../shared}/src/test/scala/scala/xml/Transformers.scala | 0 .../shared}/src/test/scala/scala/xml/UtilityTest.scala | 0 .../shared}/src/test/scala/scala/xml/XMLEmbeddingTest.scala | 0 .../shared}/src/test/scala/scala/xml/XMLSyntaxTest.scala | 0 {shared => xml/shared}/src/test/scala/scala/xml/XMLTest.scala | 0 .../src/test/scala/scala/xml/parsing/PiParsingTest.scala | 0 .../src/test/scala/scala/xml/parsing/Ticket0632Test.scala | 0 107 files changed, 1 insertion(+), 1 deletion(-) rename {jvm => xml/jvm}/src/test/scala/scala/xml/CompilerErrors.scala (100%) rename {jvm => xml/jvm}/src/test/scala/scala/xml/ReuseNodesTest.scala (100%) rename {jvm => xml/jvm}/src/test/scala/scala/xml/XMLSyntaxTest.scala (100%) rename {jvm => xml/jvm}/src/test/scala/scala/xml/XMLTest.scala (100%) rename {jvm => xml/jvm}/src/test/scala/scala/xml/parsing/ConstructingParserTest.scala (100%) rename {jvm => xml/jvm}/src/test/scala/scala/xml/parsing/PiParsingTest.scala (100%) rename {jvm => xml/jvm}/src/test/scala/scala/xml/parsing/Ticket0632Test.scala (100%) rename {jvm => xml/jvm}/src/test/scala/scala/xml/pull/XMLEventReaderTest.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Atom.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Attribute.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Comment.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Document.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Elem.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/EntityRef.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Equality.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Group.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/MalformedAttributeException.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/MetaData.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/NamespaceBinding.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Node.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/NodeBuffer.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/NodeSeq.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Null.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/PCData.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/PrefixedAttribute.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/PrettyPrinter.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/ProcInstr.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/QNode.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/SpecialNode.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Text.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/TextBuffer.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/TopScope.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/TypeSymbol.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Unparsed.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/UnprefixedAttribute.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Utility.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/XML.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/Xhtml.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/ContentModel.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/ContentModelParser.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/DTD.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/Decl.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/DocType.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/ElementValidator.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/ExternalID.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/Scanner.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/Tokens.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/ValidationException.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/Base.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/BaseBerrySethi.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/DetWordAutom.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/Inclusion.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/NondetWordAutom.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/PointedHedgeExp.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/SubsetConstruction.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/SyntaxError.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/WordBerrySethi.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/dtd/impl/WordExp.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/factory/Binder.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/factory/LoggedNodeFactory.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/factory/NodeFactory.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/factory/XMLLoader.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/include/CircularIncludeException.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/include/UnavailableResourceException.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/include/XIncludeException.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/include/sax/EncodingHeuristics.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/include/sax/XIncludeFilter.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/include/sax/XIncluder.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/package.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/ConstructingHandler.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/ConstructingParser.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/DefaultMarkupHandler.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/ExternalSources.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/FactoryAdapter.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/FatalError.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/MarkupHandler.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/MarkupParser.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/MarkupParserCommon.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/TokenTests.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/ValidatingMarkupHandler.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/XhtmlEntities.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/parsing/XhtmlParser.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/persistent/CachedFileStorage.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/persistent/Index.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/persistent/SetStorage.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/pull/XMLEvent.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/pull/XMLEventReader.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/pull/package.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/transform/BasicTransformer.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/transform/RewriteRule.scala (100%) rename {shared => xml/shared}/src/main/scala/scala/xml/transform/RuleTransformer.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/AttributeTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/JUnitAssertsForXML.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/MetaDataTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/NodeBufferTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/PatternMatching.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/PrintEmptyElementsTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/ShouldCompile.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/Transformers.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/UtilityTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/XMLEmbeddingTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/XMLSyntaxTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/XMLTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/parsing/PiParsingTest.scala (100%) rename {shared => xml/shared}/src/test/scala/scala/xml/parsing/Ticket0632Test.scala (100%) diff --git a/build.sbt b/build.sbt index 85bf1ef87..585f4c305 100644 --- a/build.sbt +++ b/build.sbt @@ -15,7 +15,7 @@ lazy val root = project.in(file(".")) .aggregate(xmlJS, xmlJVM) .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", 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 From 7e51c47d0611072e0956fcdf7b871b988ee38cf7 Mon Sep 17 00:00:00 2001 From: Allan Renucci Date: Wed, 28 Jun 2017 19:28:12 +0200 Subject: [PATCH 2/2] Add new XML interpolator --- build.sbt | 19 +- .../scala/scala/xml/quote/internal/Hole.scala | 12 ++ .../scala/xml/quote/internal/Liftables.scala | 192 ++++++++++++++++++ .../scala/xml/quote/internal/QuoteImpl.scala | 86 ++++++++ .../scala/xml/quote/internal/Transform.scala | 110 ++++++++++ .../scala/xml/quote/internal/XmlParser.scala | 128 ++++++++++++ .../xml/quote/internal/XmlSettings.scala | 12 ++ .../scala/scala/xml/quote/internal/ast.scala | 130 ++++++++++++ .../main/scala/scala/xml/quote/quote.scala | 12 ++ .../scala/xml/quote/NamespaceSuite.scala | 42 ++++ .../xml/quote/ScalacBugParitySuite.scala | 25 +++ .../scala/xml/quote/SimpleNodeSuite.scala | 124 +++++++++++ .../xml/quote/TrailingWhiteSpaceSuite.scala | 30 +++ .../scala/scala/xml/quote/UnquoteSuite.scala | 44 ++++ .../scala/scala/xml/quote/XmlQuoteSuite.scala | 41 ++++ 15 files changed, 1006 insertions(+), 1 deletion(-) create mode 100644 quote/src/main/scala/scala/xml/quote/internal/Hole.scala create mode 100644 quote/src/main/scala/scala/xml/quote/internal/Liftables.scala create mode 100644 quote/src/main/scala/scala/xml/quote/internal/QuoteImpl.scala create mode 100644 quote/src/main/scala/scala/xml/quote/internal/Transform.scala create mode 100644 quote/src/main/scala/scala/xml/quote/internal/XmlParser.scala create mode 100644 quote/src/main/scala/scala/xml/quote/internal/XmlSettings.scala create mode 100644 quote/src/main/scala/scala/xml/quote/internal/ast.scala create mode 100644 quote/src/main/scala/scala/xml/quote/quote.scala create mode 100644 quote/src/test/scala/scala/xml/quote/NamespaceSuite.scala create mode 100644 quote/src/test/scala/scala/xml/quote/ScalacBugParitySuite.scala create mode 100644 quote/src/test/scala/scala/xml/quote/SimpleNodeSuite.scala create mode 100644 quote/src/test/scala/scala/xml/quote/TrailingWhiteSpaceSuite.scala create mode 100644 quote/src/test/scala/scala/xml/quote/UnquoteSuite.scala create mode 100644 quote/src/test/scala/scala/xml/quote/XmlQuoteSuite.scala diff --git a/build.sbt b/build.sbt index 585f4c305..c2b77d152 100644 --- a/build.sbt +++ b/build.sbt @@ -12,7 +12,7 @@ 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("xml")) @@ -54,3 +54,20 @@ lazy val xml = crossProject.in(file("xml")) 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( "" ).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( "" ) + + 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 ~ "" ).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 ~ ";" | "&#x" ~ 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"""&#x;""" ≈ &#x;) + } + + 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) + } +}