AST変換のネタを考えてみた。こんな題材:
クラス定義をせずに記述したスクリプトにおいて print/println 文の出力内容をテキストエリアなどの GUI 部品に表示する。ただし、もとのスクリプトには、GUI 部品の記述は一切なしで。
これ、意外と使えると思うんだけどな。。。
以下、やろうとしていることをサンプルコードで示してみる。
(1) AST変換前のスクリプト:
// fib.groovy int fib (int x) { (x<2)?x:(fib(x-2)+fib(x-1)) } println ((0..10).collect{fib(it)}.join(" "))
これをCONVERSIONフェーズまでコンパイルすると、つぎのような AST に対応するコードになるはず。
(2) CONVERSION後の AST に対応するコード
// fib.groovy (疑似コード) class fib extends groovy.lang.Script { public fib() { } public fib(groovy.lang.Binding context) { super(context) } public static void main(java.lang.String[] args) { org.codehaus.groovy.runtime.InvokerHelper.runScript(fib, args) } public int fib (int x) { (x<2)?x:(fib(x-2)+fib(x-1)) } public Object run () { println ((0..10).collect{fib(it)}.join(" ")) } }
で、次のように書き換えてやればいいはず。
(3)AST変換後のスクリプト
// fib.groovy (AST変換後の疑似コード) class fib extends groovy.lang.Script { public fib() { } public fib(groovy.lang.Binding context) { super(context) } public static void main(java.lang.String[] args) { org.codehaus.groovy.runtime.InvokerHelper.runScript(fib, args) } // テキストエリアオブジェクトの変数 private static javax.swing.JTextArea ta=null // テキストエリアに出力するprintメソッド public static void print (java.lang.Object x) { if (ta == null) { openWindow("console") } ta.setText(ta.getText() + x.toString()) ta.setCaretPosition(ta.getText().length()) } // テキストエリアに出力するprintlnメソッド public static void println (java.lang.Object x) { print (x.toString() + "\n") } // テキストエリアのウィンドウフレームを開くメソッド private static void openWindow (String title) { javax.swing.JFrame f = new javax.swing.JFrame(title) f.setSize(800, 600) f.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE) ta = new javax.swing.JTextArea(100,50) ta.setForeground(java.awt.Color.white) ta.setBackground(java.awt.Color.black) ta.setFont( new java.awt.Font("メイリオ", java.awt.Font.PLAIN, 50)) f.getContentPane().add( new javax.swing.JScrollPane(ta), java.awt.BorderLayout.CENTER) f.setVisible(true) } public int fib (int x) { (x<2)?x:(fib(x-2)+fib(x-1)) } public Object run () { try { println ((0..10).collect{fib(it)}.join(" ")) } catch (Exception e) { println e for (java.lang.StackTraceElement ste in e.getStackTrace()) { println "\tat ${ste}" } } } }
print/println はオーバーライドしておいて、テキストエリアオブジェクトが null なら openWindow してテキストエリアを持つウィンドウフレームをオープンし、テキストエリアオブジェクトに出力する。
で、print/println/openWindow それからフィールド変数 ta を static にしておくのがミソ。main メソッドのようなクラスメソッドから print/println を呼ぶような実装にも対応できるようにしておく。
それから、例外もキャッチしてテキストエリアに表示する。
まとめると、次のようなことをする ASTTransformation を実装することになる:
(A) メインクラスにフィールド変数 ta を追加。
(B) メインクラスにメソッド print/println/openWindow を追加。
(C) run メソッド内部に try-catch 構造を追加。
次回は実装例を示す。