ここ数日、次のような記事を書きました。
ようするに、CatyScript2.0の意味論の記述方法を考えていた、ってことです(構文の記述はBNFで不満はありません)。CatyScript2.0で追加拡張する機能でたぶん最初に着手するのは変数とコマンド呼び出しです。よって、意味記述も変数とコマンド呼び出しを最初にやるでしょう。つうか、やってみました。
やってみると、言語の表層構文以外に、評価の途中でだけ使うような構文的データ構造もあったほうがよいな、と思いました。「評価の途中でだけ使う」ヤツって、だいたいはクロージャなんですけどね。もっと具体的に言うと、コマンドのパラメータとか名前やら定義体(definition body)をカプセル化したようなデータ構造です。それについて書いておきます。
パラメータデータ
最初にコマンドパラメータから; パラメータはオプションパラメータ(名前付きパラメータ)と引数パラメータ(位置パラメータ)の組なので、そのデータ構造を素直に定義すれば次のようになるでしょう。(データ型定義にはCatyスキーマ言語を使用。)
type ParamsData_1 = { /** オプションパラメータ */ "opts" : {* : any?}, /** 引数パラメータ */ "argv" : [any, any*] };
argv[0] だけは特別扱いするんで、次のような形もいいかも知れません。
type ParamsData_2 = { /** オプションパラメータ */ "opts" : {* : any?}, /** 0番目の引数パラメータ */ "arg0" : any, /** 1番以降の引数パラメータ */ "args" : [any*] };
現在採用しているのは次の形です。
type ParamsData = { /** 引数パラメータ */ "_ARGV" : [any, any*], /** オプションパラメータ */ * : any?, };
この形だと、パラメータデータがそのまま変数束縛に使えるというメリットがあります。
コマンド呼び出しのデータ
コマンド呼び出しの構文は、コマンド名とパラメータ式からなります。パラメータ式を普通に評価するとパラメータデータとなります。パラメータデータとコマンド名を一緒にしたデータを次のように定義しましょう。
type CommandData = @_command { /** パラメータデータ */ "params" : PramsData, /** コマンド名 */ "name" : string };
タグ @_command は単なる目印で深い意味はありません。
ネイティブコマンドは次のデータで表現するのが適切でしょう。
type NativeData = @_native { /** パラメータデータ */ "params" : PramsData, /** ネイティブ関数への参照 */ "ref" : string };
ネイティブ言語が複数あるなら、実装言語を識別するプロパティ(例えば、implLangプロパティ)も必要になるでしょう。
一方、コマンドがスクリプトで実装されているなら、次のようなデータで表現できます。ここで、ScriptCodeは、スクリプトコードのテキストとかコンパイル済みバイナリなどを表すデータ型とします。
type ScriptData = @_script { /** パラメータデータ */ "params" : PramsData, /** スクリプトコード */ "code" : ScriptCode };
記号表現
今定義した CommandData、NativeData、ScriptData は、実行すべきコードと評価環境(パラメータ束縛)を一緒にしているので、クロージャと言ってもいいでしょう。CommandDataとNativeDataでは、実行すべきコードの名前とか参照ですが、参照を解決すれば実行可能なナニカが得られます。
αをパラメータデータとして、CommandData、NativeData、ScriptDataのデータインスタンスを、それぞれ次のように表記することにします。
- _command{α, c} (cはコマンド名)
- _native{α, r} (rはネイティブ関数への参照)
- _script{α, E} (Eはスクリプト式)
このような内部的な式(記号表現)を評価方法の記述に用いると、記述が随分と楽になります。
実際の記述は次の機会に。