小粋なスクリプト言語が欲しい
小粋なスクリプト言語が欲しい
機内書き物。だったけどなんとなくその後もちょこちょこ編集しているページ。技術的なメモ
Android用のシェルみたいな何かが欲しいと思って、Starlarkで作ろうか、と思ったが、 Starlarkはクラスなどが無い。 小さなコアがあっていろいろその上に作っていく、というモノとは用途が違う。
luaとかはそういうものと思うが、小粋なシンタックスというのとは随分違うものだ。まぁlua詳しくないからそう思うだけかもしれないが。
EmbeddedLangに以前いろいろ見たのがあるが、これはC++。Kotlinで使いたい、と思う奴が欲しいな。
求められる性質
そもそも、そういう用途のスクリプト言語というものが無い気がする。 ここで言う「そういう用途」とはなんだろう?
- 実装が小さい
- メンテが簡単
- jarとかにせず簡単に他のプロジェクトにフォルダごとコピーして組み込める
- 小粋なシンタックス
- スピードは遅くていい
- コアの機能が小さく、拡張していく最低限のものだけを提供している
- 実装言語はGC前提で良い(Kotlinとgolangで作れればいい)
Starlarkはかなり近い。だが拡張していくベース言語というものではない。
言語内DSLを作っていけるような基盤が欲しいんだよな。
実装が簡単でランタイムはホスト側に大きく依存していて、簡単に他の言語でも再実装出来るようなのが欲しい。
でもStarlarkは改めて学習する必要が無く、広く使われている言語に近いというメリットはあるんだよなぁ。 うーむ、自分で作ってもこれらのメリットは得られない気はする。
欲しい言語機能
まぁ作るのが現実的かどうかはおいといて、何が欲しいのかをもう少し考えてみよう。
まず、Androidで使いやすいembed言語が欲しい。だからAndroidのランタイムが使えるので独自にGCとかはしなくていい。 実装は小さくて取り回しが良いのが良い。スピードはいらない。普通にテキストをパースして実行するので良い。
その気になれば簡単に実装出来るようなのがいい。とりあえずgolangとkotlinで簡単に実装出来る何か。
Python shではいろいろな付加機能をmethod chainや名前付き引数で提供していて、ああいうのを使いたい。 オプショナルな事をいろいろ簡単に書けて欲しいんだよな。
うーむ、考えていると何が欲しいのか良く分からなくなってきた。
まず当面の目的は、Starlarkで使い方を工夫すればいいような気もしてきたな。たぶんある機能でうまい事考える事は出来る気がする。
そしてそういう具体例無しで欲しい言語を考えるのは、たぶんうまくいかない。 うまく行かないのだけれど、なんとなくモヤモヤしたものを書き出してスッキリしておくのはやっておきたい気もするので、以下にはぼんやりとした考えを書き出していきたい。
関数定義が短く出来る言語がいい。ラムダも短く書ける言語がいい。
オブジェクトリテラルがJavaScriptみたいに簡単に書ける言語がいい。
パイプ演算子は欲しい。
デフォルトは短く呼べるが、オプショナルな要素を追加出来るようになっていて欲しい。
ユーザーに定義させたものを操作しやすい言語がいい。 例えば定義した関数の引数を調べて、その中身に応じて挙動を変えたい。
パースも実行も簡単な言語がいい。
例えばFSharpには、パイプラインの途中で$_を使ったプロパティアクセスがあると関数になる、みたいな機能があるが、ああいう感じの言語が欲しい気がするなぁ。
型は無くて関数適用はF#的で、中括弧でブロック、中括弧の中に$0とかあるとラムダ式になる、とかでどうだろう? シェルスクリプト的には$1からか?
仕様の試行錯誤
ちょっとそれっぽい仕様を考えてみる。ifとかの制御構造は全部ブロックと関数にする。 ブロックは実行可能配列のようなものとして、けれど中に$0とかあったら関数とする。
関数はfunでkotlinを真似てみよう。
fun hoge(a, b) {
a+b
}
ラムダだと以下。
let hoge = {$0+$1}
関数呼び出しはどうしようかな?まぁとりあえずF#スタイルにしてみるか。
hoge 1 2
ブロックはクロージャとしてそれが作られた環境を持つ。だからifなどでブロックを渡したら、呼び出し元のスコープとして評価出来る。
if文はどうしようかなぁ。遅延評価はブロックのみなら以下みたいな感じか?
if cond { body1 } else { body2 }
パースすると以下の呼び出しになる。
ifel(cond, block1, block2)
いや、別にblockにする、と決めてしまえば、パースさえできれば自動でブロックにするのはやればいいか。
引数無しのブロックはF#同様にカッコを渡すのかなぁ。
block1 ()
まぁこれでいいか。
以上から考えられる実装
- すべて関数呼び出しのシンタックスシュガー
- 遅延評価は全部ブロックになる
- intなども全部boxingしてオブジェクトに
まぁこんな感じで、あとはシンタックスをモダンな感じに出来たらいいんじゃないか。
ってこれだとクラスが無いな。いらないっちゃいらないが。でもAndroidのオブジェクト呼ぶからメソッド呼び出しのノーテーションは必要か。 うーん、いまいちだな。
ホスト側からの使いやすさを考える
Starlarkの不満としては、呼ぶのが面倒というのがある。 もっと原始的な言語でいいんだよなぁ、と。
コールスタックはいるし、変数のenvはいるし、途中でRuntime Permissionとかをリクエストする必要があるのでyieldも出来ないとだめだが…って考えていくと、結局継続も必要になって、 やっぱり似たような面倒さにはなってしまうか。