+ All Categories
Home > Technology > Groovy, Transforming Language

Groovy, Transforming Language

Date post: 13-Jan-2015
Category:
Upload: junji-uehara
View: 3,217 times
Download: 0 times
Share this document with a friend
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.
Popular Tags:
71
JJUG CCC 2009 Fall Groovyの 現在と未来 ~変容する言語~ 2009/10/08 NTTソフトウェア株式会社 上原潤二 20091010日土曜日
Transcript
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日土曜日


Recommended