summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2005-10-10 16:05:30 +0000
committerMartin Odersky <odersky@gmail.com>2005-10-10 16:05:30 +0000
commit7af69ba79dff228d3b7e2520e2f7aafec3345d52 (patch)
treec4b25765f66bd64d8ef7ad50a8d429b3a85b86a1
parent90948bf331de457c83c1c625ade401e79861a1c5 (diff)
downloadscala-7af69ba79dff228d3b7e2520e2f7aafec3345d52.tar.gz
scala-7af69ba79dff228d3b7e2520e2f7aafec3345d52.tar.bz2
scala-7af69ba79dff228d3b7e2520e2f7aafec3345d52.zip
*** empty log message ***
-rw-r--r--doc/reference/RationalePart.tex26
-rwxr-xr-xsources/scala/tools/nsc/typechecker/Codification.scala168
2 files changed, 193 insertions, 1 deletions
diff --git a/doc/reference/RationalePart.tex b/doc/reference/RationalePart.tex
index dd6164a3d0..c14eaef5ef 100644
--- a/doc/reference/RationalePart.tex
+++ b/doc/reference/RationalePart.tex
@@ -60,6 +60,30 @@ tests and type casts are generally not considered good object-oriented
style. They are rarely efficient, nor easy to use.
+By contrast, tree transformation is the natural domain of functional
+languages. Their algebraic data types, pattern matching and
+higher-order functions make these languages ideal for the task. It's
+no wonder, then, that specialized languages for transforming XML data
+such as XSLT are functional.
+
+Another reason why functional language constructs are attractive for
+web-services is that mutable state is problematic in this setting.
+Components with mutable state are harder to replicate or to restore
+after a failure. Data with mutable state is harder to cache than
+immutable data. Functional language constructs make it relatively easy
+to construct components without mutable state.
+
+Many web services are constructed by combining different languages.
+For instance, a service might use XSLT to handle document
+transformation, XQuery for database access, and Java for the
+``business logic''. The downside of this approach is that the
+necessary amount of cross-language glue can make applications
+cumbersome to write, verify, and maintain. A particular problem is
+that cross-language interfaces are usually not statically typed.
+Hence, the benefits of a static type system are missing where they are
+needed most -- at the join points of components written in different
+paradigms.
+
Conceivably, the glue problem could be addressed by a ``multi-paradigm''
language that would express object-oriented, concurrent, as well
as functional aspects of an application. But one needs to be careful
@@ -75,7 +99,7 @@ Scala is both an object-oriented and functional language. It is a
pure object-oriented language in the sense that every value is an
object. Types and behavior of objects are described by
classes. Classes can be composed using mixin composition. Scala is
-designed work seamlessly with mainstream object-oriented languages,
+designed to work seamlessly with mainstream object-oriented languages,
in particular Java and C\#.
Scala is also a functional language in the sense that every function
diff --git a/sources/scala/tools/nsc/typechecker/Codification.scala b/sources/scala/tools/nsc/typechecker/Codification.scala
new file mode 100755
index 0000000000..9070b001b3
--- /dev/null
+++ b/sources/scala/tools/nsc/typechecker/Codification.scala
@@ -0,0 +1,168 @@
+/* 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._;
+
+ def codify(tree: Tree): Tree =
+ New(TypeTree(appliedType(definitions.TypedCodeClass.typeConstructor, List(tree.tpe))),
+ List(List(inject(reify(tree)))));
+
+ 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 _ =>
+ throw new TypeError("cannot reify tree: " + tree)
+ }
+
+ def reify(sym: Symbol): reflect.Symbol = env.get(sym) match {
+ case Some(rsym) =>
+ rsym
+ case None =>
+ reify(sym.owner) match {
+ case reflect.NoSymbol =>
+ reflect.NoSymbol;
+ case reflect.Class(ownername) =>
+ val fullname = ownername + "." + sym.name;
+ 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))
+ case _ =>
+ reflect.NoSymbol
+ }
+ }
+
+ def reify(tp: Type): reflect.Type = tp match {
+ case NoPrefix =>
+ reflect.NoPrefix
+ case NoType =>
+ reflect.NoType
+ case TypeRef(pre, sym, args) =>
+ val tp = reflect.TypeIdent(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 _ =>
+ 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 reflect.Ident(_) => "Ident"
+ case reflect.Select(_, _) => "Select"
+ case reflect.Literal(_) => "Literal"
+ case reflect.Apply(_, _) => "Apply"
+ case reflect.TypeApply(_, _) => "TypeApply"
+ case reflect.Function(_, _) => "Function"
+ case reflect.Class(_) => "Class"
+ case reflect.Method(_, _) => "Method"
+ case reflect.Field(_, _) => "Field"
+ case reflect.TypeIdent(_, _) => "TypeIdent"
+ case reflect.SingleType(_, _) => "SingleType"
+ case reflect.ThisType(_) => "ThisType"
+ case reflect.AppliedType(_, _) => "AppliedType"
+ case reflect.TypeBounds(_, _) => "TypeBounds"
+ case reflect.MethodType(_, _) =>
+ if (value.isInstanceOf[reflect.ImplicitMethodType]) "ImplicitMethodType" else "MethodType"
+ case _ =>
+ ""
+ }
+
+ def objectName(value: Any): String = value match {
+ case reflect.NoSymbol => "NoSymbol"
+ case reflect.RootSymbol => "RootSymbol"
+ case reflect.NoPrefix => "NoPrefix"
+ case reflect.NoType => "NoType"
+ case _ => ""
+ }
+
+ def injectType(name: String): Tree = TypeTree(definitions.getClass("scala.reflect." + name).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(0, lname, injectType("LocalValue"),
+ New(injectType("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 s: String =>
+ Literal(Constant(s))
+ case c: CaseClass =>
+ 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(injectType(name), List(injectedArgs.toList))
+ case _ =>
+ val name = objectName(value);
+ if (name.length == 0) throw new Error("don't know how to inject " + value);
+ gen.mkRef(definitions.getModule("scala.reflect." + name))
+ }
+ }
+
+ 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);
+}