オレオレ言語を作っている
オレオレ言語を作っている:
https://github.com/sfpgmr/sgl2
動くサンプル
動くサンプル(コンパイル結果)
動くサンプル(コンパイル結果)
動くサンプル(コンパイル結果)
動くサンプル(コンパイル結果)
動くサンプル(コンパイル結果)
動くサンプル(コンパイル結果)
動くサンプル(コンパイル結果)
動機
- 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ページ上でできるようになっている。
- 検証用ウェブページ
リポジトリ
https://github.com/sfpgmr/sgl2
仕様の概要(現時点で考えてること)
- 静的型付け
- 自由文脈形式
- 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; };
コメント
コメントを投稿