Skip to content

Instantly share code, notes, and snippets.

@wangzaixiang
Created March 31, 2013 14:30
Show Gist options
  • Save wangzaixiang/5280755 to your computer and use it in GitHub Desktop.
Save wangzaixiang/5280755 to your computer and use it in GitHub Desktop.
Macro code to build a enum Just a simple prototype, but maybe useful for future. Learn how to build the AST, I first using the reify and the c.universe.showRaw, and using the scalac -Xprint:4 to show how the compiler generate the reifly code. It is nesseary to learn the reflect API in more deep.
package wangzx.macros
import scala.language.experimental.macros
import scala.reflect.macros.Context
import java.lang.String
import scala.reflect.api.Symbols
object EnumsMacro {
def docs[A](obj: A): Map[Int, String] = macro docsMacro[A]
def docsMacro[A](c: Context)(obj: c.Expr[A]): c.Expr[Map[Int, String]] = {
import c.universe._
val m = rootMirror
val typ = obj.actualType
val fields: Map[String, String] = typ.declarations.filter{ it =>
(it.typeSignature <:< typeOf[AnyVal]) && it.asTerm.isVal
}.toList.map { decl: Symbol =>
val docs = decl.annotations.filter { ant =>
ant.tpe.typeSymbol.name.toString == "doc"
}.map { ant =>
val Literal(Constant(doc: String)) :: Nil = ant.scalaArgs
doc
}
println(s"${decl.name} ${docs}")
(decl.name.toString.trim, docs(0))
}.toMap
// elem.valField -> elem.doc
// val expr = reify {
// scala.collection.immutable.Map[Int, String](Tuple2(1, "hello"), Tuple2(2, "world"))
// }
val mapSymbol = m.staticModule("scala.collection.immutable.Map")
val fieldsAsArgs = fields.map { case (name, doc) =>
Apply(
Select(Ident(m.staticModule("scala.Tuple2")), newTermName("apply")),
List(
Select(Select(obj.tree, newTermName(name)), newTermName("v")),
Literal(Constant(doc))))
}
//val x = Select(obj.tree, newTermName("Normal"))
val body = Apply(
TypeApply(
Select(build.Ident(mapSymbol), newTermName("apply")),
List(Ident(m.staticClass("scala.Int")), Ident(m.staticClass("java.lang.String")))),
fieldsAsArgs.toList)
val expr2 = c.Expr[scala.collection.immutable.Map[Int, String]](body)
expr2
}
}
/**
* Spu状态
*/
object SpuState {
@doc("正常") val Normal = new SpuState(0)
@doc("预删除") val PreDelete = new SpuState(1)
@doc("删除/废弃") val Abandon = new SpuState(2)
val docs: Map[Int, String] = EnumsMacro.docs(CommodityModel.SpuState)
}
class SpuState(val v: Byte) extends AnyVal
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment