Advertisement
PaleoCrafter

Scala in your face

May 23rd, 2015
312
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 11.46 KB | None | 0 0
  1. package de.mineformers.mcreflect
  2.  
  3. import scala.reflect.macros.blackbox
  4. import de.mineformers.mcreflect.introspection.RefMethod
  5. import de.mineformers.mcreflect.introspection.RefConstructor
  6. import de.mineformers.mcreflect.introspection.RefType
  7. import de.mineformers.mcreflect.introspection.RefField
  8. import de.mineformers.mcreflect.mapping.Mappings
  9. import scala.reflect.NameTransformer
  10. import java.io.File
  11.  
  12. /**
  13.  * Macros
  14.  *
  15.  * @author PaleoCrafter
  16.  */
  17. object Macros {
  18.   lazy val mappings = {
  19.     val gradleStart = Class.forName("net.minecraftforge.gradle.GradleStartCommon")
  20.     val field = gradleStart.getDeclaredField("SRG_DIR")
  21.     field.setAccessible(true)
  22.     val srgDir = field.get(null).asInstanceOf[File]
  23.     Mappings.fromFile(new File(srgDir, "mcp-srg.srg").getAbsolutePath)
  24.   }
  25.  
  26.   def typeImpl[C: c.WeakTypeTag](c: blackbox.Context): c.Expr[RefType[C]] = {
  27.     import c.universe._
  28.     val t = weakTypeTag[C]
  29.  
  30.     c.Expr[RefType[C]] {
  31.       refType(c)(t.tpe)
  32.     }
  33.   }
  34.  
  35.   object constructors {
  36.  
  37.     def simpleConstructorImpl[C: c.WeakTypeTag](c: blackbox.Context): c.Expr[RefConstructor[C]] = {
  38.       import c.universe._
  39.       val classTag = c.weakTypeTag[C]
  40.       val cType = classTag.tpe
  41.       val className = cType.typeSymbol.fullName
  42.       val alternatives = cType.members.filter(_.isConstructor)
  43.       if (alternatives.isEmpty)
  44.         c.abort(c.enclosingPosition, s"No constructors in $className")
  45.       if (alternatives.size > 1)
  46.         c.abort(c.enclosingPosition, s"There are multiple constructors in $className, " +
  47.           s"try referencing it with tpe.constructor(type1, type2, ..., typeN)")
  48.       val params = alternatives.head.asMethod.paramLists.head.map(_.info)
  49.  
  50.       val classLiteral = refType(c)(cType)
  51.       val descriptor = buildDescriptor(c)(params, typeOf[Unit])
  52.       val descLiteral = q"$descriptor"
  53.       val types = params map (refType(c)(_))
  54.       val typesLiteral = q"$types"
  55.  
  56.       c.Expr[RefConstructor[C]] {
  57.         q""" de.mineformers.mcreflect.introspection.RefConstructor($classLiteral, $descLiteral, $typesLiteral) """
  58.       }
  59.     }
  60.  
  61.     def constructorImpl[C: c.WeakTypeTag](c: blackbox.Context)(args: c.Expr[RefType[_]]*): c.Expr[RefConstructor[C]] = {
  62.       import c.universe._
  63.       val classTag = c.weakTypeTag[C]
  64.       val cType = classTag.tpe
  65.       val className = cType.typeSymbol.fullName
  66.       val alternatives = cType.members.filter(_.isConstructor)
  67.       if (alternatives.isEmpty)
  68.         c.abort(c.enclosingPosition, s"No constructors in $className")
  69.       val types = args.toList map (_.actualType.typeArgs.head)
  70.       val params = alternatives map (_.asMethod) find (m => m.paramLists.nonEmpty &&
  71.         m.paramLists.head.length == types.length &&
  72.         (m.paramLists.head, types)
  73.         .zipped.forall(_.info =:= _)) match {
  74.         case None =>
  75.           c.abort(c.enclosingPosition, s"No constructor $className(${types.map(_.typeSymbol.fullName).mkString(", ")}):"
  76.             + s" in $className")
  77.         case Some(m) =>
  78.           m.paramLists.head.map(_.info)
  79.       }
  80.  
  81.       val classLiteral = refType(c)(cType)
  82.       val descriptor = buildDescriptor(c)(params, typeOf[Unit])
  83.       val descLiteral = q"$descriptor"
  84.       val tpes = params map (refType(c)(_))
  85.       val tpesLiteral = q"$tpes"
  86.  
  87.       c.Expr[RefConstructor[C]] {
  88.         q""" de.mineformers.mcreflect.introspection.RefConstructor($classLiteral, $descLiteral, $tpesLiteral) """
  89.       }
  90.     }
  91.   }
  92.  
  93.   object methods {
  94.  
  95.     def simpleMethodImpl[C: c.WeakTypeTag, R: c.WeakTypeTag](c: blackbox.Context)(name: c.Expr[String]): c.Expr[RefMethod[C, R]] = {
  96.       import c.universe._
  97.       val classTag = c.weakTypeTag[C]
  98.       val cType = classTag.tpe
  99.       val returnTag = c.weakTypeTag[R]
  100.       val rType = returnTag.tpe
  101.       val className = cType.typeSymbol.fullName
  102.       val retName = rType.typeSymbol.fullName
  103.       val Literal(Constant(methodNameRaw: String)) = name.tree
  104.       val methodName = NameTransformer.encode(methodNameRaw)
  105.       val sym = cType.member(TermName(methodName))
  106.       if (sym.alternatives.isEmpty)
  107.         c.abort(c.enclosingPosition, s"Method $methodNameRaw is not defined in $className")
  108.       if (sym.alternatives.count(_.asMethod.returnType =:= rType) > 1)
  109.         c.abort(c.enclosingPosition, s"Method $className.$methodNameRaw: $retName  in  " +
  110.           s"is ambiguous, try referencing it with tpe.methods.$methodNameRaw[$retName](type1, type2, ..., typeN)")
  111.       val params = sym.alternatives map (_.asMethod) find (_.returnType =:= rType) match {
  112.         case None =>
  113.           c.abort(c.enclosingPosition, s"No method $methodNameRaw in $className with return type ${
  114.            rType.typeSymbol.fullName
  115.          }")
  116.         case Some(m) =>
  117.           if (m.paramLists.nonEmpty)
  118.             m.paramLists.head.map(_.info)
  119.           else
  120.             Nil
  121.       }
  122.  
  123.       val classLiteral = refType(c)(cType)
  124.       val methLiteral = q"$methodName"
  125.       val srgName = mappings.mapMethod(javaTypeName(c)(cType), methodName, javaTypeName(c)(rType), params map (javaTypeName(c)(_)))
  126.       val srgLiteral = q"$srgName"
  127.       val descriptor = buildDescriptor(c)(params, rType)
  128.       val descLiteral = q"$descriptor"
  129.       val returnTypeLiteral = refType(c)(rType)
  130.       val tpes = params map (refType(c)(_))
  131.       val typesLiteral = q"$tpes"
  132.  
  133.       c.Expr[RefMethod[C, R]] {
  134.         q""" de.mineformers.mcreflect.introspection.RefMethod($classLiteral, $methLiteral, $srgLiteral, $descLiteral, $returnTypeLiteral, $typesLiteral) """
  135.       }
  136.     }
  137.  
  138.     def methodImpl[C: c.WeakTypeTag, R: c.WeakTypeTag](c: blackbox.Context)(name: c.Expr[String])(args: c.Expr[RefType[_]]*): c.Expr[RefMethod[C, R]] = {
  139.       import c.universe._
  140.       val classTag = c.weakTypeTag[C]
  141.       val cType = classTag.tpe
  142.       val returnTag = c.weakTypeTag[R]
  143.       val rType = returnTag.tpe
  144.       val className = cType.typeSymbol.fullName
  145.       val retName = rType.typeSymbol.fullName
  146.       val Literal(Constant(methodNameRaw: String)) = name.tree
  147.       val methodName = NameTransformer.encode(methodNameRaw)
  148.       val sym = cType.member(TermName(methodName))
  149.       if (sym.alternatives.isEmpty)
  150.         c.abort(c.enclosingPosition, s"Method $methodNameRaw is not defined in $className")
  151.       val types = args.toList map (_.actualType.typeArgs.head)
  152.       val params = sym.alternatives map (_.asMethod) find (m => m.returnType =:= rType &&
  153.         m.paramLists.nonEmpty &&
  154.         m.paramLists.head.length == types.length &&
  155.         (m.paramLists.head, types)
  156.         .zipped.forall(_.info =:= _)) match {
  157.         case None =>
  158.           c.abort(c.enclosingPosition, s"No method $methodNameRaw(${types.map(_.typeSymbol.fullName).mkString(", ")}): " +
  159.             s"$retName in $className")
  160.         case Some(m) =>
  161.           m.paramLists.head.map(_.info)
  162.       }
  163.  
  164.       val classLiteral = refType(c)(cType)
  165.       val methLiteral = q"$methodName"
  166.       val srgName = mappings.mapMethod(javaTypeName(c)(cType), methodName, javaTypeName(c)(rType), params map (javaTypeName(c)(_)))
  167.       val srgLiteral = q"$srgName"
  168.       val descriptor = buildDescriptor(c)(params, rType)
  169.       val descLiteral = q"$descriptor"
  170.       val returnTypeLiteral = refType(c)(rType)
  171.       val tpes = params map (refType(c)(_))
  172.       val typesLiteral = q"$tpes"
  173.  
  174.       c.Expr[RefMethod[C, R]] {
  175.         q""" de.mineformers.mcreflect.introspection.RefMethod($classLiteral, $methLiteral, $srgLiteral, $descLiteral, $returnTypeLiteral, $typesLiteral) """
  176.       }
  177.     }
  178.   }
  179.  
  180.   object fields {
  181.  
  182.     def fieldImpl[C: c.WeakTypeTag, T: c.WeakTypeTag](c: blackbox.Context)(name: c.Expr[String]): c.Expr[RefField[C, T]] = {
  183.       import c.universe._
  184.       val classTag = c.weakTypeTag[C]
  185.       val cType = classTag.tpe
  186.       val typeTag = c.weakTypeTag[T]
  187.       val tType = typeTag.tpe
  188.       val className = cType.typeSymbol.fullName
  189.       val typeName = tType.typeSymbol.fullName
  190.       val Literal(Constant(fieldNameRaw: String)) = name.tree
  191.       val fieldName = NameTransformer.encode(fieldNameRaw)
  192.       val sym = cType.member(TermName(fieldName))
  193.       if (!sym.isTerm)
  194.         c.abort(c.enclosingPosition, s"No such field '$fieldNameRaw' in $className")
  195.       val term = sym.asTerm
  196.       if ((term.isMethod && !term.isGetter) || (!term.isMethod && !(term.isVal ^ term.isVar)))
  197.         c.abort(c.enclosingPosition, s"No such field '$fieldNameRaw' in $className")
  198.       if ((term.isMethod && !(term.asMethod.returnType =:= tType)) || (!term.isMethod && !(term.info =:= tType)))
  199.         c.abort(c.enclosingPosition, s"Field '$fieldNameRaw' in $className does not have type $typeName")
  200.  
  201.       val classLiteral = refType(c)(cType)
  202.       val fieldLiteral = q"$fieldName"
  203.       val srgName = mappings.mapField(javaTypeName(c)(cType), fieldName)
  204.       val fieldSrgLiteral = q"$srgName"
  205.       val byteType = nameFromType(c)(tType)
  206.       val byteTypeLiteral = q"$byteType"
  207.       val typeLiteral = refType(c)(tType)
  208.  
  209.       c.Expr[RefField[C, T]] {
  210.         q""" de.mineformers.mcreflect.introspection.RefField[$cType, $tType]($classLiteral, $fieldLiteral, $fieldSrgLiteral, $byteTypeLiteral, $typeLiteral) """
  211.       }
  212.     }
  213.   }
  214.  
  215.   private def refType(c: blackbox.Context)(t: c.Type) = {
  216.     import c.universe._
  217.     val name = javaTypeName(c)(t.dealias)
  218.     q"""de.mineformers.mcreflect.introspection.RefType[$t]($name)"""
  219.   }
  220.  
  221.   def javaTypeName(c: blackbox.Context)(t: c.Type): String = t.typeSymbol.fullName match {
  222.     case "scala.Unit"    => "void"
  223.     case "scala.Boolean" => "boolean"
  224.     case "scala.Char"    => "char"
  225.     case "scala.Byte"    => "byte"
  226.     case "scala.Short"   => "short"
  227.     case "scala.Int"     => "int"
  228.     case "scala.Float"   => "float"
  229.     case "scala.Long"    => "long"
  230.     case "scala.Double"  => "double"
  231.     case "scala.Array"   => javaTypeName(c)(t.typeArgs.head.dealias) + "[]"
  232.     case x               => resolveInnerClass(c)(t)
  233.   }
  234.  
  235.   private def buildDescriptor(c: blackbox.Context)(paramTypes: List[c.Type], returnType: c.Type): String = {
  236.     paramTypes.map(x => nameFromType(c)(x)).mkString("(", "", ")") + nameFromType(c)(returnType)
  237.   }
  238.  
  239.   def resolveInnerClass(c: blackbox.Context)(t: c.Type) = {
  240.     import c.universe._
  241.  
  242.     def enclosingType(sym: Symbol): Symbol = {
  243.       if (sym == NoSymbol) NoSymbol
  244.       else if (sym.isType && (sym.owner.isPackage || sym.owner == NoSymbol)) sym
  245.       else enclosingType(sym.owner)
  246.     }
  247.  
  248.     def innerClassName(sym: Symbol) = {
  249.       val tName = t.typeSymbol.fullName
  250.       val sName = sym.fullName
  251.       if (sName != tName) {
  252.         val innerName = tName.replaceFirst(sName, "").replace(".", "$")
  253.         sName + innerName
  254.       } else
  255.         sym.fullName
  256.     }
  257.  
  258.     innerClassName(enclosingType(t.typeSymbol))
  259.   }
  260.  
  261.   def nameFromType(c: blackbox.Context)(t: c.Type) = {
  262.     import c.universe._
  263.     val vRef = typeOf[Unit]
  264.     val zRef = typeOf[Boolean]
  265.     val cRef = typeOf[Char]
  266.     val bRef = typeOf[Byte]
  267.     val sRef = typeOf[Short]
  268.     val iRef = typeOf[Int]
  269.     val fRef = typeOf[Float]
  270.     val jRef = typeOf[Long]
  271.     val dRef = typeOf[Double]
  272.     c match {
  273.       case _ if t =:= vRef => "V"
  274.       case _ if t =:= zRef => "Z"
  275.       case _ if t =:= cRef => "C"
  276.       case _ if t =:= bRef => "B"
  277.       case _ if t =:= sRef => "S"
  278.       case _ if t =:= iRef => "I"
  279.       case _ if t =:= fRef => "F"
  280.       case _ if t =:= jRef => "J"
  281.       case _ if t =:= dRef => "D"
  282.       case _               => "L" + resolveInnerClass(c)(t).replace('.', '/') + ";"
  283.     }
  284.   }
  285. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement