diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-01-20 01:52:40 +0100 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-01-20 06:54:20 +0100 |
commit | 35e676ded0f9bfd006a5f090841abdea3ff1759c (patch) | |
tree | ade8247e0ebc66964189875194f78b85c6596d27 /test/files/macros/Printf.scala | |
parent | 58cb15c40dc431e45eaa0a5278874d9996e42104 (diff) | |
download | scala-35e676ded0f9bfd006a5f090841abdea3ff1759c.tar.gz scala-35e676ded0f9bfd006a5f090841abdea3ff1759c.tar.bz2 scala-35e676ded0f9bfd006a5f090841abdea3ff1759c.zip |
Progress with macros
A short recap:
* Macro expansion now works finely for instance macro invocations
* Macros are now hidden behind -Xmacros
* Bodies of macros now have "import _context._" in their preamble
* Macros are now loaded from classpath, much like regular libraries
* Macros can now override methods (in that case macro expansion
does not crash if macro is not found, it just falls back to super)
Review by @odersky.
Diffstat (limited to 'test/files/macros/Printf.scala')
-rw-r--r-- | test/files/macros/Printf.scala | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/test/files/macros/Printf.scala b/test/files/macros/Printf.scala new file mode 100644 index 0000000000..4a88e5b069 --- /dev/null +++ b/test/files/macros/Printf.scala @@ -0,0 +1,39 @@ +// macros should be built separately from their clients, so simple "scalac Printf.scala Test.scala" won't work +// 1) first build this file with "scalac -Xmacros Printf.scala" +// 2) the build the test with "scalac -cp <output directory of compiling Printf.scala> Test.scala" + +object Printf extends App { + def macro printf(format: String, params: Any*) : String = { + var i = 0 + def gensym(name: String) = { i += 1; newTermName(name + i) } + + def createTempValDef(value: Tree, clazz: Class[_]): (Option[Tree], Tree) = { + val local = gensym("temp") + val tpe = if (clazz == classOf[Int]) Ident(newTypeName("Int")) + else if (clazz == classOf[String]) Select(Select(Ident(newTermName("java")), newTermName("lang")), newTypeName("String")) + else throw new Exception("unknown class " + clazz.toString) + (Some(ValDef(Modifiers(), local, tpe, value)), Ident(local)) + } + + def tree_printf(format: Tree, params: Tree*) = { + val Literal(Constant(s_format: String)) = format + val paramsStack = scala.collection.mutable.Stack(params: _*) + val parsed = s_format.split("(?<=%[\\w%])|(?=%[\\w%])") map { + case "%d" => createTempValDef(paramsStack.pop, classOf[Int]) + case "%s" => createTempValDef(paramsStack.pop, classOf[String]) + case "%%" => (None, Literal(Constant("%"))) + case part => (None, Literal(Constant(part))) + } + + val evals = for ((Some(eval), _) <- parsed if eval != None) yield eval + val prints = for ((_, ref) <- parsed) yield { + val print = Select(Select(Ident(newTermName("scala")), newTermName("Predef")), newTermName("print")) + Apply(print, List(ref)) + } + + Block((evals ++ prints).toList, Literal(Constant(()))) + } + + tree_printf(format, params: _*) + } +} |