Date post: | 13-Jan-2015 |
Category: |
Technology |
Upload: | junji-uehara |
View: | 3,217 times |
Download: | 0 times |
JJUG CCC 2009 Fall
Groovyの現在と未来~変容する言語~
2009/10/08
NTTソフトウェア株式会社 上原潤二
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
はじめに
2
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
自己紹介• 上原潤二
• NTTソフトウェア株式会社• JGGUG運営委員• ブログ“Grな日々”
• “Grails徹底入門”2章執筆• JavaWorld記事執筆• Twitter: uehaj
3
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
本日の内容• Groovyの紹介• Groovyの歴史• Groovyの今•進化するGroovy
• 人それぞれのGroovy
• 変形するGroovy• 力強く表明するGroovy
•まとめ4
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
Groovyの紹介なぜGroovyか
5
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
Groovyとはッ!
6
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!
6
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!
6
• JavaVM上で動作ッ
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
Groovyとはッ!• Java使いの「傍らに立つ(Stand by me)」言語なのだッ!!!
6
• JavaVM上で動作ッ• Javaクラス(バイトコード)を実行時コンパイル生成、ラッパー無しで相互連携
2009年10月10日土曜日
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日土曜日
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日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
JVM上の他言語との比較• ScalaやJRuby
• 新規コードはScalaやRubyで書くのが正しい• コレクションや基本型は独自のものが基本、レガシー資産としてJava API/ライブラリも呼べる
• 要は別言語
• Groovyは• Javaと併用する、バイトコード生成のための拡張書式• コレクションや基本型はJavaのものをシェア• Mavenとかと同様の、Java周辺ツールの一つ
7
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
Groovyの特徴的な機能•標準Java APIの拡張「GDK」
Javaクラスに透過的に機能を追加する機構を持つ
•簡潔記述のための様々な機能• クロージャ,マップ/リストリテラル,etc
•動的言語•記法のカスタマイズ機能(DSL)8
2009年10月10日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
HTTPに限ればprintln new URL("http://www.java-users.jp").text
12
2009年10月10日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
短さの意味• 短かいことが本質ではない
• 短くて分かりにくくなることもある• ポイントは「やりたい事(what)/コード量」のSN比
• 「書きたいように書ける」を達成するための1ファクターでしかない
• 書きたいこと以外の雑事によって、わずらわされない事が重要
13
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
使い分けが肝要•万能言語は無い
• 万能を目指すと「言語力(げんごぢから)」は低下する(Algol, Common Lisp, Ada, C++…)
用途と特性に応じて言語を使い分け、組み合わせる(Polyglot Programing)
• Groovyの使いどころ既存Javaライブラリやフレームワーク機能の「呼び出し側」の記述一般ユーザより、ビジネスロジックよりの部分
14
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
Groovyの歴史その来歴
15
2009年10月10日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
黒歴史?• 2004年のころの性能や機能で悪印象を持ってる人が多い?
• SyntaxErrorがStacktrace!
• プロジェクトリード交代をへて、現在では十分な安定性・性能を誇る• キラーフレームワークGrailsでは商用実績多• JRubyと同様の最適化
17
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
Groovyの進化1.6以降の新機能について
18
2009年10月10日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
人それぞれのGroovyインスタンスごとのメタクラス
20
2009年10月10日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
変形するGroovy(1 of 3) AST変換について
22
transform
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
AST変換とは• Groovyプログラムを表す中間データ構造
(AST、抽象構文木)を変換する処理• Groovyコンパイラの処理の一部をカスタマイズできる
• 標準AST変換に加え、ユーザ定義のAST変換を組み込み可能。「コンパイラのプラグイン」
aka コンパイル時メタプログラミング23
transformation
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
AST変換処理
24
字句解析部(Antlr)
構文解析部(Antlr)
コード生成部(ASM)
a=a+a
Groovyソースコード
0xCAFEBABE........
Javaバイトコード
2009年10月10日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
ローカル&グローバル•ローカルAST変換•マーカーアノテーションの指定をきっかけとしてAST変換を実行する
•大域AST変換•マーカーアノテーション不要。コードすべてに作用できる。
25
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
AST変換その他トピック•コンパイル時に作用するので、変換処理は実行速度に影響を与えない• 「groovyc」するとAST変換後のバイトコードが得られる• groovyコマンドでの実行時コンパイルの場合は、ロード時間に影響がある
•リフレクションでとれない情報も扱えるGroovyの構文規則は破れない
26
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
変形するGroovy(2 of 3) 標準のAST変換について
27
transform
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
標準AST変換(グローバル)機能 説明
Grape(@Grab)依存JARの芋づる式自動ダウンロード(Apache Ivyベース)
Power AssertAssert失敗時に式を構成する部分式の値を表示する
ASTBuilderAST変換をGroovyで書くときに使用できる「コードからASTを生成」
28
2009年10月10日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
変形するGroovy(3 of 3) AST変換を定義する
39
transform
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
AST変換(ローカル)の定義方法•「AST変換クラス」を定義する•「マーカーアノテーションクラス」を定義する(対応するAST変換クラスを指定)
•両者をコンパイルしクラスパスにいずれもGroovyで書ける
40
2009年10月10日土曜日
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日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
作るもの:ソース情報取得•シンボル_FILE_, _LINE_, _CLASS_, _METHOD_を、処理中のソースコード情報に置き換えるAST変換•log("$_FILE_:$_LINE_:$_CLASS_:$_METHOD_ ", ..)
43
2009年10月10日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
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日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
AST変換の開発支援(1)•groovyConsoleのASTビューワ
49
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
AST変換の開発支援(2)•ASTBuilder• buildFromSpec … AST生成用のDSL
• buildFromString … 文字列をパースしてASTを作る
• buildFromCode … 実コード断片(クロージャ)からAST取得
50
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
AST変換について感想•言語拡張の敷居が相対的に下がった
• コンパイラを改造するよりはるかに簡単• 誰でもというものではない
• 拡張機能を容易に配布できる
• Scalaとの相互運用の@Scalifyなど、今後の発展が期待される。
51
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
まとめ
52
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
まとめ• GroovyはJavaと組み合わせて使うツール•高い自由度と拡張性•今回紹介できなかった特徴:
• DSL、メタプログラミング、正規表現、コレクション処理・・
• 関連ツール群・ライブラリ群
•いますぐにでも実用的53
2009年10月10日土曜日
Slide# JJUG CCC 2009 Fall / 2009.10.08
コミュニティもよろしく!
54
•http://www.jggug.org/
2009年10月10日土曜日
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日土曜日