Skip to content

Commit e570648

Browse files
committed
Rewrite and adapt to Scala 3 features
1 parent a79745e commit e570648

File tree

13 files changed

+189
-193
lines changed

13 files changed

+189
-193
lines changed

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ lazy val root = project
88

99
scalaVersion := dottyVersion,
1010
scalacOptions ++= Seq(
11-
"-deprecation"
11+
"-deprecation", "-feature", "-language:implicitConversions"
1212
),
1313
libraryDependencies ++= Seq(
1414
"org.scala-lang.modules" % "scala-parser-combinators_2.13" % "1.1.2",
Lines changed: 48 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
package dotty.xml.interpolator
22
package internal
33

4-
import scala.language.implicitConversions
54
import scala.quoted._
65

7-
import dotty.xml.interpolator.internal.Tree._
6+
import Tree.*
87

9-
object Expand {
8+
object Expand:
109

11-
def apply(nodes: Seq[Node])(implicit ctx: XmlContext, q: Quotes): Expr[scala.xml.Node | scala.xml.NodeBuffer] = {
12-
if (nodes.size == 1) expandNode(nodes.head).asInstanceOf[Expr[scala.xml.Node]]
10+
def apply(nodes: Seq[Node])(using XmlContext, Quotes): Expr[scala.xml.Node | scala.xml.NodeBuffer] =
11+
if nodes.size == 1 then expandNode(nodes.head).asInstanceOf[Expr[scala.xml.Node]]
1312
else expandNodes(nodes)
14-
}
1513

16-
private def expandNode(node: Node)(implicit ctx: XmlContext, q: Quotes): Expr[Any] = {
17-
node match {
14+
private def expandNode(node: Node)(using XmlContext, Quotes): Expr[Any] =
15+
node match
1816
case group: Group => expandGroup(group)
1917
case elem: Elem => expandElem(elem)
2018
case text: Text => expandText(text)
@@ -24,33 +22,32 @@ object Expand {
2422
case procInstr: ProcInstr => expandProcInstr(procInstr)
2523
case entityRef: EntityRef => expandEntityRef(entityRef)
2624
case unparsed: Unparsed => expandUnparsed(unparsed)
27-
}
28-
}
25+
end expandNode
2926

30-
private def expandNodes(nodes: Seq[Node])(implicit ctx: XmlContext, q: Quotes): Expr[scala.xml.NodeBuffer] = {
31-
nodes.foldLeft('{ new _root_.scala.xml.NodeBuffer() })((expr, node) => '{ $expr &+ ${expandNode(node)} } )
32-
}
27+
private def expandNodes(nodes: Seq[Node])(using XmlContext, Quotes): Expr[scala.xml.NodeBuffer] =
28+
nodes.foldLeft('{ scala.xml.NodeBuffer() }): (expr, node) =>
29+
'{ $expr &+ ${ expandNode(node) } }
3330

34-
private def expandGroup(group: Group)(implicit ctx: XmlContext, q: Quotes): Expr[scala.xml.Group] =
35-
'{ new _root_.scala.xml.Group(${expandNodes(group.nodes)}) }
31+
private def expandGroup(group: Group)(using XmlContext, Quotes): Expr[scala.xml.Group] =
32+
'{ scala.xml.Group(${ expandNodes(group.nodes) }) }
3633

37-
private def expandElem(elem: Elem)(implicit ctx: XmlContext, q: Quotes): Expr[scala.xml.Elem] = {
34+
private def expandElem(elem: Elem)(using ctx: XmlContext, q: Quotes): Expr[scala.xml.Elem] =
3835
val (namespaces, attributes) = elem.attributes.partition(_.isNamespace)
39-
val prefix = if (elem.prefix.nonEmpty) Expr(elem.prefix) else '{ null: String }
36+
val prefix = if elem.prefix.nonEmpty then Expr(elem.prefix) else '{ null }
4037
val label = Expr(elem.label)
4138
val attributes1 = expandAttributes(attributes)
4239
val scope = expandNamespaces(namespaces)
4340
val empty = Expr(elem.end.isEmpty)
44-
val child = expandNodes(elem.children)(new XmlContext(ctx.args, scope), q)
45-
if (elem.children.isEmpty)
46-
'{ new _root_.scala.xml.Elem($prefix, $label, $attributes1, $scope, $empty) }
41+
val child = expandNodes(elem.children)(using new XmlContext(ctx.args, scope), q)
42+
if elem.children.isEmpty then
43+
'{ new scala.xml.Elem($prefix, $label, $attributes1, $scope, $empty) }
4744
else
48-
'{ new _root_.scala.xml.Elem($prefix, $label, $attributes1, $scope, $empty, _root_.scala.xml.NodeSeq.seqToNodeSeq($child): _*) }
49-
}
45+
'{ new scala.xml.Elem($prefix, $label, $attributes1, $scope, $empty, scala.xml.NodeSeq.seqToNodeSeq($child)*) }
46+
end expandElem
5047

51-
private def expandAttributes(attributes: Seq[Attribute])(implicit ctx: XmlContext, q: Quotes): Expr[scala.xml.MetaData] = {
48+
private def expandAttributes(attributes: Seq[Attribute])(using XmlContext, Quotes): Expr[scala.xml.MetaData] =
5249
import quotes.reflect._
53-
attributes.foldRight('{ _root_.scala.xml.Null }: Expr[scala.xml.MetaData])((attribute, rest) => {
50+
attributes.foldRight('{ _root_.scala.xml.Null }: Expr[scala.xml.MetaData]): (attribute, rest) =>
5451
val value = attribute.value match {
5552
case Seq(v) => expandNode(v)
5653
case vs => expandNodes(vs)
@@ -71,57 +68,52 @@ object Expand {
7168
*/
7269

7370
val term = value.asTerm
74-
if (term.tpe <:< TypeRepr.of[String]) {
71+
if term.tpe <:< TypeRepr.of[String] then
7572
val value = term.asExprOf[String]
76-
if (attribute.prefix.isEmpty) '{ new _root_.scala.xml.UnprefixedAttribute(${Expr(attribute.key)}, $value, $rest) }
77-
else '{ new _root_.scala.xml.PrefixedAttribute(${Expr(attribute.prefix)}, ${Expr(attribute.key)}, $value, $rest) }
78-
} else if (term.tpe <:< TypeRepr.of[collection.Seq[scala.xml.Node]]) {
73+
if attribute.prefix.isEmpty then '{ scala.xml.UnprefixedAttribute(${ Expr(attribute.key) }, $value, $rest) }
74+
else '{ scala.xml.PrefixedAttribute(${ Expr(attribute.prefix) }, ${ Expr(attribute.key) }, $value, $rest) }
75+
else if term.tpe <:< TypeRepr.of[collection.Seq[scala.xml.Node]] then
7976
val value = term.asExprOf[collection.Seq[scala.xml.Node]]
80-
if (attribute.prefix.isEmpty) '{ new _root_.scala.xml.UnprefixedAttribute(${Expr(attribute.key)}, $value, $rest) }
81-
else '{ new _root_.scala.xml.PrefixedAttribute(${Expr(attribute.prefix)}, ${Expr(attribute.key)}, $value, $rest) }
82-
} else {
77+
if attribute.prefix.isEmpty then '{ scala.xml.UnprefixedAttribute(${ Expr(attribute.key) }, $value, $rest) }
78+
else '{ scala.xml.PrefixedAttribute(${ Expr(attribute.prefix) }, ${ Expr(attribute.key) }, $value, $rest) }
79+
else
8380
val value = term.asExprOf[Option[collection.Seq[scala.xml.Node]]]
84-
if (attribute.prefix.isEmpty) '{ new _root_.scala.xml.UnprefixedAttribute(${Expr(attribute.key)}, $value, $rest) }
85-
else '{ new _root_.scala.xml.PrefixedAttribute(${Expr(attribute.prefix)}, ${Expr(attribute.key)}, $value, $rest) }
86-
}
87-
})
88-
}
81+
if attribute.prefix.isEmpty then '{ scala.xml.UnprefixedAttribute(${ Expr(attribute.key) }, $value, $rest) }
82+
else '{ scala.xml.PrefixedAttribute(${ Expr(attribute.prefix) }, ${ Expr(attribute.key) }, $value, $rest) }
83+
end expandAttributes
8984

90-
private def expandNamespaces(namespaces: Seq[Attribute])(implicit ctx: XmlContext, q: Quotes): Expr[scala.xml.NamespaceBinding] = {
85+
private def expandNamespaces(namespaces: Seq[Attribute])(using XmlContext, Quotes): Expr[Scope] =
9186
import quotes.reflect._
92-
namespaces.foldLeft(ctx.scope)((rest, namespace) => {
93-
val prefix = if (namespace.prefix.nonEmpty) Expr(namespace.key) else '{ null: String }
94-
val uri = (namespace.value.head: @unchecked) match {
87+
namespaces.foldLeft(ctx.scope): (rest, namespace) =>
88+
val prefix = if namespace.prefix.nonEmpty then Expr(namespace.key) else '{ null }
89+
val uri = (namespace.value.head: @unchecked) match
9590
case Text(text) => Expr(text)
9691
case Placeholder(id) =>
97-
val call = '{ ${ctx.args(id)}(using _root_.scala.xml.TopScope) }
92+
val call = '{ ${ctx.args(id)}(using scala.xml.TopScope) }
9893
Expr.betaReduce(call).asExprOf[String]
99-
}
100-
'{ new _root_.scala.xml.NamespaceBinding($prefix, $uri, $rest) }
101-
})
102-
}
94+
'{ scala.xml.NamespaceBinding($prefix, $uri, $rest) }
95+
end expandNamespaces
10396

10497
private def expandText(text: Text)(using Quotes): Expr[scala.xml.Text] =
105-
'{ new _root_.scala.xml.Text(${Expr(text.text)}) }
98+
'{ scala.xml.Text(${ Expr(text.text) }) }
10699

107100
private def expandComment(comment: Comment)(using Quotes): Expr[scala.xml.Comment] =
108-
'{ new _root_.scala.xml.Comment(${Expr(comment.text)}) }
101+
'{ scala.xml.Comment(${ Expr(comment.text) }) }
109102

110-
private def expandPlaceholder(placeholder: Placeholder)(implicit ctx: XmlContext, q: Quotes): Expr[Any] = {
103+
private def expandPlaceholder(placeholder: Placeholder)(using XmlContext, Quotes): Expr[Any] =
111104
val arg = ctx.args(placeholder.id)
112-
val scope = ctx.scope
113-
Expr.betaReduce('{ $arg(using $scope) })
114-
}
105+
Expr.betaReduce('{ $arg(using ${ ctx.scope }) })
115106

116107
private def expandPCData(pcdata: PCData)(using Quotes): Expr[scala.xml.PCData] =
117-
'{ new _root_.scala.xml.PCData(${Expr(pcdata.data)}) }
108+
'{ scala.xml.PCData(${ Expr(pcdata.data) }) }
118109

119110
private def expandProcInstr(instr: ProcInstr)(using Quotes): Expr[scala.xml.ProcInstr] =
120-
'{ new _root_.scala.xml.ProcInstr(${Expr(instr.target)}, ${Expr(instr.proctext)}) }
111+
'{ scala.xml.ProcInstr(${ Expr(instr.target) }, ${ Expr(instr.proctext) }) }
121112

122113
private def expandEntityRef(ref: EntityRef)(using Quotes): Expr[scala.xml.EntityRef] =
123-
'{ new _root_.scala.xml.EntityRef(${Expr(ref.name)}) }
114+
'{ scala.xml.EntityRef(${ Expr(ref.name) }) }
124115

125116
private def expandUnparsed(unparsed: Unparsed)(using Quotes): Expr[scala.xml.Unparsed] =
126-
'{ new _root_.scala.xml.Unparsed(${Expr(unparsed.data)}) }
127-
}
117+
'{ scala.xml.Unparsed(${ Expr(unparsed.data) }) }
118+
119+
end Expand
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package dotty.xml.interpolator
22
package internal
33

4-
object Hole {
4+
object Hole:
55
val HoleStart = 0xE000.toChar.toString
66
val HoleChar = 0xE001.toChar.toString
7-
def encode(i: Int) = HoleStart + HoleChar * i
8-
}
7+
def encode(i: Int) = HoleStart + HoleChar * i

src/main/scala/dotty/xml/interpolator/internal/Macro.scala

Lines changed: 47 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -6,38 +6,43 @@ import scala.quoted._
66
import scala.collection.mutable.ArrayBuffer
77
import scala.language.implicitConversions
88

9-
object Macro {
9+
object Macro:
1010

11-
def impl(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Scope ?=> Any]], scope: Expr[Scope])(using qctx: Quotes): Expr[scala.xml.Node | scala.xml.NodeBuffer] = {
12-
((strCtxExpr, argsExpr): @unchecked) match {
11+
/** ??? */
12+
def impl(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Scope ?=> Any]], scope: Expr[Scope])
13+
(using Quotes): Expr[scala.xml.Node | scala.xml.NodeBuffer] =
14+
15+
(strCtxExpr, argsExpr) match
1316
case ('{ StringContext(${Varargs(parts)}: _*) }, Varargs(args)) =>
17+
1418
val (xmlStr, offsets) = encode(parts)
15-
implicit val ctx: XmlContext = new XmlContext(args, scope)
16-
implicit val reporter: Reporter = new Reporter {
17-
import quotes.reflect._
1819

19-
def error(msg: String, idx: Int): Unit = {
20-
val (part, offset) = Reporter.from(idx, offsets, parts)
21-
val pos = part.asTerm.pos
22-
val (srcF, start) = (pos.sourceFile, pos.start)
23-
report.error(msg, Position(srcF, start + offset, start + offset + 1))
24-
}
20+
given XmlContext = new XmlContext(args, scope)
21+
given Reporter = new Reporter {
22+
import quotes.reflect.*
23+
24+
def error(msg: String, idx: Int): Unit = {
25+
val (part, offset) = Reporter.from(idx, offsets, parts)
26+
val pos = part.asTerm.pos
27+
val (srcF, start) = (pos.sourceFile, pos.start)
28+
report.error(msg, Position(srcF, start + offset, start + offset + 1))
29+
}
30+
31+
def error(msg: String, expr: Expr[Any]): Unit =
32+
report.error(msg, expr)
33+
}
2534

26-
def error(msg: String, expr: Expr[Any]): Unit = {
27-
report.error(msg, expr)
28-
}
29-
}
3035
implCore(xmlStr)
31-
}
32-
}
36+
end impl
3337

34-
def implErrors(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Scope ?=> Any]], scope: Expr[Scope])(using qctx: Quotes): Expr[List[(Int, String)]] = {
35-
((strCtxExpr, argsExpr): @unchecked) match {
38+
def implErrors(strCtxExpr: Expr[StringContext], argsExpr: Expr[Seq[Scope ?=> Any]], scope: Expr[Scope])
39+
(using Quotes): Expr[List[(Int, String)]] =
40+
(strCtxExpr, argsExpr) match
3641
case ('{ StringContext(${Varargs(parts)}: _*) }, Varargs(args)) =>
3742
val errors = List.newBuilder[Expr[(Int, String)]]
3843
val (xmlStr, offsets) = encode(parts)
39-
implicit val ctx: XmlContext = new XmlContext(args, scope)
40-
implicit val reporter: Reporter = new Reporter {
44+
given XmlContext = new XmlContext(args, scope)
45+
given Reporter = new Reporter {
4146
import quotes.reflect._
4247

4348
def error(msg: String, idx: Int): Unit = {
@@ -53,48 +58,42 @@ object Macro {
5358
}
5459
implCore(xmlStr)
5560
Expr.ofList(errors.result())
56-
}
57-
}
61+
end implErrors
5862

59-
private def implCore(xmlStr: String)(using XmlContext, Reporter, Quotes): Expr[scala.xml.Node | scala.xml.NodeBuffer] = {
63+
private def implCore(xmlStr: String)(using XmlContext, Reporter, Quotes): Expr[scala.xml.Node | scala.xml.NodeBuffer] =
6064

61-
import Parse.{apply => parse}
62-
import Transform.{apply => transform}
63-
import Validate.{apply => validate}
64-
import TypeCheck.{apply => typecheck}
65-
import Expand.{apply => expand}
65+
import Parse.apply as parse
66+
import Transform.apply as transform
67+
import Validate.apply as validate
68+
import TypeCheck.apply as typecheck
69+
import Expand.apply as expand
6670

67-
val interpolate = (
68-
parse
69-
andThen transform
70-
andThen validate
71-
andThen typecheck
72-
andThen expand
73-
)
71+
val interpolate = parse andThen
72+
transform andThen
73+
validate andThen
74+
typecheck andThen
75+
expand
7476

7577
interpolate(xmlStr)
76-
}
78+
end implCore
7779

78-
private def encode(parts: Seq[Expr[String]])(using Quotes): (String, Array[Int]) = {
80+
private def encode(parts: Seq[Expr[String]])(using Quotes): (String, Array[Int]) =
7981
val sb = new StringBuilder()
8082
val bf = ArrayBuffer.empty[Int]
8183

82-
def appendPart(part: Expr[String]) = {
84+
def appendPart(part: Expr[String]) =
8385
bf += sb.length
8486
sb ++= part.valueOrAbort
8587
bf += sb.length
86-
}
8788

88-
def appendHole(index: Int) = {
89-
sb ++= Hole.encode(index)
90-
}
89+
def appendHole(index: Int) = sb ++= Hole.encode(index)
9190

92-
for ((part, index) <- parts.init.zipWithIndex) {
91+
for (part, index) <- parts.init.zipWithIndex do
9392
appendPart(part)
9493
appendHole(index)
95-
}
9694
appendPart(parts.last)
9795

9896
(sb.toString, bf.toArray)
99-
}
100-
}
97+
end encode
98+
99+
end Macro
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package dotty.xml.interpolator
22
package internal
33

4-
import scala.quoted._
4+
import scala.quoted.*
55

6-
trait Reporter {
6+
trait Reporter:
77
def error(msg: String, idx: Int): Unit
88
def error(msg: String, expr: Expr[Any]): Unit
9-
}
109

11-
object Reporter {
10+
object Reporter:
1211
def from(idx: Int, offsets: Array[Int], parts: Seq[Expr[String]]): (Expr[String], Int) = {
1312
val index = offsets.lastIndexWhere(idx >= _)
1413
val isWithinHoleOrAtTheEnd = index % 2 != 0
@@ -17,5 +16,4 @@ object Reporter {
1716
case false => (index / 2, idx - offsets(index))
1817
}
1918
(parts(partIndex), offset)
20-
}
21-
}
19+
}
Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
package dotty.xml.interpolator
22
package internal
33

4-
import dotty.xml.interpolator.internal.Tree._
4+
import Tree.*
55

6-
object Transform {
7-
def apply(nodes: Seq[Node]): Seq[Node] = {
8-
nodes.map {
6+
object Transform:
7+
8+
def apply(nodes: Seq[Node]): Seq[Node] =
9+
nodes.map:
910
case elem : Elem =>
1011
val children = apply(elem.children)
11-
if (elem.name == "xml:group" && !elem.end.isEmpty) Group(elem.children).setPos(elem.pos)
12+
if elem.name == "xml:group" && !elem.end.isEmpty then Group(elem.children).setPos(elem.pos)
1213
else elem.copy(children = children).setPos(elem.pos)
1314
case node => node
14-
}
15-
}
16-
}
15+
end apply
16+
17+
end Transform

0 commit comments

Comments
 (0)