diff options
Diffstat (limited to 'test/files')
-rw-r--r-- | test/files/macros/Printf.scala | 39 | ||||
-rw-r--r-- | test/files/macros/Test.scala | 8 | ||||
-rw-r--r-- | test/files/macros/macros_v0001.bat | 40 | ||||
-rw-r--r-- | test/files/macros/macros_v0001.sh | 30 | ||||
-rw-r--r-- | test/files/pos/macros.flags | 2 | ||||
-rw-r--r-- | test/files/pos/macros.scala | 6 | ||||
-rw-r--r-- | test/files/run/Predef.readLine.check | 3 | ||||
-rw-r--r-- | test/files/run/Predef.readLine.scala | 10 | ||||
-rw-r--r-- | test/files/run/macro-range.check | 9 | ||||
-rw-r--r-- | test/files/run/macro-range.flags | 1 | ||||
-rw-r--r-- | test/files/run/macro-range/macro_range_1.scala | 94 | ||||
-rw-r--r-- | test/files/run/macro-range/macro_range_2.scala | 94 |
12 files changed, 331 insertions, 5 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: _*) + } +} diff --git a/test/files/macros/Test.scala b/test/files/macros/Test.scala new file mode 100644 index 0000000000..d8cdcf6756 --- /dev/null +++ b/test/files/macros/Test.scala @@ -0,0 +1,8 @@ +// macros should be built separately from their clients, so simple "scalac Printf.scala Test.scala" won't work +// 1) first build the printf macro with "scalac -Xmacros Printf.scala" +// 2) the build this file with "scalac -cp <output directory of compiling Printf.scala> Test.scala" + +object Test extends App { + import Printf._ + printf("hello %s", "world") +}
\ No newline at end of file diff --git a/test/files/macros/macros_v0001.bat b/test/files/macros/macros_v0001.bat new file mode 100644 index 0000000000..3395d2e3c1 --- /dev/null +++ b/test/files/macros/macros_v0001.bat @@ -0,0 +1,40 @@ +@echo off
+
+set scalahome=%~dp0\..\..\..
+set scaladeps=%scalahome%\lib\jline.jar;%scalahome%\lib\fjbg.jar
+set scalalib=%scalahome%\build\pack\lib\scala-library.jar
+if not exist "%scalalib%" set scalalib=%scalahome%\build\locker\classes\library
+set scalacomp="%scalahome%\build\pack\lib\scala-compiler.jar"
+if not exist "%scalacomp%" set scalacomp=%scalahome%\build\locker\classes\compiler
+set stdcp=%scaladeps%;%scalalib%;%scalacomp%
+
+echo Compiling macros...
+set cp=%stdcp%
+call :scalac -Xmacros "%~dp0\Printf.scala"
+
+echo Compiling the program...
+set cp=%stdcp%;%~dp0.
+call :scalac "%~dp0\Test.scala"
+
+echo.
+echo NOW LOOK!!!
+echo ===============================================
+set cp=%stdcp%;%~dp0.
+call :scala Test
+echo.
+echo ===============================================
+goto :eof
+
+:scalac
+setlocal
+call set args=%*
+rem echo java -cp "%cp%" -Dscala.usejavacp=true scala.tools.nsc.Main %args%
+java -cp "%cp%" -Dscala.usejavacp=true scala.tools.nsc.Main %args%
+endlocal&goto :eof
+
+:scala
+setlocal
+call set args=%*
+rem echo java -cp "%cp%" -Dscala.usejavacp=true scala.tools.nsc.MainGenericRunner %args%
+java -cp "%cp%" -Dscala.usejavacp=true scala.tools.nsc.MainGenericRunner %args%
+endlocal&goto :eof
diff --git a/test/files/macros/macros_v0001.sh b/test/files/macros/macros_v0001.sh new file mode 100644 index 0000000000..abe09836bb --- /dev/null +++ b/test/files/macros/macros_v0001.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -o errexit + +if [[ $(uname -s) == CYGWIN* ]]; then cpsep=";"; else cpsep=":"; fi +scripthome="$(dirname "$0")" +scalahome="$scripthome/../../.." +scaladeps="$scalahome/lib/jline.jar;$scalahome/lib/fjbg.jar" +scalalib="$scalahome/build/pack/lib/scala-library.jar" +if [ ! -f "$scalalib" ]; then scalalib="$scalahome/build/locker/classes/library"; fi +scalacomp="$scalahome/build/pack/lib/scala-compiler.jar" +if [ ! -f "$scalacomp" ]; then scalacomp="$scalahome/build/locker/classes/compiler"; fi +stdcp="$scaladeps$cpsep$scalalib$cpsep$scalacomp" +function scalac { java -cp "$cp" -Dscala.usejavacp=true scala.tools.nsc.Main $*; } +function scala { java -cp "$cp" -Dscala.usejavacp=true scala.tools.nsc.MainGenericRunner $*; } + +echo "Compiling macros..." +cp="$stdcp" +scalac -Xmacros "$scripthome/Printf.scala" + +echo "Compiling the program..." +cp="$stdcp$cpsep$scripthome" +scalac "$scripthome/Test.scala" + +echo "" +echo "NOW LOOK" +echo "===============================================" +cp="$stdcp$cpsep$scripthome" +scala Test +echo "" +echo "===============================================" diff --git a/test/files/pos/macros.flags b/test/files/pos/macros.flags index e1b37447c9..7fea2ff901 100644 --- a/test/files/pos/macros.flags +++ b/test/files/pos/macros.flags @@ -1 +1 @@ --Xexperimental
\ No newline at end of file +-Xmacros
\ No newline at end of file diff --git a/test/files/pos/macros.scala b/test/files/pos/macros.scala index 8a98195978..303610d464 100644 --- a/test/files/pos/macros.scala +++ b/test/files/pos/macros.scala @@ -1,10 +1,8 @@ object Test { - class C { + class C { def macro foo[T](xs: List[T]): T = (T, xs) match { - case (t1: glob.Type, t2: glob.Tree) => t2 + case (t1: Type, t2: Tree) => t2 } } } - - diff --git a/test/files/run/Predef.readLine.check b/test/files/run/Predef.readLine.check new file mode 100644 index 0000000000..4fb2bc4c6a --- /dev/null +++ b/test/files/run/Predef.readLine.check @@ -0,0 +1,3 @@ +prompt +fancy prompt +immensely fancy prompt
\ No newline at end of file diff --git a/test/files/run/Predef.readLine.scala b/test/files/run/Predef.readLine.scala new file mode 100644 index 0000000000..9f07936638 --- /dev/null +++ b/test/files/run/Predef.readLine.scala @@ -0,0 +1,10 @@ +import java.io.StringReader + +object Test extends App { + Console.withIn(new StringReader("")) { + readLine() + readLine("prompt\n") + readLine("%s prompt\n", "fancy") + readLine("%s %s prompt\n", "immensely", "fancy") + } +}
\ No newline at end of file diff --git a/test/files/run/macro-range.check b/test/files/run/macro-range.check new file mode 100644 index 0000000000..0719398930 --- /dev/null +++ b/test/files/run/macro-range.check @@ -0,0 +1,9 @@ +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/test/files/run/macro-range.flags b/test/files/run/macro-range.flags new file mode 100644 index 0000000000..06a7b31f11 --- /dev/null +++ b/test/files/run/macro-range.flags @@ -0,0 +1 @@ +-Xmacros diff --git a/test/files/run/macro-range/macro_range_1.scala b/test/files/run/macro-range/macro_range_1.scala new file mode 100644 index 0000000000..15a018fcff --- /dev/null +++ b/test/files/run/macro-range/macro_range_1.scala @@ -0,0 +1,94 @@ +import reflect.api.Modifier +import reflect.macro.Context + +abstract class RangeDefault { + val from, to: Int + def foreach(f: Int => Unit) = { + var i = from + while (i < to) { f(i); i += 1 } + } +} + +/** This class should go into reflect.macro once it is a bit more stable. */ +abstract class Utils { + val context: Context + import context._ + + class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer { + override def transform(tree: Tree): Tree = tree match { + case Ident(_) => + def subst(from: List[Symbol], to: List[Tree]): Tree = + if (from.isEmpty) tree + else if (tree.symbol == from.head) to.head.duplicate // TODO: does it ever make sense *not* to perform a shallowDuplicate on `to.head`? + else subst(from.tail, to.tail); + subst(from, to) + case _ => + val tree1 = super.transform(tree) + if (tree1 ne tree) tree1.tpe = null + tree1 + } + } + def makeApply(fn: Tree, args: List[Tree]): Tree = fn match { + case Function(vparams, body) => + new TreeSubstituter(vparams map (_.symbol), args) transform body + case Block(stats, expr) => + Block(stats, makeApply(expr, args)) + case _ => + println("no beta on "+fn+" "+fn.getClass) + Apply(fn, args) + } + def makeWhile(lname: TermName, cond: Tree, body: Tree): Tree = { + val continu = Apply(Ident(lname), Nil) + val rhs = If(cond, Block(List(body), continu), Literal(Constant())) + LabelDef(lname, Nil, rhs) + } + def makeBinop(left: Tree, op: String, right: Tree): Tree = + Apply(Select(left, newTermName(op)), List(right)) +} + +class Range(val from: Int, val to: Int) extends RangeDefault { + override def macro foreach(f: Int => Unit): Unit = { + println("macro-expand, _this = "+ _this) + import _context._ + object utils extends Utils { + val context: _context.type = _context + } + import utils._ + + val initName = newTermName("<init>") + // Either: + // scala"{ var i = $low; val h = $hi; while (i < h) { $f(i); i = i + 1 } } + // or: + // scala"($_this: RangeDefault).foreach($f)" + _this match { + case Apply(Select(New(tpt), initName), List(lo, hi)) if tpt.symbol.fullName == "Range" => + val iname = newTermName("$i") + val hname = newTermName("$h") + def iref = Ident(iname) + def href = Ident(hname) + val labelname = newTermName("$while") + val cond = makeBinop(iref, "$less", href) + val body = Block( + List(makeApply(f, List(iref))), + Assign(iref, makeBinop(iref, "$plus", Literal(Constant(1))))) + tools.nsc.util.trace("generated: ")( + Block( + List( + ValDef(Modifiers(Set(Modifier.mutable)), iname, TypeTree(), lo), + ValDef(Modifiers(), hname, TypeTree(), hi)), + makeWhile(labelname, cond, body))) + case _ => + Apply( + Select( + Typed(_this, Ident(newTypeName("RangeDefault"))), + newTermName("foreach")), + List(f)) + } + } +} + +object Test extends App { + + new Range(1, 10) foreach println + +} diff --git a/test/files/run/macro-range/macro_range_2.scala b/test/files/run/macro-range/macro_range_2.scala new file mode 100644 index 0000000000..15a018fcff --- /dev/null +++ b/test/files/run/macro-range/macro_range_2.scala @@ -0,0 +1,94 @@ +import reflect.api.Modifier +import reflect.macro.Context + +abstract class RangeDefault { + val from, to: Int + def foreach(f: Int => Unit) = { + var i = from + while (i < to) { f(i); i += 1 } + } +} + +/** This class should go into reflect.macro once it is a bit more stable. */ +abstract class Utils { + val context: Context + import context._ + + class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer { + override def transform(tree: Tree): Tree = tree match { + case Ident(_) => + def subst(from: List[Symbol], to: List[Tree]): Tree = + if (from.isEmpty) tree + else if (tree.symbol == from.head) to.head.duplicate // TODO: does it ever make sense *not* to perform a shallowDuplicate on `to.head`? + else subst(from.tail, to.tail); + subst(from, to) + case _ => + val tree1 = super.transform(tree) + if (tree1 ne tree) tree1.tpe = null + tree1 + } + } + def makeApply(fn: Tree, args: List[Tree]): Tree = fn match { + case Function(vparams, body) => + new TreeSubstituter(vparams map (_.symbol), args) transform body + case Block(stats, expr) => + Block(stats, makeApply(expr, args)) + case _ => + println("no beta on "+fn+" "+fn.getClass) + Apply(fn, args) + } + def makeWhile(lname: TermName, cond: Tree, body: Tree): Tree = { + val continu = Apply(Ident(lname), Nil) + val rhs = If(cond, Block(List(body), continu), Literal(Constant())) + LabelDef(lname, Nil, rhs) + } + def makeBinop(left: Tree, op: String, right: Tree): Tree = + Apply(Select(left, newTermName(op)), List(right)) +} + +class Range(val from: Int, val to: Int) extends RangeDefault { + override def macro foreach(f: Int => Unit): Unit = { + println("macro-expand, _this = "+ _this) + import _context._ + object utils extends Utils { + val context: _context.type = _context + } + import utils._ + + val initName = newTermName("<init>") + // Either: + // scala"{ var i = $low; val h = $hi; while (i < h) { $f(i); i = i + 1 } } + // or: + // scala"($_this: RangeDefault).foreach($f)" + _this match { + case Apply(Select(New(tpt), initName), List(lo, hi)) if tpt.symbol.fullName == "Range" => + val iname = newTermName("$i") + val hname = newTermName("$h") + def iref = Ident(iname) + def href = Ident(hname) + val labelname = newTermName("$while") + val cond = makeBinop(iref, "$less", href) + val body = Block( + List(makeApply(f, List(iref))), + Assign(iref, makeBinop(iref, "$plus", Literal(Constant(1))))) + tools.nsc.util.trace("generated: ")( + Block( + List( + ValDef(Modifiers(Set(Modifier.mutable)), iname, TypeTree(), lo), + ValDef(Modifiers(), hname, TypeTree(), hi)), + makeWhile(labelname, cond, body))) + case _ => + Apply( + Select( + Typed(_this, Ident(newTypeName("RangeDefault"))), + newTermName("foreach")), + List(f)) + } + } +} + +object Test extends App { + + new Range(1, 10) foreach println + +} |