Clover2開発日誌

Clover2というJavaのように静的な型を持つRubyのようなコンパイラ+仮想マシンの開発日誌です。LLVMでJITもします。https://github.com/ab25cqにて開発しています。

version 3.1.9 リリース 2017/11/28

setterとgetterがフィールドを定義すると自動的に定義されるようになりました。

> vim SetterAndGetter.clcl
class SetterAndGetter {
    field1:int;
    field2: String;
    field3: private int;

    def initialize() {}
}
> vim setter_and_getter.cl
a := new SetterAndGetter();
a.field1(123);
a.field2("ABC");
Clover.test("setter and getter", a.field1() == 123 && b.field2().equals("ABC"));

# a.field3()は定義されているがa.field3(123)は定義されていない。

デフォルトの定義が気に食わないときはそのようなメソッドを後から定義してください。Clover2は後から定義されたメソッドがメソッド検索時に優先されるので。

version 3.1.8リリース

列挙型

> vim EnumTest.clclc
class EnumTest {
    enum { Value1, Value2, Value3 }
    enum { BValue1, BValue2, BValue3 }
}
> vim enum_test.cl
Clover.test("enum test", EnumTest.Value1 == 0 && EnumTest.Value2 == 1 && EnumTest.Value3 == 2 && EnumTest.BValue1 == 0 && EnumTest.BValue2 == 1 && EnumTest.BValue3 == 2);
> clover2 enum_test.cl
enum test...OK

になります。enum型の要素は初期化される単なるstatic intです。糖衣構文みたいなもんですね。

メソッドのデフォルト引数 version 3.1.7

> vim ClassA.clcl
class ClassA {
    def initialize() {}
    def method(a:int, b:int=2, c:int=3) {
        return a + b + c;
    }
}
> vim a.cl
a := new ClassA();
Clover.test("Method arg default value", a.method(1) == 6);
> clover2 a.cl
Method arg default value...OK

上記のようにメソッドの引数のデフォルト値が設定できます。

version 3.1.6 リリース 2017/11/21

isメソッドがAnonymousメソッド以外にも呼べるようになりました。List<Object>などで便利だと思います。

> a := new List<Object>();
> a.add(1);
> a.add("ABC");
> a.each {
>    if(it.is("String")) {
>        it.printf("[%s]"); # itはString型
>    }
>    elif(it.is("Integer")) {
>        it.printf("[%d]"); # itはInteger型
>    }
> }

みたいな感じです。その時気づいたのですが、List<Object>に1をaddする時boxingもされずにObject型に代入できてしまうためセグメンテーション違反が出てました。ちゃんとインタフェースにはプリミティブ型は代入できないようにチェックするようにしました。またインターフェースへのプリミティブ型の代入はboxingされるようにしました。上のコードはversion 3.1.6ではちゃんと動きます。

version 3.1.5リリース

version 3.1.5 リリース 2017/11/20

クラスの循環参照の問題を解決しました。

> vim ClassA.clcl
class ClassA {
    field1: static int;

    def hello(): static {
        ClassB.hello();
    }
}
> vim ClassB.clcl
class ClassB {
    def hello(): static {
        println("ClassA.field1 \{ClassA.field1}\n");
    }
}

このようなコードの場合ClassA.clcl, ClassB.clcl両方のコンパイルが通りませんが以下の様にすれば大丈夫です。

> vim ClassA.clcl
include "ClassB.clcl"

class ClassA {
    field1: static int;

    def hello(): static {
        ClassB.hello();
    }
}
> vim ClassB.clcl
include "ClassA.clcl"

class ClassB {
    def hello(): static {
        println("ClassA.field1 \{ClassA.field1}\n");
    }
}

循環参照しているソース両方でincludeしてください。どちらかのソースをコンパイルするとコンパイルが通ります。

version 3.1.4リリース

クラスの自動コンパイル機能を入れました。クラス名をファイル名に持つクラスは自動的にコンパイルされます。 例えば

> vim Hello.clcl
class Hello {
    def hello() {
       println("HELLO WORLD");
    }
}
> vim hello.cl
Hello.hello();
> clover2 hello.cl
HELLO WORLD

のような感じです。クラス名はファイル名と同じにしておくほうが自動的コンパイルされるので便利かもしません。あとコメントを日本語で書き始めました。そのほうがしっくりきました。Clover2は日本人向けに作っていきたいと思います。