71
JJUG CCC 2009 Fall Groovyの 現在と未来 ~変容する言語~ 2009/10/08 NTTソフトウェア株式会社 上原潤二 20091010日土曜日

Groovy, Transforming Language

Embed Size (px)

DESCRIPTION

Slides for JJUG(Japan Java User Group) 2009 Fall BOF. Talking about groovy history, new features in Groovy 1.6,1.7. Especially focused on AST Transformations.

Citation preview

Page 1: Groovy, Transforming Language

JJUG CCC 2009 Fall

Groovyの現在と未来~変容する言語~

2009/10/08

NTTソフトウェア株式会社 上原潤二

2009年10月10日土曜日

Page 2: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

はじめに

2

2009年10月10日土曜日

Page 3: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

自己紹介• 上原潤二

• NTTソフトウェア株式会社• JGGUG運営委員• ブログ“Grな日々”

• “Grails徹底入門”2章執筆• JavaWorld記事執筆• Twitter: uehaj

3

2009年10月10日土曜日

Page 4: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

本日の内容• Groovyの紹介• Groovyの歴史• Groovyの今•進化するGroovy

• 人それぞれのGroovy

• 変形するGroovy• 力強く表明するGroovy

•まとめ4

2009年10月10日土曜日

Page 5: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyの紹介なぜGroovyか

5

2009年10月10日土曜日

Page 6: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyとはッ!

6

2009年10月10日土曜日

Page 7: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!

6

2009年10月10日土曜日

Page 8: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!

6

• JavaVM上で動作ッ

2009年10月10日土曜日

Page 9: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!

6

• JavaVM上で動作ッ• Javaクラス(バイトコード)を実行時コンパイル生成、ラッパー無しで相互連携

2009年10月10日土曜日

Page 10: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!

6

• JavaVM上で動作ッ• Javaクラス(バイトコード)を実行時コンパイル生成、ラッパー無しで相互連携

• 文法はJavaのほぼ上位互換ッ• annotation/enum/generics/vararg/static import/内部クラス

2009年10月10日土曜日

Page 11: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!

6

• JavaVM上で動作ッ• Javaクラス(バイトコード)を実行時コンパイル生成、ラッパー無しで相互連携

• 文法はJavaのほぼ上位互換ッ• annotation/enum/generics/vararg/static import/内部クラス

• 例えるならッ!JSPみたいなもの

2009年10月10日土曜日

Page 12: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!

6

ポイント:(Javaに)馴染む、馴染むぞォォ!

• JavaVM上で動作ッ• Javaクラス(バイトコード)を実行時コンパイル生成、ラッパー無しで相互連携

• 文法はJavaのほぼ上位互換ッ• annotation/enum/generics/vararg/static import/内部クラス

• 例えるならッ!JSPみたいなもの

2009年10月10日土曜日

Page 13: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

JVM上の他言語との比較• ScalaやJRuby

• 新規コードはScalaやRubyで書くのが正しい• コレクションや基本型は独自のものが基本、レガシー資産としてJava API/ライブラリも呼べる

• 要は別言語

• Groovyは• Javaと併用する、バイトコード生成のための拡張書式• コレクションや基本型はJavaのものをシェア• Mavenとかと同様の、Java周辺ツールの一つ

7

2009年10月10日土曜日

Page 14: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyの特徴的な機能•標準Java APIの拡張「GDK」

Javaクラスに透過的に機能を追加する機構を持つ

•簡潔記述のための様々な機能• クロージャ,マップ/リストリテラル,etc

•動的言語•記法のカスタマイズ機能(DSL)8

2009年10月10日土曜日

Page 15: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

コード例: Javaimport java.io.*;import java.net.*;

