summaryrefslogblamecommitdiff
path: root/test/files/run/reify_printf.scala
blob: cd6052bc5ebfe459f9aae4cd71910b4a278368d1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                             


                                          
                                       





















































                                                                                                              
import java.io.{ ByteArrayOutputStream, PrintStream }
import scala.reflect.Code
import scala.reflect.mirror._
import scala.reflect.api._
import scala.reflect.api.Trees
import scala.reflect.internal.Types
import reflect.runtime.Mirror.ToolBox
import scala.tools.nsc.reporters._
import scala.tools.nsc.Settings
import scala.util.matching.Regex

object Test extends App {
  val tree = tree_printf(Code.lift("hello %s").tree, Code.lift("world").tree)

  val reporter = new ConsoleReporter(new Settings)
  val toolbox = new ToolBox(reporter, args mkString " ")

  val output = new ByteArrayOutputStream()
  Console.setOut(new PrintStream(output))
  val evaluated = toolbox.runExpr(tree)

  assert(output.toString() == "hello world", output.toString() +" ==     hello world")

  /*
  macro def printf(format: String, params: Any*) : String = tree_printf(format: Tree, (params: Seq[Tree]): _*)
   */

  var i = 0
  def gensym(name: String) = { i += 1; newTermName(name + i) }

  def createTempValDef( value : Tree, tpe : Type ) : (Option[Tree],Tree) = {
    val local = gensym("temp")
    (
      Some(
        ValDef(
          Modifiers()
          , local
          , TypeTree().setType(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, classToType(classOf[Int]) )
      case "%s" => createTempValDef( paramsStack.pop, classToType(classOf[String]) )
      case "%%" => {
        (None:Option[Tree], Literal(Constant("%")))
      }
      case part => {
        (None:Option[Tree], Literal(Constant(part)))
      }
    }

    val evals = for ((Some(eval), _) <- parsed if eval != None) yield (eval: Tree)
    val prints = for ((_, ref) <- parsed) yield
      Apply(
        Select(
          Select(
            Ident( newTermName("scala") )
            , newTermName("Predef")
          )
          , newTermName("print")
        )
        , List(ref)
      ): Tree
    Block((evals ++ prints).toList, Literal(Constant(())))
  }
}