mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-13 17:04:25 +00:00
346 lines
13 KiB
Scala
346 lines
13 KiB
Scala
package codechicken.multipart.asm
|
|
|
|
import scala.reflect.runtime.{universe => ru}
|
|
import ru._
|
|
import Flag._
|
|
import scala.tools.reflect.ToolBox
|
|
import scala.collection.mutable.{Map => MMap}
|
|
import codechicken.multipart.TileMultipart
|
|
import codechicken.multipart.TileMultipartClient
|
|
import codechicken.multipart.handler.MultipartProxy
|
|
import cpw.mods.fml.common.FMLCommonHandler
|
|
import codechicken.multipart.TMultiPart
|
|
import cpw.mods.fml.relauncher.Side
|
|
import codechicken.multipart.MultipartGenerator
|
|
|
|
/**
|
|
* Adds top level code gen to toolboxes
|
|
* Scala 2.10 implementaton for https://github.com/scala/scala/pull/2662
|
|
*/
|
|
class ExtendedToolbox(tb:ToolBox[ru.type])
|
|
{
|
|
def define(tree: ImplDef, pkg:String): Symbol =
|
|
{
|
|
val compiler = tb.asInstanceOf[{ def compiler: scala.tools.nsc.Global }].compiler
|
|
val importer = compiler.mkImporter(ru)
|
|
val exporter = importer.reverse
|
|
val ctree: compiler.ImplDef = importer.importTree(tree).asInstanceOf[compiler.ImplDef]
|
|
def defineInternal(ctree: compiler.ImplDef): compiler.Symbol =
|
|
{
|
|
import compiler._
|
|
|
|
val pdef = PackageDef(Ident(pkg:TermName), List(ctree))
|
|
val unit = new CompilationUnit(scala.reflect.internal.util.NoSourceFile)
|
|
unit.body = pdef
|
|
|
|
val run = new Run
|
|
reporter.reset()
|
|
run.compileUnits(List(unit), run.namerPhase)
|
|
compiler.asInstanceOf[{ def throwIfErrors(): Unit }].throwIfErrors()
|
|
|
|
ctree.symbol
|
|
}
|
|
val csym: compiler.Symbol = defineInternal(ctree)
|
|
val usym = exporter.importSymbol(csym)
|
|
usym
|
|
}
|
|
}
|
|
|
|
object ExtendedToolbox
|
|
{
|
|
implicit def extend(tb:ToolBox[ru.type]) = new ExtendedToolbox(tb)
|
|
}
|
|
|
|
object ScalaCompilerFactory extends IMultipartFactory
|
|
{
|
|
import ExtendedToolbox._
|
|
|
|
private var ugenid = 0
|
|
|
|
var mirror = scala.reflect.runtime.currentMirror
|
|
var tb = mirror.mkToolBox()
|
|
private val definedTypes = MMap[String, TypeSymbol]()
|
|
|
|
def getType(obj:Any) = mirror.classSymbol(obj.getClass).toType
|
|
|
|
def Apply(f:Tree, args:Tree*) = scala.reflect.runtime.universe.Apply(f, List(args:_*))
|
|
def Apply(f:Tree, args:List[Tree]) = scala.reflect.runtime.universe.Apply(f, args)
|
|
def TypeApply(f:Tree, args:Tree*) = scala.reflect.runtime.universe.TypeApply(f, List(args:_*))
|
|
def TypeApply(f:Tree, args:List[Tree]) = scala.reflect.runtime.universe.TypeApply(f, args)
|
|
def Invoke(s:Tree, n:TermName, args:Tree*) = Apply(Select(s, n), args:_*)
|
|
def literalUnit = Literal(Constant(()))
|
|
def const(o:Any) = Literal(Constant(o))
|
|
def PkgIdent(s:String):Tree = Ident(typeSymbol(s))
|
|
|
|
def typeSymbol(s:String) = definedTypes.getOrElse(s, mirror.staticClass(s))
|
|
|
|
def defaultConstructor() =
|
|
DefDef(
|
|
Modifiers(),
|
|
nme.CONSTRUCTOR, //method name
|
|
List(), //type params
|
|
List(List()), //params
|
|
TypeTree(), //return type
|
|
Block(
|
|
Invoke(//body
|
|
Super(This(tpnme.EMPTY), tpnme.EMPTY),
|
|
nme.CONSTRUCTOR
|
|
)
|
|
)
|
|
)
|
|
|
|
def normalClassDef(mods:FlagSet, name:String, parents:List[TypeSymbol], methods:List[Tree]) =
|
|
ClassDef(
|
|
Modifiers(mods),
|
|
name,
|
|
List(),
|
|
Template(
|
|
parents.map(Ident(_)),
|
|
emptyValDef,
|
|
methods
|
|
)
|
|
)
|
|
|
|
def uniqueName(prefix:String):String = {
|
|
val ret = prefix+"$$"+ugenid
|
|
ugenid += 1
|
|
return ret
|
|
}
|
|
|
|
def define(tree: ImplDef): TypeSymbol =
|
|
{
|
|
val sym = tb.define(tree, "scfactory").asType
|
|
definedTypes+=((sym.fullName, sym))
|
|
return sym
|
|
}
|
|
|
|
abstract class Generator
|
|
{
|
|
def generate():TileMultipart
|
|
}
|
|
|
|
object SuperSet
|
|
{
|
|
val TileMultipartType = classOf[TileMultipart].getName
|
|
val TileMultipartClientType = classOf[TileMultipartClient].getName
|
|
def apply(types:Seq[String], client:Boolean) = new SuperSet(types, client)
|
|
}
|
|
|
|
class SuperSet(types:Seq[String], client:Boolean)
|
|
{
|
|
import SuperSet._
|
|
val set = baseType+:types.sorted
|
|
|
|
def interfaces = set
|
|
def baseType = if(client) TileMultipartClientType else TileMultipartType
|
|
|
|
override def equals(obj:Any) = obj match
|
|
{
|
|
case x:SuperSet => set == x.set
|
|
case _ => false
|
|
}
|
|
|
|
override def hashCode() = set.hashCode
|
|
|
|
def generate():TileMultipart =
|
|
{
|
|
return generatorMap.getOrElse(this, gen_sync).generate
|
|
}
|
|
|
|
def gen_sync():Generator = tb.synchronized
|
|
{
|
|
return generatorMap.getOrElse(this, {
|
|
var gen = generator
|
|
generatorMap = generatorMap+(this->gen)
|
|
gen
|
|
})
|
|
}
|
|
|
|
def generator():Generator =
|
|
{
|
|
val startTime = System.currentTimeMillis
|
|
val defClass =
|
|
normalClassDef(
|
|
NoFlags,
|
|
uniqueName("TileMultipart_cmp"),
|
|
set.map(s => typeSymbol(s)).toList,
|
|
List(
|
|
defaultConstructor
|
|
)
|
|
)
|
|
val csym = define(defClass)
|
|
|
|
val defClassOf = TypeApply(Ident("classOf"), Ident(csym))
|
|
val cmpClass = tb.eval(defClassOf).asInstanceOf[Class[_ <: TileMultipart]]
|
|
MultipartGenerator.registerTileClass(cmpClass, types.toSet)
|
|
|
|
val defGenClass =
|
|
normalClassDef(
|
|
FINAL,
|
|
uniqueName("TileMultipart_gen"),
|
|
List(typeOf[Generator].typeSymbol.asType),
|
|
List(//methods
|
|
defaultConstructor,
|
|
DefDef(
|
|
Modifiers(OVERRIDE),
|
|
"generate":TermName,
|
|
List(),
|
|
List(List()),
|
|
TypeTree(),
|
|
Invoke(
|
|
New(Ident(csym)),
|
|
nme.CONSTRUCTOR
|
|
)
|
|
)
|
|
)
|
|
)
|
|
val gsym = define(defGenClass)
|
|
|
|
val constructGenClass =
|
|
Invoke(//return new generator instance
|
|
New(Ident(gsym)),
|
|
nme.CONSTRUCTOR
|
|
)
|
|
|
|
val genInst = tb.eval(Block(defGenClass, constructGenClass)).asInstanceOf[Generator]
|
|
println("Generation ["+types.mkString(", ")+"] took: "+(System.currentTimeMillis-startTime))
|
|
return genInst
|
|
}
|
|
}
|
|
|
|
private var generatorMap:Map[SuperSet, Generator] = Map()
|
|
|
|
SuperSet(Seq(), false).generate//default impl, boots generator
|
|
if(FMLCommonHandler.instance.getEffectiveSide == Side.CLIENT)
|
|
SuperSet(Seq(), true).generate
|
|
|
|
private def symbolToValDef(m:Symbol) =
|
|
ValDef(Modifiers(PARAM), m.asTerm.name.decoded, Ident(m), EmptyTree)
|
|
|
|
private def passThroughMethod(tname:String, vname:String, m:MethodSymbol):Tree =
|
|
DefDef(
|
|
Modifiers(Flag.OVERRIDE),
|
|
m.name,
|
|
List(),
|
|
m.paramss.map(_.map(m => symbolToValDef(m))),
|
|
TypeTree(),
|
|
Apply(
|
|
Select(
|
|
Select(This(tname), vname),
|
|
m.name.toTermName),
|
|
m.paramss.flatMap(_.map{m =>
|
|
Ident(m.name)
|
|
})
|
|
)
|
|
)
|
|
|
|
private def passThroughTraitName(iName:String) =
|
|
"T" + (if(iName.startsWith("I")) iName.substring(1) else iName)
|
|
|
|
def generatePassThroughTrait(s_interface:String):String =
|
|
{
|
|
val iSymbol = mirror.staticClass(s_interface)
|
|
val tname = uniqueName(passThroughTraitName(iSymbol.name.decoded))
|
|
val vname = tname+"_impl"
|
|
val methods = iSymbol.toType.members.filter(_.isJava).map(m => passThroughMethod(tname, vname, m.asMethod))
|
|
val traitDef =
|
|
normalClassDef(
|
|
ABSTRACT | TRAIT,
|
|
tname,
|
|
List(
|
|
typeSymbol("codechicken.multipart.TileMultipart"),
|
|
iSymbol),
|
|
List(
|
|
ValDef(//pass through field
|
|
Modifiers(MUTABLE | DEFAULTINIT),
|
|
vname,
|
|
Ident(iSymbol),
|
|
EmptyTree),
|
|
DefDef(
|
|
Modifiers(OVERRIDE),
|
|
"partAdded":TermName,
|
|
List(),
|
|
List(
|
|
List(
|
|
ValDef(Modifiers(PARAM), "part", PkgIdent("codechicken.multipart.TMultiPart"), EmptyTree)
|
|
)),
|
|
TypeTree(),
|
|
Block(
|
|
If(
|
|
TypeApply(
|
|
Select(Ident("part"), "isInstanceOf"),
|
|
Ident(iSymbol)),
|
|
Apply(
|
|
Select(This(tname), vname+"_$eq"),
|
|
TypeApply(
|
|
Select(Ident("part"), "asInstanceOf"),
|
|
Ident(iSymbol))),
|
|
literalUnit),
|
|
Apply(
|
|
Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), "partAdded"),
|
|
Ident("part")
|
|
)
|
|
)),
|
|
DefDef(
|
|
Modifiers(OVERRIDE),
|
|
"partRemoved":TermName,
|
|
List(),
|
|
List(
|
|
List(
|
|
ValDef(Modifiers(PARAM), "part", PkgIdent("codechicken.multipart.TMultiPart"), EmptyTree),
|
|
ValDef(Modifiers(PARAM), "p", PkgIdent("scala.Int"), EmptyTree)
|
|
)),
|
|
TypeTree(),
|
|
Block(
|
|
If(
|
|
Apply(
|
|
Select(Ident("part"), "$eq$eq"),
|
|
Select(This(tname), vname)),
|
|
Apply(
|
|
Select(This(tname), vname+"_$eq"),
|
|
const(null)),
|
|
literalUnit),
|
|
Apply(
|
|
Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), "partRemoved"),
|
|
Ident("part"),
|
|
Ident("p")
|
|
)
|
|
)),
|
|
DefDef(
|
|
Modifiers(OVERRIDE),
|
|
"canAddPart":TermName,
|
|
List(),
|
|
List(
|
|
List(
|
|
ValDef(Modifiers(PARAM), "part", PkgIdent("codechicken.multipart.TMultiPart"), EmptyTree)
|
|
)),
|
|
Ident("Boolean":TypeName),
|
|
Block(
|
|
If(//if(part.isInstanceOf[I] && impl != null)
|
|
Invoke(
|
|
TypeApply(
|
|
Select(Ident("part"), "isInstanceOf"),
|
|
Ident(iSymbol)),
|
|
"$amp$amp",
|
|
Invoke(
|
|
Select(This(tname), vname),
|
|
"$bang$eq",
|
|
const(null))),
|
|
Return(const(false)),//return true
|
|
literalUnit),//else nothing
|
|
Invoke(//call super
|
|
Super(This(tpnme.EMPTY), tpnme.EMPTY),
|
|
"canAddPart",
|
|
Ident("part")
|
|
)
|
|
)
|
|
)
|
|
)
|
|
++methods
|
|
)
|
|
|
|
return define(traitDef).fullName
|
|
}
|
|
|
|
def generateTile(types:Seq[String], client:Boolean) = SuperSet(types, client).generate
|
|
} |