20 スタティックメソッド呼び出しに対応する

# はじめに

前回記事の「[オブジェクト生成に対応する](http://qiita.com/quwahara/items/ced0e9e2bf487f4021f8)」でクラスのロードができるようになりました。
ロードできるようになったクラスを利用して、そのクラスのスタティックメソッド呼び出しに対応したいと思います。

# スタティックメソッド呼び出し対応でやりたいこと

スタティックメソッド呼び出し対応でやりたいことを確認します。
例えば下のようなプログラムがあります。
1行目で`Integer`クラスを変数`integerClass`へロードします。
2行目でそのクラスの`toHexString`スタティックメソッドを呼び出し、その戻り値を出力するようにしたいと思います。
`toHexString`スタティックメソッドは引数の整数を16進数表現の文字列にして返します。
例の引数は`255`なので出力は`ff`になります。

```JS
var integerClass = loadClass("java.lang.Integer")
println(integerClass.toHexString(255))
```

# 実装の仕方

インタプリタ(Interpreter)での実装の仕方について考えていきます。
字句解析(Lexer)と構文解析(Parser)の変更はありません。

## インタプリタ(Interpreter)の実装の仕方

以前の記事、「[メソッド呼び出しに対応する](http://qiita.com/quwahara/items/f1bddefe984c8d233e02)」で、インスタンスメソッド呼び出しには対応しました。
スタティックメソッドも構文はインスタンスメソッドと同じなので、対応する箇所は、インスタンスメソッドでの対応と同じ箇所へ行います。

実装の仕方は、例えば`v.method()`のようなメソッド呼び出しがあったときの、`v`の型が何かを参照して、
それがインスタンスメソッドの呼び出しか、スタティックメソッドの呼び出しかを切り分けます。
切り分け方は、`v`の型が`Class<?>`ならスタティックメソッド呼び出しとみなし、
それ以外の型なら、インスタンスメソッド呼び出しとみなします。
それ以外の型とは、例えば`String`や`Integer`などです。

# Javaで実装してみる

実装にうつります。
インタプリタ(Interpreter)について、変更したところみてみます。

## Interpreter.java

Interpreter.javaの実装です。

`func()`メソッドの変更です。
`func()`メソッドは引数の`value`が、関数のように呼び出し可能であることを保証します。

`// Update`の下へ`if`文を入れる変更をしました。
先の例`v.method()`の`v`のあたるのが`d.left`です。
`d.left.getClass()`で`v`の型を取得します。
`v`の型が`Class<?>`であったら、それをスタティックメソッド呼び出しとみなし、そうでなければインスタンスメソッド呼び出しとみなします。
`if`文では、`MethodFunc`型変数の`mf`のフィールドへ、何を代入するかを決定します。
`mf`のフィールドへ正しく値を準備できれば、スタティックメソッド呼び出しとインスタンスメソッド呼び出しの違いを意識することなく、
`MethodFunc`クラスの`invoke`メソッドで、メソッド呼び出しを実行でるからです。

`if`文が真の場合、すなわちスタティックメソッド呼び出しの場合は、`mf.class_`に`d.left`自身を代入しています。
`d.left`自身が型を表しているためです。
`mf.target`には`null`を代入しています。
`null`を代入するのは、スタティックメソッド呼び出しなため、メソッド呼び出しにインスタンスが必要ないためです。
`if`文が偽の場合、すなわちインスタンスメソッド呼び出しの場合は、以前のメソッド呼び出しで実装したものと同じままです。

```Java:Interpreter.java
    public Func func(Object value) throws Exception {
        if (value instanceof Func) {
            return (Func) value;
        } else if (value instanceof Dotted) {
            Dotted d = (Dotted) value;
            MethodFunc mf = new MethodFunc();
            mf.name = d.right.value;
            // Update
            Class<?> c = d.left.getClass();
            if (c == Class.class.getClass()) {
                mf.class_ = (Class<?>) d.left;
                mf.target = null;
            } else {
                mf.class_ = c;
                mf.target = d.left;
            }
            return mf;
        } else if (value instanceof Variable) {
            Variable v = (Variable) value;
            return func(v.value);
        } else {
            throw new Exception("Not a function");
        }
    }
```

主な変更箇所は以上です。

以上の実装を使って下のプログラム

```JS
var integerClass = loadClass("java.lang.Integer")
println(integerClass.toHexString(255))
```

を実行し、`255`の16進数表現`ff`を出力します。

```Java:Interpreter.java
    public static void main(String[] args) throws Exception {
        String text = "";
        text += "var integerClass = loadClass(\"java.lang.Integer\")";
        text += "println(integerClass.toHexString(255))";
        List<Token> tokens = new Lexer().init(text).tokenize();
        List<Token> blk = new Parser().init(tokens).block();
        new Interpreter().init(blk).run();
        // --> ff
    }
```

実装は以上です。
ありがとうございました。

# おわりに

ソースの全文はこちらで公開しています。

**Calc**
https://github.com/quwahara/Calc/tree/article-20-static-method-invocation/Calc/src/main/java

続きの記事があります。

**スクリプトをファイルから読み込んで実行する**
http://qiita.com/quwahara/items/bac43cd1df11b025e46a