public class SocketAccess {

public static void main(String[] args) { Socket soc = null; InputStream ins = null; OutputStream outs = null; try { soc = new Socket("www.java-users.jp", 80); ins = soc.getInputStream(); outs = soc.getOutputStream(); outs.write("GET / HTTP/1.0\n\n".getBytes()); BufferedReader bis = new BufferedReader(new InputStreamReader(ins));

String line; while ((line = bis.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); try { if (soc != null) soc.close(); } catch(IOException ex) {} } }}

9

2009年10月10日土曜日

Page 16: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

コード例: Groovy!import java.io.*; import java.net.*;

public class SocketAccess {

public static void main(String[] args) { Socket soc = null; InputStream ins = null; OutputStream outs = null; try { soc = new Socket("www.java-users.jp", 80); ins = soc.getInputStream(); outs = soc.getOutputStream(); outs.write("GET / HTTP/1.0\n\n".getBytes()); BufferedReader bis = new BufferedReader(new InputStreamReader(ins));

String line; while ((line = bis.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); try { if (soc != null) soc.close(); } catch(IOException ex) {} } }}

10

2009年10月10日土曜日

Page 17: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

コード例: Groovy!import java.io.*; import java.net.*;

public class SocketAccess {

public static void main(String[] args) { Socket soc = null; InputStream ins = null; OutputStream outs = null; try { soc = new Socket("www.java-users.jp", 80); ins = soc.getInputStream(); outs = soc.getOutputStream(); outs.write("GET / HTTP/1.0\n\n".getBytes()); BufferedReader bis = new BufferedReader(new InputStreamReader(ins));

String line; while ((line = bis.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); try { if (soc != null) soc.close(); } catch(IOException ex) {} } }}

10

ポイント: 正しいJavaコードは一般に正しいGroovyコードでもある(例外もある)

2009年10月10日土曜日

Page 18: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

よりGroovyなコードnew Socket("www.java-users.jp", 80).withStreams { ins, outs ->  outs.write("GET / HTTP/1.0\n\n".bytes)  ins.eachLine {    println it  }}

11

2009年10月10日土曜日

Page 19: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

ポイント: java.net.Socketクラスやjava.io.*Streamクラスに自動closeなどの便利機能が追加されたメソッド(eachLine, withStreams)が追加されている(GDK)。

(eachLine,withStreams)

よりGroovyなコードnew Socket("www.java-users.jp", 80).withStreams { ins, outs ->  outs.write("GET / HTTP/1.0\n\n".bytes)  ins.eachLine {    println it  }}

11

2009年10月10日土曜日

Page 20: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

ポイント: java.net.Socketクラスやjava.io.*Streamクラスに自動closeなどの便利機能が追加されたメソッド(eachLine, withStreams)が追加されている(GDK)。

(eachLine,withStreams)

ポイント:プロパティアクセス記法(.bytes)はgetter(getBytes())を呼び出す(.bytes)

よりGroovyなコードnew Socket("www.java-users.jp", 80).withStreams { ins, outs ->  outs.write("GET / HTTP/1.0\n\n".bytes)  ins.eachLine {    println it  }}

11

2009年10月10日土曜日

Page 21: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

ポイント: java.net.Socketクラスやjava.io.*Streamクラスに自動closeなどの便利機能が追加されたメソッド(eachLine, withStreams)が追加されている(GDK)。

(eachLine,withStreams)

ポイント:プロパティアクセス記法(.bytes)はgetter(getBytes())を呼び出す(.bytes)

よりGroovyなコードnew Socket("www.java-users.jp", 80).withStreams { ins, outs ->  outs.write("GET / HTTP/1.0\n\n".bytes)  ins.eachLine {    println it  }}

11

ポイント: 特定のimport文、クラス定義、セミコロンなど多くを省略可

2009年10月10日土曜日

Page 22: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

HTTPに限ればprintln new URL("http://www.java-users.jp").text

12

2009年10月10日土曜日

Page 23: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

HTTPに限ればprintln new URL("http://www.java-users.jp").text

12

JavaからGroovyに書き直すと、大抵数分の1程度にはなる。

マップリテラル、リストリテラルなどもコードが短くなる要因として良く示されるが、Java 7で採用されるので割愛。

2009年10月10日土曜日

Page 24: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

短さの意味• 短かいことが本質ではない

• 短くて分かりにくくなることもある• ポイントは「やりたい事(what)/コード量」のSN比

• 「書きたいように書ける」を達成するための1ファクターでしかない

• 書きたいこと以外の雑事によって、わずらわされない事が重要

13

2009年10月10日土曜日

Page 25: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

使い分けが肝要•万能言語は無い

• 万能を目指すと「言語力(げんごぢから)」は低下する(Algol, Common Lisp, Ada, C++…)

用途と特性に応じて言語を使い分け、組み合わせる(Polyglot Programing)

• Groovyの使いどころ既存Javaライブラリやフレームワーク機能の「呼び出し側」の記述一般ユーザより、ビジネスロジックよりの部分

14

2009年10月10日土曜日

Page 26: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyの歴史その来歴

15

2009年10月10日土曜日

Page 27: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovy年表

16

2003 2004 2005

12月▲

1.5.0

2月▲

1.5.4

2月▲1.0

4月▲

1.1b2

8月 3月▲

1.0b4JSR化

2月▲

1.0b10JSR版EA

7月▲

1.0 JSR-6

12月▲1.5.71.6-rc1

2006 2007 2008 20098月▲1.6.41.7-b1Grails

0.5.6Grails

0.3

黎明期

復活期雌伏期

暗黒期初期注目

再発展期

2009年10月10日土曜日

Page 28: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

黒歴史?• 2004年のころの性能や機能で悪印象を持ってる人が多い?

• SyntaxErrorがStacktrace!

• プロジェクトリード交代をへて、現在では十分な安定性・性能を誇る• キラーフレームワークGrailsでは商用実績多• JRubyと同様の最適化

17

2009年10月10日土曜日

Page 29: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyの進化1.6以降の新機能について

18

2009年10月10日土曜日

Page 30: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

Groovyの比較的新機能•インスタンス毎のメタクラス

(1.6~)

•Grape(1.6~)

•AST変換(1.6~)

•Power Assert(1.7~)

19

2009年10月10日土曜日

Page 31: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

人それぞれのGroovyインスタンスごとのメタクラス

20

2009年10月10日土曜日

Page 32: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

POJOインスタンスにメソッドを追加

21

'ls'.metaClass.exec = { new File(".").eachFile{println it} }'pwd'.metaClass.exec = { println new File(".").absolutePath }'env'.metaClass.exec = { System.getenv().each{k,v->println "$k=$v" }}

System.in.eachLine {  it.intern().exec()}

ポイント: intern()で一意化。

ポイント: 利点はクラス定義と分岐の削減によるコード簡素化。

2009年10月10日土曜日

Page 33: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

変形するGroovy(1 of 3) AST変換について

22

transform

2009年10月10日土曜日

Page 34: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換とは• Groovyプログラムを表す中間データ構造

(AST、抽象構文木)を変換する処理• Groovyコンパイラの処理の一部をカスタマイズできる

• 標準AST変換に加え、ユーザ定義のAST変換を組み込み可能。「コンパイラのプラグイン」

aka コンパイル時メタプログラミング23

transformation

2009年10月10日土曜日

Page 35: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換処理

24

字句解析部(Antlr)

構文解析部(Antlr)

コード生成部(ASM)

a=a+a

Groovyソースコード

0xCAFEBABE........

Javaバイトコード

2009年10月10日土曜日

Page 36: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換処理

24

字句解析部(Antlr)

構文解析部(Antlr)

コード生成部(ASM)

a=a+a

Groovyソースコード

=

+a

1a

= +a 1a

トークン列 AST

0xCAFEBABE........

Javaバイトコード

2009年10月10日土曜日

Page 37: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換処理

24

字句解析部(Antlr)

構文解析部(Antlr)

コード生成部(ASM)

a=a+a

Groovyソースコード

=

+a

1a

= +a 1a

トークン列 AST

0xCAFEBABE........

Javaバイトコード

AST変換

2009年10月10日土曜日

Page 38: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換処理

24

字句解析部(Antlr)

構文解析部(Antlr)

コード生成部(ASM)

a=a+a

Groovyソースコード

=

+a

1a

= +a 1a

トークン列 AST

0xCAFEBABE........

Javaバイトコード

AST変換AST変換

2009年10月10日土曜日

Page 39: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換処理

24

字句解析部(Antlr)

構文解析部(Antlr)

コード生成部(ASM)

a=a+a

Groovyソースコード

=

+a

1a

= +a 1a

トークン列 AST

0xCAFEBABE........

Javaバイトコード

AST変換AST変換AST変換

2009年10月10日土曜日

Page 40: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換処理

24

字句解析部(Antlr)

構文解析部(Antlr)

コード生成部(ASM)

a=a+a

Groovyソースコード

=

+a

1a

= +a 1a

トークン列 AST

0xCAFEBABE........

Javaバイトコード

AST変換ポイント: コンパイラの各フェイズごとに登録したAST変換が実行される。

AST変換AST変換

2009年10月10日土曜日

Page 41: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

ローカル&グローバル•ローカルAST変換•マーカーアノテーションの指定をきっかけとしてAST変換を実行する

•大域AST変換•マーカーアノテーション不要。コードすべてに作用できる。

25

2009年10月10日土曜日

Page 42: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換その他トピック•コンパイル時に作用するので、変換処理は実行速度に影響を与えない• 「groovyc」するとAST変換後のバイトコードが得られる• groovyコマンドでの実行時コンパイルの場合は、ロード時間に影響がある

•リフレクションでとれない情報も扱えるGroovyの構文規則は破れない

26

2009年10月10日土曜日

Page 43: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

変形するGroovy(2 of 3) 標準のAST変換について

27

transform

2009年10月10日土曜日

Page 44: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

標準AST変換(グローバル)機能 説明

Grape(@Grab)依存JARの芋づる式自動ダウンロード(Apache Ivyベース)

Power AssertAssert失敗時に式を構成する部分式の値を表示する

ASTBuilderAST変換をGroovyで書くときに使用できる「コードからASTを生成」

28

2009年10月10日土曜日

Page 45: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: @Grab@Grab('org.mortbay.jetty:jetty-embedded:6.1.0')import org.mortbay.jetty.Serverimport org.mortbay.jetty.servlet.*import groovy.servlet.*

def server = new Server(8080)def context = new Context(server, "/", Context.SESSIONS)context.resourceBase = "."context.addServlet(TemplateServlet, "*.gsp")server.start()

29

ポイント: スクリプト配布が非常に容易に

• あらかじめjettyのJarをインストールしておく必要が無い• 初回実行時に、Mavenリポジトリから依存Jarを含め‾/.groovy/

grapesあたりに取ってくる。

2009年10月10日土曜日

Page 46: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: Power Assert

•assertのFAIL時メッセージがわかりやすくなる

30

a = 4assert 1+Math.max(3,a)*5==3==>EXCEPTION:Assertion failed:

assert 1+Math.max(3,a)*5==3 | | | | | 21 4 4 | false 25

ポイント: assertのバリエーションのいくつかが不要になる

2009年10月10日土曜日

Page 47: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

標準AST変換(ローカル)アノテーション 説明

@Bindable /@Vetoable

Swingで使用するプロパティの更新伝播(java.beans. PropertyChangeSupport使用)

@Singleton クラスをシングルトンに変換@Immutable インスタンス生成後の変更を禁止@Delegate 委譲パターン@Lazy フィールド初期値設定を初回評価時に遅延

@Category クラス定義と同形のカテゴリ定義@Mixin 指定クラス実装をmixin

@Newify Python/Rubyライクなnew(例: Integer(5), Integer.new(5))

@PackageScope packageスコープの指定。31 太字を本スライドで説明

2009年10月10日土曜日

Page 48: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: @Singleton

@Singletonclass Foo {  def hello() { println "hello" }}Foo.instance.hello()  // シングルトン参照a = new Foo()  // newでインスタンス生成不可==>EXCEPTION:java.lang.RuntimeException: Can't instantiate singleton Foo. Use Foo.instance at Foo.<init>(Script1.groovy) at Script1.run(Script1.groovy:6)

32

•唯一のインスタンスを生成/保証

2009年10月10日土曜日

Page 49: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: @Immutable

@Immutablefinal class Foo {  String x, y}a  = new Foo(x:"a",y:"b")a.x = "hoge"  // 変更を試みる

==>EXCEPTION:groovy.lang.ReadOnlyPropertyException: Cannot set readonly property: x for class: Foo at Foo.setProperty(Script1.groovy) at Script1.run(Script1.groovy:6)

33

•変更不可クラス

2009年10月10日土曜日

Page 50: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: @Delegateimport java.util.concurrent.locks.*class LockableMap {  @Delegate private Map map = [:]  @Delegate private Lock lock = new ReentrantLock ()}res = new LockableMap()res.lock() // Lockとして振舞うtry {  res.a = 0 // Mapとしても振舞う} finally {  res.unlock ()}assert res instanceof Mapassert res instanceof Lock

34

ポイント: 別オブジェクトの機能を取り込むが、参照経由の別インスタンス。

•委譲/Proxyパターン

http://www.infoq.com/jp/articles/groovy-1-6 を参考に作成2009年10月10日土曜日

Page 51: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: @Lazyclass LazyTest {  @Lazy List s1 ={println "s1 initializing"; [1,2,3] }();  List  s2 = {println "s2 initializing"; [4,5,6] }();}

x = new LazyTest()// s2 initializing が出力される。println x.s1       // s1の初回参照// s1 initializing が出力される。// [1, 2, 3]が出力されるprintln x.s2// [4, 5, 6]が出力されるprintln x.s1// [1, 2, 3]が出力される。

35

•フィールド初期化を初回参照時まで遅延

2009年10月10日土曜日

Page 52: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: @Category@Category(String)class TrMethod {  String tr(from,to) {    def result = this    from.eachWithIndex{it,idx->      result = result.replaceAll(it, to.getAt(idx))    }    result  }}use (TrMethod) {  assert 'abcdefおえい123'.tr('abcあいうえお','XYZアイウエオ') == 'XYZdefオエイ123'}

36

• useで使うカテゴリの定義

2009年10月10日土曜日

Page 53: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: @Mixinclass Dumpable {  void dump() { this.metaClass.methods.each{  println it.name }    this.metaClass.properties.each {  println it.name }  }}

@Mixin(Dumpable)class MyClass {  int field  void foo() {}  int bar(String i) {}}

x = new MyClass()x.dump()==>toStringdumpget__timeStamp__239_neverHappen1254628920761set__timeStamp__239_neverHappen1254628920761equalsgetClass :barfoofield

37

•別クラスの機能を取り込む

2009年10月10日土曜日

Page 54: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換: @Newifyclass Test {

  @Newify(String) // Python風の場合、型の明示指定が必要  static test() {    def s0 = new String("hoge") // Groovy/Java標準    def s1 = String("hoge")  // Python風    def s2 = String.new("hoge")  // Ruby風  }}

38

ポイント:Python風の場合、ツリーの生成が特に簡潔になる。(例: Mul(Add(1,2),Div(3, 2)) )

• Python/Ruby風のnew

2009年10月10日土曜日

Page 55: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

変形するGroovy(3 of 3) AST変換を定義する

39

transform

2009年10月10日土曜日

Page 56: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換(ローカル)の定義方法•「AST変換クラス」を定義する•「マーカーアノテーションクラス」を定義する(対応するAST変換クラスを指定)

•両者をコンパイルしクラスパスにいずれもGroovyで書ける

40

2009年10月10日土曜日

Page 57: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換(グローバル)の定義方法• 「AST変換クラス」を定義する• コンパイルしてクラスパスに置く• 以下の設定ファイルにAST変換クラス名を指定• META-INF/services/org.codehaus.groovy.transform.ASTTransformation

• Groovy自体の再ビルド(JARアーカイブ生成)

41

2009年10月10日土曜日

Page 58: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換クラス• インターフェースASTTransformationを継承

• 以下のメソッドを定義• void visit(ASTNode[] nodes,

SourceUnit source)

• SourceUnit getSourceUnit()

• visit()でASTに対する処理を行うVisitorパターン

42

2009年10月10日土曜日

Page 59: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

作るもの:ソース情報取得•シンボル_FILE_, _LINE_, _CLASS_, _METHOD_を、処理中のソースコード情報に置き換えるAST変換•log("$_FILE_:$_LINE_:$_CLASS_:$_METHOD_ ", ..)

43

2009年10月10日土曜日

Page 60: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

マーカーアノテーションpackage org.jggug.transformimport org.codehaus.groovy.transform.GroovyASTTransformationClass;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import java.lang.annotation.ElementType;

@Retention(RetentionPolicy.SOURCE)@Target([ElementType.TYPE])@GroovyASTTransformationClass("org.jggug.transform.UseSourceInfoSymbolASTTransformation")public @interface UseSourceInfoSymbol {}

44

AST変換クラス名マーカーアノテーション

2009年10月10日土曜日

Page 61: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換クラス(1 of 2)package org.jggug.transform

import org.codehaus.groovy.ast.*;import org.codehaus.groovy.ast.expr.*;import org.codehaus.groovy.ast.stmt.Statement;import org.codehaus.groovy.control.CompilePhase;import org.codehaus.groovy.control.SourceUnit;import org.codehaus.groovy.transform.ASTTransformation;import org.codehaus.groovy.transform.GroovyASTTransformation;

@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)public class UseSourceInfoSymbolASTTransformation extends ClassCodeExpressionTransformer implements ASTTransformation {  private SourceUnit sourceUnit;  SourceUnit getSourceUnit() {    return sourceUnit;  }  String visitingMethod = null  String visitingClass = null

  void visit(ASTNode[] nodes, SourceUnit source) {    sourceUnit = source;    def parent = nodes[1]    visitingClass = parent.name    super.visitClass(parent)  }

  void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {    visitingMethod = node.name    super.visitConstructorOrMethod(node, isConstructor)  }(次のページに続く)

45

ポイント: 用意されたVisitorやTransformerを使って木を処理する。

2009年10月10日土曜日

Page 62: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換クラス(2 of 2)  Expression transform(Expression exp) {    if (exp == null) return null;    switch (exp.class) {    case VariableExpression.class:      switch (exp.name) {        case '_FILE_': return new ConstantExpression(sourceUnit.name)        case '_LINE_': return new ConstantExpression(exp.lineNumber)        case '_COLUMN_': return new ConstantExpression(exp.columnNumber)        case '_CLASS_': return new ConstantExpression(visitingClass)        case '_METHOD_': return new ConstantExpression(visitingMethod)        default: return exp      }    case MethodCallExpression.class:      def args = transform(exp.arguments);      def method = transform(exp.method);      def object = transform(exp.objectExpression);      return new MethodCallExpression(object, method, args);    case ClosureExpression.class:      Statement code = exp.code;      if (code == null) return exp      return code.visit(this)    case ConstructorCallExpression.class:      return exp.transformExpression(this)    default:      return exp.transformExpression(this)    }  }} 46

ポイント: 木の端っこの方は明示的にたどる(効率のためか、全自動ではない)

実際の変換

2009年10月10日土曜日

Page 63: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

実行例import org.jggug.transform.UseSourceInfoSymbol

@UseSourceInfoSymbolclass Test {  def foo(hoge, fuga) {    println _FILE_+':'+_LINE_    println _FILE_+':'+_LINE_    println _FILE_+':'+_LINE_    println _FILE_+':'+_LINE_    println _FILE_+':'+_LINE_    println _CLASS_+':'+_METHOD_  }}

test = new Test()test.foo(1,2)

47

==>/tmp/test02.groovy:6/tmp/test02.groovy:7/tmp/test02.groovy:8/tmp/test02.groovy:9/tmp/test02.groovy:10sample.Test:foo

2009年10月10日土曜日

Page 64: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

その他,作ってみたAST変換•$b

48

機能 説明

@UseBinaryLiteral

二進数リテラル(Java 7で採用予定機能)println $b01_001_0001==> 145

@WithTimeoutタイムアウト指定をすぎると例外発生@WithTimeout(3) def work() { ....... }

@Define

シンボルの置換@Define(symbol="that", value="delegate")@Define(symbol="それ", value="it")@Define(symbol="これ", value="this")@Define(symbol="表示", value="println")

2009年10月10日土曜日

Page 65: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換の開発支援(1)•groovyConsoleのASTビューワ

49

2009年10月10日土曜日

Page 66: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換の開発支援(2)•ASTBuilder• buildFromSpec … AST生成用のDSL

• buildFromString … 文字列をパースしてASTを作る

• buildFromCode … 実コード断片(クロージャ)からAST取得

50

2009年10月10日土曜日

Page 67: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

AST変換について感想•言語拡張の敷居が相対的に下がった

• コンパイラを改造するよりはるかに簡単• 誰でもというものではない

• 拡張機能を容易に配布できる

• Scalaとの相互運用の@Scalifyなど、今後の発展が期待される。

51

2009年10月10日土曜日

Page 68: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

まとめ

52

2009年10月10日土曜日

Page 69: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

まとめ• GroovyはJavaと組み合わせて使うツール•高い自由度と拡張性•今回紹介できなかった特徴:

• DSL、メタプログラミング、正規表現、コレクション処理・・

• 関連ツール群・ライブラリ群

•いますぐにでも実用的53

2009年10月10日土曜日

Page 70: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

コミュニティもよろしく!

54

•http://www.jggug.org/

2009年10月10日土曜日

Page 71: Groovy, Transforming Language

Slide# JJUG CCC 2009 Fall / 2009.10.08

参考リンク・文献• http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST

+TransformationsCompile-time Metaprogramming - AST Transformations

• http://groovy.codehaus.org/AST+Macros+and+AnnotationsAST Macros and Annotations

• http://groovy.codehaus.org/Building+AST+GuideBuilding AST in Groovy 1.6 and Prior

• http://kartik-shah.blogspot.com/2009/03/groovy-16-ast-transformation-example_5323.htmlGroovy 1.6 AST Transformation Example

• http://www.infoq.com/jp/articles/groovy-1-6Groovy 1.6で注目の新機能 - Groovyの開発リーダーによる解説

• http://www.slideshare.net/paulk_asert/groovy-testing-aug2009-1945995Groovy Testing Sep2009

• http://dl.getdropbox.com/u/132573/groovy_scala/index.htmlGroovyとScala: 二つのJVM言語の物語

• プロダクティブ・プログラマ

55

2009年10月10日土曜日