summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Codification.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Codification.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Codification.scala207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Codification.scala b/src/compiler/scala/tools/nsc/typechecker/Codification.scala
new file mode 100644
index 0000000000..1deda7bdfb
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/Codification.scala
@@ -0,0 +1,207 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.typechecker;
+
+import symtab.Flags._;
+import scala.collection.immutable.ListMap;
+import scala.tools.nsc.util.{ListBuffer, FreshNameCreator};
+
+[_trait_] abstract class Codification: Analyzer {
+
+ import global._;
+
+ case class FreeValue(tree: Tree) extends reflect.Code;
+
+ type ReifyEnvironment = ListMap[Symbol, reflect.Symbol];
+
+ class Reifier(env: ReifyEnvironment, currentOwner: reflect.Symbol) {
+
+ def reify(tree: Tree): reflect.Code = tree match {
+ case Ident(_) =>
+ val rsym = reify(tree.symbol);
+ if (rsym == reflect.NoSymbol) FreeValue(tree)
+ else reflect.Ident(rsym)
+ case Select(qual, _) =>
+ val rsym = reify(tree.symbol);
+ if (rsym == reflect.NoSymbol) throw new TypeError("cannot reify symbol: " + tree.symbol)
+ else reflect.Select(reify(qual), reify(tree.symbol))
+ case Literal(constant) =>
+ reflect.Literal(constant.value)
+ case Apply(fun, args) =>
+ reflect.Apply(reify(fun), args map reify)
+ case TypeApply(fun, args) =>
+ reflect.TypeApply(reify(fun), args map (.tpe) map reify)
+ case Function(vparams, body) =>
+ var env1 = env;
+ for (val vparam <- vparams) {
+ val local = reflect.LocalValue(
+ currentOwner, vparam.symbol.name.toString(), reify(vparam.symbol.tpe));
+ env1 = env1.update(vparam.symbol, local);
+ }
+ reflect.Function(vparams map (.symbol) map env1,
+ new Reifier(env1, currentOwner).reify(body))
+ case This(_) =>
+ reflect.This(reify(tree.symbol))
+ case _ =>
+ throw new TypeError("cannot reify tree: " + tree)
+ }
+
+ private def mkGlobalSymbol(fullname: String, sym: Symbol): reflect.Symbol =
+ if (sym.isClass) reflect.Class(fullname)
+ else if (sym.isType) reflect.TypeField(fullname, reify(sym.info))
+ else if (sym.isMethod) reflect.Method(fullname, reify(sym.info))
+ else reflect.Field(fullname, reify(sym.info));
+
+ def reify(sym: Symbol): reflect.Symbol = env.get(sym) match {
+ case Some(rsym) =>
+ rsym
+ case None =>
+ if (sym.isRoot || sym.isRootPackage || sym.isEmptyPackageClass || sym.isEmptyPackage)
+ reflect.RootSymbol
+ else reify(sym.owner) match {
+ case reflect.NoSymbol =>
+ reflect.NoSymbol;
+ case reflect.RootSymbol =>
+ mkGlobalSymbol(sym.name.toString(), sym)
+ case reflect.Class(ownername) =>
+ mkGlobalSymbol(ownername + "." + sym.name, sym)
+ case _ =>
+ reflect.NoSymbol
+ }
+ }
+
+ def reify(tp: Type): reflect.Type = null /*tp match {
+ case NoPrefix =>
+ reflect.NoPrefix
+ case NoType =>
+ reflect.NoType
+ case TypeRef(pre, sym, args) =>
+ val tp = if (sym.owner.isPackageClass) reflect.NamedType(sym.fullNameString);
+ else reflect.PrefixedType(reify(pre), reify(sym));
+ if (args.isEmpty) tp else reflect.AppliedType(tp, args map reify)
+ case SingleType(pre, sym) =>
+ reflect.SingleType(reify(pre), reify(sym))
+ case ThisType(clazz) =>
+ reflect.ThisType(reify(clazz))
+ case TypeBounds(lo, hi) =>
+ reflect.TypeBounds(reify(lo), reify(hi))
+ case MethodType(formals, restp) =>
+ val formals1 = formals map reify;
+ val restp1 = reify(restp);
+ if (tp.isInstanceOf[ImplicitMethodType]) new reflect.ImplicitMethodType(formals1, restp1)
+ else reflect.MethodType(formals1, restp1)
+ //case PolyType(typeParams, ClassInfoType(parents, decls, symbol)) => reflect.PolyType(typeParams map reify, Nil, resultType)
+ //case PolyType(typeParams, SingleType(pre, sym)) => reflect.PolyType(typeParams map reify, Nil, resultType)
+ case PolyType(typeParams, MethodType(paramsList, resultType)) =>
+ System.err.println("poly polyyyy");
+ reflect.PolyType(Nil, Nil , reify(resultType)) //typeParams map mkTypeBounds
+ case _ =>
+ throw new TypeError("cannot reify type: " + tp)
+ }*/
+ }
+
+ type InjectEnvironment = ListMap[reflect.Symbol, Name];
+
+ class Injector(env: InjectEnvironment, fresh: FreshNameCreator) {
+
+ // todo replace className by caseName in CaseClass once we have switched to nsc.
+ def className(value: CaseClass): String = value match {
+ case _ :: _ => "scala.$colon$colon"
+ case reflect.Ident(_) => "scala.reflect.Ident"
+ case reflect.Select(_, _) => "scala.reflect.Select"
+ case reflect.Literal(_) => "scala.reflect.Literal"
+ case reflect.Apply(_, _) => "scala.reflect.Apply"
+ case reflect.TypeApply(_, _) => "scala.reflect.TypeApply"
+ case reflect.Function(_, _) => "scala.reflect.Function"
+ case reflect.Class(_) => "scala.reflect.Class"
+ case reflect.Method(_, _) => "scala.reflect.Method"
+ case reflect.Field(_, _) => "scala.reflect.Field"
+ case reflect.This(_) => "scala.reflect.This"
+ case reflect.NamedType(_) => "scala.reflect.NamedType"
+ case reflect.PrefixedType(_, _) => "scala.reflect.PrefixedType"
+ case reflect.SingleType(_, _) => "scala.reflect.SingleType"
+ case reflect.ThisType(_) => "scala.reflect.ThisType"
+ case reflect.AppliedType(_, _) => "scala.reflect.AppliedType"
+ case reflect.TypeBounds(_, _) => "scala.reflect.TypeBounds"
+ case reflect.MethodType(_, _) =>
+ if (value.isInstanceOf[reflect.ImplicitMethodType]) "scala.reflect.ImplicitMethodType" else "scala.reflect.MethodType"
+ case reflect.PolyType(_, _, _) => "scala.reflect.PolyType"
+ case _ =>
+ ""
+ }
+
+ def objectName(value: Any): String = value match {
+ case Nil => "scala.Nil"
+ case reflect.NoSymbol => "scala.reflect.NoSymbol"
+ case reflect.RootSymbol => "scala.reflect.RootSymbol"
+ case reflect.NoPrefix => "scala.reflect.NoPrefix"
+ case reflect.NoType => "scala.reflect.NoType"
+ case _ => ""
+ }
+
+ def injectType(name: String): Tree = TypeTree(definitions.getClass(name).initialize.tpe);
+
+ def inject(value: Any): Tree = value match {
+ case FreeValue(tree) =>
+ tree
+ case reflect.Function(params, body) =>
+ var env1 = env;
+ val vdefs = for (val param <- params) yield {
+ val lname = newTermName(fresh.newName());
+ env1 = env1.update(param, lname);
+ ValDef(NoMods, lname, injectType("scala.reflect.LocalValue"),
+ New(injectType("scala.reflect.LocalValue"),
+ List(List(inject(param.owner), inject(param.name), inject(param.tpe)))))
+ }
+ Block(vdefs, new Injector(env1, fresh).inject(body))
+ case rsym: reflect.LocalSymbol =>
+ Ident(env(rsym))
+ case x: String => Literal(Constant(x))
+ case x: Boolean => Literal(Constant(x))
+ case x: Byte => Literal(Constant(x))
+ case x: Short => Literal(Constant(x))
+ case x: Char => Literal(Constant(x))
+ case x: Int => Literal(Constant(x))
+ case x: Long => Literal(Constant(x))
+ case x: Float => Literal(Constant(x))
+ case x: Double => Literal(Constant(x))
+ case c: CaseClass =>
+ val name = objectName(c);
+ if (name.length() != 0) gen.mkRef(definitions.getModule(name))
+ else {
+ val name = className(c);
+ if (name.length() == 0) throw new Error("don't know how to inject " + value);
+ val injectedArgs = new ListBuffer[Tree];
+ for (val i <- Iterator.range(0, c.caseArity))
+ injectedArgs += inject(c.caseElement(i));
+ New(Ident(definitions.getClass(name)), List(injectedArgs.toList))
+ }
+ case null => gen.mkRef(definitions.getModule("scala.reflect.NoType"))
+ case _ => throw new Error("don't know how to inject " + value);
+ }
+ }
+
+ def reify(tree: Tree): reflect.Code =
+ new Reifier(ListMap.Empty, reflect.NoSymbol).reify(tree);
+
+ def inject(code: reflect.Code): Tree =
+ new Injector(ListMap.Empty, new FreshNameCreator).inject(code);
+
+ /** returns
+ * < new TypedCode[T](tree1) >
+ * where T = tree.tpe
+ * tree1 = inject(reify(tree))
+ */
+ def codify(tree: Tree): Tree = {
+ val reified = reify(tree);
+ if (settings.debug.value) log("reified = " + reified);
+ val injected = inject(reified);
+ if (settings.debug.value) log("injected = " + injected);
+ New(TypeTree(appliedType(definitions.TypedCodeClass.typeConstructor, List(tree.tpe))),
+ List(List(injected)));
+
+ }
+}