free(malloc(sizeof(MRM)));

虚無・アクセラレーション

プログラミング言語を作っているよというお話.

自作言語をかれこれ8ヶ月ぐらい作ってるんですが,ちょっとドキュメント(笑)的なものは書いとくかと思ったので投稿します. 随時更新していきます.
リポジトリはここ!

特徴

インタプリタ

内部でソースコードバイトコードコンパイルして,それをVM(仮想機械)上で実行します.replもついてます.

repl

>> 10
10 : int
>> [10] 
[10] : [int]
>> 10 + 40
50 : int
>> let a = 10
>> a * 20000000  
200000000 : int
>> "println" + "orintln"
printlnorintln : string

普通のreplですが,pythonrubyのreplとは違い型を書いてくれるので便利です.

静的型付け

コンパイル時に型を解析します.

フルスクラッチ

(言語の特徴では無いですが,)解析,実行までの全フェーズ自分の手で書いています.

サンプルコード

なんか色々説明するよりソースコードを見てもらった方がよさそう.
Rustのsyntax colorを適用してるのでちょっと変な感じです.

ハロワ

println("Hello, World!");

標準出力は組み込み関数のprint,printlnで行います(printlnは改行がつきます).
式や文のデリミタは;(セミコロン)です.

変数定義

let a: int = 100;
let b: float = 100.0;
let c = "StrStrStr";

println(a, " ", b, " ", c);

実行結果

100 100.000000 StrStrStr

型の推論が可能な場合,型注釈を省略することができます. また,宣言をまとめることができます.

let {
    a = 100;
    b = 100.0;
    c = "StrStrStr";
}

if・while

なんかfor文は面倒くさくてまだ実装してません.明日から本気出します.

def fizzbuzz(n: int) {
    let i = 1;
    while i <= n {
        if i % 15 == 0 {
            println("fizzbuzz");
        }
        else if i % 5 == 0 {
            println("buzz");
        }
        else if i % 3 == 0 {
            println("fizz");
        }
        else {
            println(i);
        }

        ++i;
    }
}

15.fizzbuzz();

実行結果

1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz

関数定義・関数呼び出し

関数定義はdefキーワードで行います.前まではfnでした.

def dump_int(n: int) {
    println(n);
}
def add(a: int, b: int): int {
    return a + b;
}
def mul(a: int, b: int) = a * b;

dump_int(add(mul(10, 10), 400));

実行結果

500

戻り値の型がnone(なし)のときは,省略することができます.
また,関数の中身が式1つだけなら,中括弧を使わず=で一行で書くことが出来ます.この場合,戻り値の型が推論可能な場合は省略することができます.

UFCS

UFCS(Unified Function Call Syntax)は,一般的な関数呼び出しfunction(arr1, arr2)arr1.function(arg2)のように記述できる糖衣構文です.
これによって,上の関数呼び出しは以下のように記述することができるようになります.

10.mul(10).add(400).dump_int();

上のと比較すると,単純に左から読んで行けばいいので分かりやすくなっています.

また,引数が一個でUFCSを使用する場合は()を省略できます.

10.mul(10).add(400).dump_int;

関数のオーバーロード

def test() {
    println("No Arg");
}

def test(a: int) {
    println("arg 1: ", a);
}

def test(a: int, b: int) {
    println("arg 2: ", a, " ", b);
}

def test(a: float) {
    println("arg 1(float): ", a);
}

test();
test(19);
test(22, 42);
test(32.3);

実行結果

No Arg
arg 1: 19
arg 2: 22 42
arg 1(float): 32.300000

if式

def fibo(n: int): int = if n <= 1 n else fibo(n - 1) + fibo(n - 2);

34.fibo.println;

実行結果

5702887

if式 + 関数の中の式が一個の場合中括弧を省略できる機能でフィボナッチ級数を求めるプログラムを短く記述できます.
でもこのif式,若干見にくいので改良予定.

リスト

let a = [10, 41, 43, 582, 1];

println(a);

実行結果

[10,41,43,582,1]

rangeベースのfor文の実装とかはまだ.あと追加とかもまだ無理です.明日頑張る できました.

let a = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
let res = 0;

for i in a {
    res = res + i;
}

if res == 550 {
    println("success");
}

2重for文はまだバグります.なぜだ.

import(2019-9-19追加)

別ファイルに記述してあるプログラムを読み込むことができます.

import.mxc

import aaa;

println(aaa@aaaaa());

aaa.mxc

def aaaaa(): string {
    return "aaaaa";
}

実行結果

aaaaa

assert

assert 10 == 10;
assert 10 != 10;
[runtime error] assertion failed
 in tmp/assert.mxc::<global>

オブジェクト(構造体)

object Human {
    name: string,
    age: int
}

def speak(h: Human) {
    println(h.name, " uonuonuonuon ", h.age);
}

let marimo = new Human {};

marimo.name = "marimo";
marimo.age = 17;

marimo.speak;

実行結果

marimo uonuonuonuon 17

構造体の初期化はnew TagName {}で行います.将来的には

let marimo = new Human {name: "marimo", age: 17};

みたいなことができるようになると思います.

メソッドの定義

(メソッドといってもただの関数定義ですが)オブジェクトを第一引数に持ってくる + UFCSで関数がオブジェクトに束縛されているように記述できます.

def speak(h: Human) {
    println(h.name, " uonuonuonuon ", h.age);
}

marimo.speak;

組み込み関数一覧

  • print
  • println
  • echo printlnと同じです.
  • len 文字列長を返します.
  • objectid オブジェクトの識別子を返します.
  • tofloat int型の値をfloatにキャストして返します(ノリで実装したけど普通のキャストで良い気がする).

ないもの

オブジェクトの継承 無い
メンバ変数の隠蔽 無い
リスト 昔あったけど無い(明日からがんばる) さっき実装した(2019/8/28)
タプル 昔あったけど無い(明日からがんばる)
多分岐(switch-caseみたいなやつ) 無い(明日からがんばる)

その他もろもろ色々できません(明日からがんばります)

TODO

いっぱい

随時更新していきます.