LoginSignup
52
32

More than 5 years have passed since last update.

オレオレ言語を作っている

Last updated at Posted at 2018-10-13

動機

  • JSで素のWebGLをいじってゲームを作ろうとしていた。
  • GLSLで静的型付け言語の良さを再認識する。
  • JSからWebGLをいじってると、型変換のオーバーヘッドがちょっと気になってくる。
  • JSでのベクトルと行列の演算処理を書くのは面倒くさい。しかしGLSLのベクトルと行列の演算機能はよくできてて、JSもこんな感じでベクトル演算を書ければ楽なのになあと思う。
  • WebAssemblyができてメジャーブラウザで使えるようになる。これはまあLLVMのWeb版とも言える仕様。つまり言語が作れる!
  • 調べるともうすでにemscriptenがサポート、AssemblyScriptができていた!
  • これ使えばいいかなと思うが、emscriptenはサポートコードがでかい。さらにAssemblyScriptも試したが、ちょっと私のニーズには合わなさそう。
  • でまあGLSLチックなベクトル・行列演算機能を持つC風の言語を作ることにした。

何で作っているか

  • node.jsとpratt parserのコードをベースに実装している。
  • wasm出力はbinaryen.js(emscriptenでwasmにコンパイルして)を使用している。
  • とりあえずなにがしかのコンパイルはWebページ上でできるようになっている。
  • 検証用ウェブページ

image.png

リポジトリ

仕様の概要(現時点で考えてること)

  • 静的型付け
  • 自由文脈形式
  • C風かつwasmを強く意識した構文
    • そのままwasmにコンパイルされ、余計なサポートコードを極力吐かない
  • ユーザー定義型(カスタム型)が定義・使用可能
    • classなどは持たないかもしれない
  • ガベージコレクションは行わない
  • wasmの線形メモリに破壊的にアクセスできる
    • ヒープ/フリーストアのようなメモリ管理機構は持たない。ただしライブラリで書けるレベルの構文は用意する。
  • ベクトル・行列演算機能をGLSLのようにビルトインで持つ
  • コルーチンを言語機能として持つ

仕様詳細(まとめ中)

進捗状況

  • 2018年3月ころから実装し始めたが、まだまだ道半ばといった感じ。。

実装状況のレポーティング

  • まだまだ実装中
  • 実装状況はTwitterでつぶやき、それをTogetterでまとめている

コンパイルのサンプル

  • まだまだこの程度しかコンパイルできません。。

その1

ソース

// 関数 日本語使用可能
i32 𩸽(i32 a,i32 b){
    return a * b;
};

// メイン 
export i32 main(){
  i32 b = 0;

  for(i32 c = 0;c < 4;++c) {
    b = b + 1;
  }
  return 𩸽(b,b);// 4
};

動くサンプル

動くサンプル

コンパイル結果

(module
 (type $𩸽 (func (param i32 i32) (result i32)))
 (type $main (func (result i32)))
 (memory $0 1 1)
 (export "main" (func $main))
 (func $𩸽 (; 0 ;) (type $𩸽) (param $0 i32) (param $1 i32) (result i32)
  (return
   (i32.mul
    (get_local $0)
    (get_local $1)
   )
  )
 )
 (func $main (; 1 ;) (type $main) (result i32)
  (local $0 i32)
  (local $1 i32)
  (set_local $0
   (i32.const 0)
  )
  (block
   (block $for0
    (set_local $1
     (i32.const 0)
    )
    (loop $loop1
     (br_if $for0
      (i32.eqz
       (i32.lt_s
        (get_local $1)
        (i32.const 4)
       )
      )
     )
     (block
      (set_local $0
       (i32.add
        (get_local $0)
        (i32.const 1)
       )
      )
     )
     (set_local $1
      (i32.add
       (get_local $1)
       (i32.const 1)
      )
     )
     (br $loop1)
    )
   )
  )
  (return
   (call $𩸽
    (get_local $0)
    (get_local $0)
   )
  )
 )
)

その2:ユーザー定義型(カスタム型)

ソース

  type Bar {
  public:
    i32 barA = 3;
    i32 barB = 4;
  };

  type Foo {
  public:
    i32 a = 1;
    i32 b = 2;
    Bar c;
  };

  export i32 main(){
    Foo foo,foo1;
    foo.a = 2;
    foo1 = foo;  
    foo.a = 10;
    return foo.a * foo1.a;
  };

動くサンプル(コンパイル結果)

動くサンプル(コンパイル結果)

その3:ポインタ

ソースコード

export i32 main(){
  i32 p = 0;// メモリオフセット0をポインタにセット
  *p = 32.0f;// floatの値を保存
  u32 a = *p;// float値をu32値として取り出し
  return a;
};

動くサンプル(コンパイル結果)

動くサンプル(コンパイル結果)

その4:型エイリアス

ソースコード

export i32 main(){
  // type エイリアス
  type& T = i32;        
  type& T1 = T;

  T a = 1; 
  T1& b = a; 
  ++a;
  b += 2;
  return a;// 4
};

動くサンプル(コンパイル結果)

動くサンプル(コンパイル結果)

その5:const変数

ソースコード

const WIDTH = 320;
const HEIGHT = 240;

export i32 main(){
  i32 a = WIDTH * HEIGHT;
  return a;// 76800
};

動くサンプル(コンパイル結果)

動くサンプル(コンパイル結果)

その6:reinterpret cast

ソースコード

export f64 main(){
  i64 a = 0x3fc4 0000 0000 0000xl;// f64を整数値として代入
  f64 b = (^f64)a;// reinterpret cast

  return b;// 0.15625
};

動くサンプル(コンパイル結果)

動くサンプル(コンパイル結果)

その7:キャスト

ソースコード

// キャストの実装(ネイティブ型同士のみ)
export i32 main(){
  i32 b = 10;
  f64 c = (f64)b + 10.0lf;
  return (i32)c;
};


動くサンプル(コンパイル結果)

動くサンプル(コンパイル結果)

その8:数値リテラル

ソースコード

export i32 main(){
  i32 a = 0x1 00x;// 16進リテラル(スペースで値が区切れる)
  ,b = 0b1 0000 0000 b;// 2進数リテラル
  if( a == b){
    return 1;
  } 

  return 0;
};



動くサンプル(コンパイル結果)

動くサンプル(コンパイル結果)

52
32
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
52
32