KotlinのREPLで括弧だけのコードを動かす

KotlinにはREPL機能があります。対話型実行環境ですね。さらに、拡張関数を定義できるなど、かなり柔軟なコードが書ける言語でもあります。

今回は演算子の拡張関数を利用することで、(){}だけで任意の処理を動かすようにしてみます。Ook言語を利用しています。

コード全体はこちら

コードを読み解くために、まずは拡張関数の定義を見ていきます。

typealias Brace = () -> Unit

operator fun Brace.invoke(_b: Brace) = Brace2

object Brace2 {
    operator fun invoke(_b: Brace) = BracketsOok(WholeState(Memory({ Array<Byte>(30000, { 0 }) }), InstructionStack(emptyArray())))
}

文に出てくる単体の{}() -> Unitという型になります。これをBraceと呼ぶこととします。
さらにBraceを、Braceを一つ引数に取る関数のように実行(invoke)させられるようにします。ここで、Kotlinでは関数に1つの関数を引数として渡すときは()を省略し、{}を使って書けるということを思い出してください。
これにより、{}{}Brace2オブジェクトを表すことができます。
オーバーロードしている関数に渡す場合、hoge()hoge({})hoge({}{})という3つのパターンができることになります。

続いて、プログラムの開始と終了を表す記述を定義します。上のコードに出てきていますが、(({}{}){})BracketsOokのインスタンスを表すようにします。ここの()を省略すると曖昧になって上手くいきません。

operator fun invoke(): BracketsOok {}

operator fun invoke(_b: Brace): BracketsOok {}

operator fun invoke(_b2: Brace2): BracketsOok {}

operator fun invoke(_bf: BracketsOok) {}

BracketsOokもまた関数のように実行(invoke)できるようにし、3つの先ほどのパターンを利用して内部状態を変化させることでコードとして蓄積させます。最後に、(({}{}){})を渡すと記述終了とし、蓄積したコードを実行します。

括弧の列をそのまま単体でmain関数に書いてもいいですが、タイトルの通りREPL上にすると括弧しかないようなプログラムになります。以下がIntelliJ IDEA 2017.1で実行した例です。(実行には時間がかかります)

REPL結果

HelloWorldのほうはコンパイルは出来ないんですが、REPLでは動く…

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です