Skip to content

Commit 7987718

Browse files
committed
[xml] Allow target type to influence XmlFactory implicit search
1 parent 7a44692 commit 7987718

File tree

6 files changed

+34
-16
lines changed

6 files changed

+34
-16
lines changed

XmlParser/src/main/scala/XmlFactory.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package name.rayrobdod.stringContextParserCombinatorExample.xml
1818
* - literal
1919
* - interpolation
2020
*/
21-
trait XmlFactory
21+
trait XmlFactory[Z]
2222

2323
object XmlFactory:
2424
/** An `XmlFactory.entities` implementation that handles only the predefined entities */
@@ -29,7 +29,7 @@ object XmlFactory:
2929
val quot:A = fn('"')
3030
val apos:A = fn('\'')
3131

32-
given default:XmlFactory with
32+
given default:XmlFactory[scala.xml.NodeSeq] with
3333
import scala.language.dynamics
3434
enum IEitherPrefixUri:
3535
case PrefixOnly(prefix:String)

XmlParser/src/main/scala/XmlParser.scala

+11-11
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ private[xml] object XmlParser {
126126
)
127127
}
128128

129-
private def interpolation(factory: Expr[XmlFactory])(using Quotes):Interpolator[quotes.reflect.Term] = {
129+
private def interpolation(factory: Expr[XmlFactory[_]])(using Quotes):Interpolator[quotes.reflect.Term] = {
130130
import quotes.reflect._
131131
ofType[Any]
132132
.map({(value) =>
@@ -140,7 +140,7 @@ private[xml] object XmlParser {
140140
})
141141
}
142142

143-
private def attribute(factory:Expr[XmlFactory])(using Quotes):Interpolator[Attribute] = {
143+
private def attribute(factory:Expr[XmlFactory[_]])(using Quotes):Interpolator[Attribute] = {
144144
def valueText(excluding:Char) = (charRef <|> xmlAllowedChar("<&" + excluding)).repeat(1)
145145
.map({data =>
146146
import quotes.reflect._
@@ -161,7 +161,7 @@ private[xml] object XmlParser {
161161
.map((k,v) => Attribute(k, v.map(_.asExpr)))
162162
}
163163

164-
private def cdata(factory:Expr[XmlFactory])(using Quotes):Interpolator[quotes.reflect.Term] = {
164+
private def cdata(factory:Expr[XmlFactory[_]])(using Quotes):Interpolator[quotes.reflect.Term] = {
165165
given typeclass.Eithered[CodePoint, String, String] with
166166
def left(elem:CodePoint):String = elem.toString
167167
def right(elem:String):String = elem
@@ -185,7 +185,7 @@ private[xml] object XmlParser {
185185
})
186186
}
187187

188-
private def entity(factory:Expr[XmlFactory])(using Quotes):Interpolator[quotes.reflect.Term] = {
188+
private def entity(factory:Expr[XmlFactory[_]])(using Quotes):Interpolator[quotes.reflect.Term] = {
189189
(isString("&") ~> xmlName <~ isString(";"))
190190
.map({name =>
191191
import quotes.reflect._
@@ -196,7 +196,7 @@ private[xml] object XmlParser {
196196
.attempt
197197
}
198198

199-
private def text(factory:Expr[XmlFactory])(using Quotes):Interpolator[quotes.reflect.Term] = {
199+
private def text(factory:Expr[XmlFactory[_]])(using Quotes):Interpolator[quotes.reflect.Term] = {
200200
(charRef <|> xmlAllowedChar("<&")).repeat(1)
201201
.map({data =>
202202
import quotes.reflect._
@@ -206,7 +206,7 @@ private[xml] object XmlParser {
206206
})
207207
}
208208

209-
private def comment(factory:Expr[XmlFactory])(using Quotes):Interpolator[quotes.reflect.Term] = {
209+
private def comment(factory:Expr[XmlFactory[_]])(using Quotes):Interpolator[quotes.reflect.Term] = {
210210
(
211211
isString("<!--")
212212
~> (
@@ -223,7 +223,7 @@ private[xml] object XmlParser {
223223
})
224224
}
225225

226-
private def processingInstruction(factory:Expr[XmlFactory])(using Quotes):Interpolator[quotes.reflect.Term] = {
226+
private def processingInstruction(factory:Expr[XmlFactory[_]])(using Quotes):Interpolator[quotes.reflect.Term] = {
227227
(
228228
isString("<?")
229229
~> xmlName.filter(_ != "xml", "not `xml`")
@@ -242,7 +242,7 @@ private[xml] object XmlParser {
242242
})
243243
}
244244

245-
private def fragment(factory:Expr[XmlFactory], nsb: NamespaceBinding)(using Quotes):Interpolator[List[quotes.reflect.Term]] = {
245+
private def fragment(factory:Expr[XmlFactory[_]], nsb: NamespaceBinding)(using Quotes):Interpolator[List[quotes.reflect.Term]] = {
246246
(
247247
interpolation(factory) <|>
248248
entity(factory) <|>
@@ -254,7 +254,7 @@ private[xml] object XmlParser {
254254
).repeat()
255255
}
256256

257-
private def elem(factory:Expr[XmlFactory], nsb:NamespaceBinding)(using Quotes):Interpolator[quotes.reflect.Term] = {
257+
private def elem(factory:Expr[XmlFactory[_]], nsb:NamespaceBinding)(using Quotes):Interpolator[quotes.reflect.Term] = {
258258
import quotes.reflect._
259259
(
260260
isString("<") ~>
@@ -341,7 +341,7 @@ private[xml] object XmlParser {
341341
}
342342

343343

344-
def interpolate(sc:Expr[scala.StringContext], args:Expr[Seq[Any]], factory:Expr[XmlFactory])(using Quotes):Expr[Any] = {
344+
def interpolate[Z](sc:Expr[scala.StringContext], args:Expr[Seq[Any]], factory:Expr[XmlFactory[Z]])(using Type[Z], Quotes):Expr[Z] = {
345345
import quotes.reflect.*
346346
val (factoryExpr, factoryType) = factory match {case '{ $x: t } => ((x, Type.of[t])) }
347347

@@ -355,7 +355,7 @@ private[xml] object XmlParser {
355355
.selectAndApplyToArgsMaybeDynamicMaybeVarargs
356356
("literal")
357357
((fragment(factoryExpr, initialNsb) <~> end).interpolate(sc, args))
358-
.asExpr
358+
.asExprOf[Z]
359359
}
360360

361361
def classSymbolThatDoesntResultInBadSymbolicReferenceWhenLookingForAnObjectContainedClass(name:String)(using Quotes):quotes.reflect.Symbol = {
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package name.rayrobdod.stringContextParserCombinatorExample.xml
22

33
extension (inline sc:scala.StringContext)
4-
transparent inline def xml(inline args:Any*)(using factory:XmlFactory):Any =
4+
transparent inline def xml[Z](inline args:Any*)(using factory:XmlFactory[Z]):Z =
55
${XmlParser.interpolate('sc, 'args, 'factory)}

XmlParser/src/test/scala/MinixmlFactoryTest.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ package minixml:
1010
final case class Text(content:String) extends Node
1111
final case class Elem(name:QName, attrs: Map[QName, String], childs: Seq[Node]) extends Node
1212

13-
object MinixmlFactory extends XmlFactory:
13+
object MinixmlFactory extends XmlFactory[minixml.Elem]:
1414
import minixml.*
1515

1616
inline def literal(arg:Any):arg.type = arg

XmlParser/src/test/scala/OpmlXmlFactoryTest.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ package Opml:
3939
case class OutlineTag(text:String, typ:Option[String], children: Seq[OutlineTag])
4040

4141

42-
object OpmlXmlFactory extends XmlFactory:
42+
object OpmlXmlFactory extends XmlFactory[Any]:
4343
import Opml.*
4444
import scala.language.dynamics
4545

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package name.rayrobdod.stringContextParserCombinatorExample.xml
2+
3+
final class TargetTypingTest extends munit.FunSuite:
4+
given xml: MinixmlFactory.type = MinixmlFactory
5+
6+
test ("finds MinixmlFactory for target type minixml.Elem") {
7+
val actual: minixml.Elem = xml"<tag-name/>"
8+
import minixml.*
9+
val expected = Elem(QName("", "tag-name"), Map.empty, Seq.empty)
10+
assertEquals(actual, expected)
11+
}
12+
13+
test ("finds XmlFactory.default for target type scala.xml.NodeSeq") {
14+
val actual: scala.xml.NodeSeq = xml"<tag-name/>"
15+
import scala.xml.*
16+
val expected = Elem(null, "tag-name", Null, TopScope, true)
17+
assertEquals(actual, expected)
18+
}

0 commit comments

Comments
 (0)