ErlangとJInterface

JIntefaceはErlangJavaの相互運用を可能にするモジュールです。OTPに最初から含まれているので手軽に利用することができます。

先日、ErlangにRPCで指示を出して、応答をJTreeで表示するというテストアプリを書いてみたところ思いのほか便利で、これに加えて、普段Erlangを使っているときに表示されている式を適当にコピペするとビジュアライズできるようになったらもっと便利だなあと思いました。

そのためには文字列で与えたErlangのコードをparseしてevalできるような仕組が必要です。Erlang側にモジュールを作ってその力を借りればそんなに難しくなさそうですが、今回はJava側で組み立てて実行するようにしてみました。

(Erlangのevalってこうやるのか - kgbu? を参考にさせていただきました)

public static OtpErlangObject rpcExec(OtpConnection connection, String M, String F, OtpErlangList A) throws IOException, OtpErlangExit, OtpAuthException
{
	connection.sendRPC(M, F, A);
	return connection.receiveRPC();
}
public static final OtpErlangList emptyList = new OtpErlangList(new OtpErlangObject[]{} );
public static OtpErlangObject evalString(OtpConnection c, String expr) throws IOException, OtpException
{
	OtpErlangObject received ;
	// erl_scan:string(expr)
	received = rpcExec(c, "erl_scan", "string",
			new OtpErlangList(
					new OtpErlangObject[] {
							new OtpErlangString(expr)
					}));
	// should be {ok, Tokens, EndLocation}
	if(!(received instanceof OtpErlangTuple)) return received;
	OtpErlangTuple tuple = (OtpErlangTuple)received;
	if(tuple.arity() != 3) return received;
	OtpErlangAtom t1 = (OtpErlangAtom)tuple.elementAt(0);
	if(!t1.atomValue().equals("ok")) return received;
	
	OtpErlangObject tokens = tuple.elementAt(1);
	// erl_parse:parse_exprs(Tokens)
	received = rpcExec(c, "erl_parse", "parse_exprs",
			new OtpErlangList(
					new OtpErlangObject[] { tokens }));
	
	// should be {ok, [Expression]}   (Expression is tuple)
	if(!(received instanceof OtpErlangTuple)) return received;
	tuple = (OtpErlangTuple)received;
	if(tuple.arity() != 2) return received;
	t1 = (OtpErlangAtom)tuple.elementAt(0);
	if(!t1.atomValue().equals("ok")) return received;
	
	OtpErlangTuple expression = (OtpErlangTuple)((OtpErlangList)tuple.elementAt(1)).elementAt(0);
	
	// erl_eval:expr(Expression, erl_eval:bindings(erl_eval:new_bindings()))
	OtpErlangObject newBindings = rpcExec(c, "erl_eval", "new_bindings", emptyList);
	OtpErlangObject bindings = rpcExec(c, "erl_eval", "bindings",
			new OtpErlangList(new OtpErlangObject[] { newBindings} ));
	received = rpcExec(c, "erl_eval", "expr",
			new OtpErlangList(new OtpErlangObject[] { expression, bindings} ));
	return ((OtpErlangTuple)received).elementAt(1);
}

簡単なUIをつけてみました。


下のTextAreaに入力したテキストを↑のevalに通して、結果を上のJTreeに表示します。

コピペしたErlangのtermを表示した例です。バイナリはHEXで表示するようにしてみました。もうちょっとUIを考えないと常用には耐えられなさそうですけど、なかなか便利かもしれないと思いました。