os.xml_2.11.0-RC4.1.0.0-M1.source-code.Unliftables.scala Maven / Gradle / Ivy
package org.scalamacros.xml
import scala.reflect.api.Universe
trait Unliftables extends Nodes {
protected val __universe: Universe
import __universe._
import __universe.internal.reificationSupport.{SyntacticBlock => SynBlock}
object XML {
private val xmlpackage = rootMirror.staticPackage("scala.xml")
def unapply(tree: Tree) = tree match {
case q"_root_.scala.xml" => true
case tq"_root_.scala.xml" => true
case rt: RefTree if rt.symbol == xmlpackage => true
case _ => false
}
}
implicit val UnliftComment = Unliftable[xml.Comment] {
case q"new ${XML()}.Comment(${text: String})" => xml.Comment(text)
}
implicit val UnliftText = Unliftable[xml.Text] {
case q"new ${XML()}.Text(${text: String})" => xml.Text(text)
}
implicit val UnliftEntityRef = Unliftable[xml.EntityRef] {
case q"new ${XML()}.EntityRef(${name: String})" => xml.EntityRef(name)
}
implicit val UnliftProcInstr = Unliftable[xml.ProcInstr] {
case q"new ${XML()}.ProcInstr(${target: String}, ${proctext: String})" =>
xml.ProcInstr(target, proctext)
}
implicit val UnliftUnparsed = Unliftable[xml.Unparsed] {
case q"new ${XML()}.Unparsed(${data: String})" => xml.Unparsed(data)
}
implicit val UnliftPCData = Unliftable[xml.PCData] {
case q"new ${XML()}.PCData(${data: String})" => xml.PCData(data)
}
// extract string literal or null
private object Str {
def unapply(tree: Tree): Option[String] = tree match {
case Literal(Constant(s: String)) => Some(s)
case Literal(Constant(null)) => Some(null)
case _ => None
}
}
private def withRetreat[T](f: (() => Nothing) => T)(orElse: => T): T = {
class Stop extends Exception
try f(() => throw new Stop) catch {
case _: Stop => orElse
}
}
private object DDScope {
def unapply(tree: Tree) = tree match {
case q"$$scope" => true
case q"${XML()}.$$scope" => true
case _ => false
}
}
private object Scoped {
def unapply(tree: Tree)(implicit outer: xml.NamespaceBinding): Option[(xml.NamespaceBinding, Tree)] = tree match {
case q"""
var $$tmpscope: ${XML()}.NamespaceBinding = ${DDScope()}
..$scopes
${SynBlock(q"val $$scope: ${XML()}.NamespaceBinding = $$tmpscope" :: last)}
""" =>
withRetreat { retreat =>
Some((scopes.foldLeft[xml.NamespaceBinding](outer) {
case (ns, q"$$tmpscope = new ${XML()}.NamespaceBinding(${Str(prefix)}, ${uri: String}, $$tmpscope)") =>
xml.NamespaceBinding(prefix, uri, ns)
case _ =>
retreat()
}, q"..$last"))
} {
Some((outer, tree))
}
case q"..$stats" =>
Some((outer, q"..$stats"))
}
}
// extract a sequence of $md = FooAttribute(..., $md) as metadata
private object Attributed {
def unapply(tree: Tree)(implicit outer: xml.NamespaceBinding): Option[(xml.MetaData, Tree)] = tree match {
case q"""
var $$md: ${XML()}.MetaData = ${XML()}.Null
..$attributes
$last
""" =>
withRetreat { retreat =>
Some((attributes.foldLeft[xml.MetaData](xml.Null) {
case (md, q"$$md = new ${XML()}.UnprefixedAttribute(${key: String}, ${value: xml.Node}, $$md)") =>
new xml.UnprefixedAttribute(key, value, md)
case (md, q"$$md = new ${XML()}.UnprefixedAttribute(${key: String}, $expr, $$md)") =>
new xml.UnprefixedAttribute(key, Unquote(expr), md)
case (md, q"$$md = new ${XML()}.PrefixedAttribute(${pre: String}, ${key: String}, ${value: xml.Node}, $$md)") =>
new xml.PrefixedAttribute(pre, key, value, md)
case (md, q"$$md = new ${XML()}.PrefixedAttribute(${pre: String}, ${key: String}, $expr, $$md)") =>
new xml.PrefixedAttribute(pre, key, Unquote(expr), md)
case _ =>
retreat()
}, last))
} {
Some((xml.Null, tree))
}
case q"..$stats" =>
Some((xml.Null, q"..$stats"))
}
}
// extract a seq of nodes from mutable nodebuffer-based construction
private object Children {
def unapply(children: List[Tree])(implicit outer: xml.NamespaceBinding): Option[Seq[xml.Node]] = children match {
case Nil => Some(Nil)
case q"{ val $$buf = new ${XML()}.NodeBuffer; ..$additions; $$buf }: _*" :: Nil =>
try Some(additions.map {
case q"$$buf &+ ${node: xml.Node}" => node
case q"$$buf &+ $unquote" => Unquote(unquote)
}) catch {
case _: MatchError => None
}
case _ => None
}
}
private def correspondsAttrRef(attrs: xml.MetaData, attrref: Tree): Boolean = (attrs, attrref) match {
case (xml.Null, q"${XML()}.Null") => true
case (metadata, q"$$md") if metadata.nonEmpty => true
case _ => false
}
implicit def UnliftElem(implicit outer: xml.NamespaceBinding = xml.TopScope): Unliftable[xml.Elem] = new Unliftable[xml.Elem] {
def unapply(tree: Tree): Option[xml.Elem] = {
val Scoped(scope, inner) = tree;
{
val outer = 'shadowed
implicit val current = scope
inner match {
case Attributed(attrs,
q"new ${XML()}.Elem(${Str(prefix)}, ${Str(label)}, $attrref, ${DDScope()}, ${minimizeEmpty: Boolean}, ..${Children(children)})")
if correspondsAttrRef(attrs, attrref) =>
Some(xml.Elem(prefix, label, attrs, scope, minimizeEmpty, children: _*))
case _ =>
None
}
}
}
}
implicit val UnliftAtom = Unliftable[xml.Atom[String]] {
case UnliftPCData(pcdata) => pcdata
case UnliftText(text) => text
case UnliftUnparsed(unparsed) => unparsed
}
implicit val UnliftSpecialNode: Unliftable[xml.SpecialNode] = Unliftable[xml.SpecialNode] {
case UnliftAtom(atom) => atom
case UnliftComment(comment) => comment
case UnliftProcInstr(procinstr) => procinstr
case UnliftEntityRef(entityref) => entityref
}
implicit def UnliftNode(implicit outer: xml.NamespaceBinding = xml.TopScope): Unliftable[xml.Node] = Unliftable[xml.Node] {
case q"${elem: xml.Elem}" => elem
case UnliftSpecialNode(snode) => snode
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy