DLRのASTのみを使う
簡単な言語を作るシリーズでNyaRuRuさんがDLRのASTだけを使った方法というのを解説していると取り上げました。DLRのソースコードを使わないで、DLRのASTだけを扱う方法を以下に示します。
using System;
using System.Collections.Generic;
using Microsoft.Scripting;
using Microsoft.Scripting.Ast;
namespace AstTest
{
delegate void MyFunc();
class Program
{
static void Main(string[] args)
{
var helper = typeof(Console).GetMethod("WriteLine",
new[] {typeof(string)});
// コードブロックが、関数名の一種と考えれば良い
CodeBlock cb = Ast.CodeBlock("MyFunc", typeof(void));
cb.Body =
Ast.Block(
Ast.Call(helper, Ast.Constant("Hello, World")),
Ast.Call(helper, Ast.Constant("Hello, World")),
Ast.Call(helper, Ast.Constant("Hello, World"))
);
// 型パラメータを作成したコードブロックに一致させる
MyFunc myFunc = TreeCompiler.CompileBlock<myfunc>(cb);
myFunc();
Console.ReadKey();
}
}
}
このプログラムにMicrosft.Scripting.dllへの参照を追加して実行すれば、「Hello, World」の文字列が3回コンソールに出力されます。このコードが何をしているかと云えば、以下のようなことです。
- CodeBlock定義:一種の関数定義と思っていただければ良いと思います。第一引数にブロック(関数)名、第二引数に戻り値の型を指定します。
- Body定義:何を実行するかを定義します。この場合で云えば、Console.WriteLineメソッド呼び出しに、Hello, Worldという定数を引き渡します。
- TreeCompiler:Microsoft.Scripting.Ast.TreeCompilerクラスのComipleBlockメソッドでコードブロックをコンパイルして、結果をデリゲートインスタンスとして返します。ここで指定している型パラメータは、作成したコードブロック(関数のようなもの)に合わせます。
- 作成したデリゲートを呼び出します。
これで作成したDLRのASTが無事に実行されるのです。この例では、戻り値の無いMyFuncというコードブロックを作成するために、「delegate void MyFunc()」というデリゲートを定義しています。戻り値や引数がある場合は、Funcデリゲートを流用しても良いでしょう。
この例以外に引数を取るブロックやループなどが出来るのは、NyaRuRuさんのエントリーの通りです。他の言語を使用するまでも無く、ちょっとしたロジックを自分でASTを組み立てて実行したい時などに利用することができるでしょう。
Comments
Anonymous
February 28, 2008
PingBack from http://www.biosensorab.org/2008/02/29/dlr%e3%81%aeast%e3%81%ae%e3%81%bf%e3%82%92%e4%bd%bf%e3%81%86/Anonymous
March 01, 2008
Microsoft.Scripting.Ast.TreeCompiler 『C#, DLR AST, meta programming』で「DLR AST の直接コンパイルは public クラスからはできない」と書きましたが,誤報でした.すみません. 荒井さんのエントリ『DLRのASTのみを使う』にあるように,TreeCompiler クラスのスタティAnonymous
September 03, 2008
以前の DLRのASTのみを使う というエントリでTreeCompilerを使う方法を説明しました。最近のDLRでは、どうなったでしょうか。結論から云えば、IronPython 2.0 ベータ4ではTreeCompilerは無くなっています。その代わりに、以下のような方法を使うことでDLRのASTのみを使うことができます。