Gradle の Scala プラグインで -Xprint オプションを使用

Gradle の Scala プラグインで -Xprint オプションを試してみました。

  • Gradle 1.7

-Xprint はコンパイル途中のコードを出力する Scala コンパイラのオプションで、
-Xprint:<フェーズ> のようにコンパイルフェーズを指定して使用します。

例えば -Xprint:typer と指定する事で implicit による暗黙変換などを処理した後のコードが出力されます。

-Xprint オプション指定方法

Gradle の Scala プラグインで -Xprint のようなオプションを指定するには下記のように compileScala.scalaCompileOptions.additionalParameters を使います。

build.gradle 設定例 (-Xprint:typer 指定)
apply plugin: 'scala'
・・・
compileScala {
    scalaCompileOptions.additionalParameters = ['-Xprint:typer', ・・・]
}

ここで compileScala.scalaCompileOptions.useAnt の値によって、使用される Scala コンパイラクラスや -Xprint の出力に差が生じる点に注意が必要です。

useAnt の値 Scala コンパイラクラス -Xprint の出力
true AntScalaCompiler gradle コマンドで -i オプションを指定すると出力される
false ZincScalaCompiler 特に何もしなくても出力される

なお、useAnt は true がデフォルト値です。

-Xprint:typer を指定したビルド例

それでは、下記のような build.gradle とサンプルソースを使って -Xprint:typer を試してみます。

サンプルソースは http://github.com/fits/try_samples/tree/master/blog/20130928/

ビルド定義 build.gradle
apply plugin: 'scala'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.scala-lang:scala-library:2.10.2'
    compile 'org.scalaz:scalaz-core_2.10:7.1.0-M3'
}

compileScala {
    scalaCompileOptions.additionalParameters = ['-Xprint:typer', '-feature']
    // (1)
    scalaCompileOptions.useAnt = false
    // (2)
    // scalaCompileOptions.useAnt = true
}
サンプルソース Sample.scala
package fits.sample

import scala.language.postfixOps

import scalaz._
import Scalaz._

object Sample extends App {

    val plus3: Int => Int = 3 +
    val times: Int => Int = 2 *

    // 2 * (3 + 4) = 14
    println( 4 |> plus3 >>> times )

    // (3 + 4, 2 * 5) = (7, 10)
    println( (4, 5) |> plus3 *** times )

    // (3 + 5, 2 * 5) = (8, 10)
    println( 5 |> plus3 &&& times )
}

(1) useAnt = false の場合

useAnt を false に変更した場合の gradle build 結果は下記の通りです。
(-Xprint:typer の内容が出力されます)

実行結果
> gralde build

:compileJava UP-TO-DATE
:compileScala
[[syntax trees at end of                     typer]] // Sample.scala
package fits.sample {
  import scala.language.postfixOps;
  import scalaz._;
  import scalaz.Scalaz._;
  object Sample extends AnyRef with App {
    def <init>(): fits.sample.Sample.type = {
      Sample.super.<init>();
      ()
    };
    private[this] val plus3: Int => Int = {
      ((x: Int) => 3.+(x))
    };
    <stable> <accessor> def plus3: Int => Int = Sample.this.plus3;
    private[this] val times: Int => Int = {
      ((x: Int) => 2.*(x))
    };
    <stable> <accessor> def times: Int => Int = Sample.this.times;
    scala.this.Predef.println(scalaz.Scalaz.ToIdOps[Int](4).|>[Int](scalaz.Scalaz.ToComposeOps[Function1, Int, Int](Sample.this.plus3)(scalaz.Scalaz.function1Instance).>>>[Int](Sample.this.times)));
    scala.this.Predef.println(scalaz.Scalaz.ToIdOps[(Int, Int)](scala.Tuple2.apply[Int, Int](4, 5)).|>[(Int, Int)](scalaz.Scalaz.ToArrowOps[Function1, Int, Int](Sample.this.plus3)(scalaz.Scalaz.function1Instance).***[Int, Int](Sample.this.times)));
    scala.this.Predef.println(scalaz.Scalaz.ToIdOps[Int](5).|>[(Int, Int)](scalaz.Scalaz.ToArrowOps[Function1, Int, Int](Sample.this.plus3)(scalaz.Scalaz.function1Instance).&&&[Int](Sample.this.times)))
  }
}

:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestScala UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

(2) useAnt = true の場合

useAnt が true (デフォルト値) の場合の gradle build 結果は下記の通りです。
(-Xprint:typer の内容は出力されません)

実行結果1
> gralde build

:compileJava UP-TO-DATE
:compileScala
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava UP-TO-DATE
:compileTestScala UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check UP-TO-DATE
:build

BUILD SUCCESSFUL

ここで gradle build -i と実行すれば -Xprint:typer の内容が出力されます。

実行結果2
> gralde build -i

・・・
[ant:scalac] [[syntax trees at end of                     typer]] // Sample.scala
[ant:scalac] package fits.sample {

[ant:scalac]   import scala.language.postfixOps;

[ant:scalac]   import scalaz._;

[ant:scalac]   import scalaz.Scalaz._;

[ant:scalac]   object Sample extends AnyRef with App {

[ant:scalac]     def <init>(): fits.sample.Sample.type = {

[ant:scalac]       Sample.super.<init>();

[ant:scalac]       ()

[ant:scalac]     };

[ant:scalac]     private[this] val plus3: Int => Int = {

[ant:scalac]       ((x: Int) => 3.+(x))

[ant:scalac]     };

[ant:scalac]     <stable> <accessor> def plus3: Int => Int = Sample.this.plus3;

[ant:scalac]     private[this] val times: Int => Int = {

[ant:scalac]       ((x: Int) => 2.*(x))

[ant:scalac]     };

[ant:scalac]     <stable> <accessor> def times: Int => Int = Sample.this.times;

[ant:scalac]     scala.this.Predef.println(scalaz.Scalaz.ToIdOps[Int](4).|>[Int](scalaz.Scalaz.ToComposeOps[Function1, Int, Int](Sample.this.plus3)(scalaz.Scalaz.function1Instance).>>>[Int](Sample.this.times)));

[ant:scalac]     scala.this.Predef.println(scalaz.Scalaz.ToIdOps[(Int, Int)](scala.Tuple2.apply[Int, Int](4, 5)).|>[(Int, Int)](scalaz.Scalaz.ToArrowOps[Function1, Int, Int](Sample.this.plus3)(scalaz.Scalaz.function1Instance).***[Int, Int](Sample.this.times)));

[ant:scalac]     scala.this.Predef.println(scalaz.Scalaz.ToIdOps[Int](5).|>[(Int, Int)](scalaz.Scalaz.ToArrowOps[Function1, Int, Int](Sample.this.plus3)(scalaz.Scalaz.function1Instance).&&&[Int](Sample.this.times)))

[ant:scalac]   }

[ant:scalac] }
[ant:scalac] 
:compileScala (Thread[main,5,main]) - complete
・・・