空想犬猫記

※当日記では、犬も猫も空想も扱っておりません。(旧・エト記)

etolisp 進捗 (10) return の実装

今日は,return-from や return の実装をした。

etolisp のもう一つの設計方針は,Lisp の関数が C の関数(あるいは C++ の関数オブジェクト)に一対一対応になるようにする,というもの。それはコードの見通しの良さと,将来,C/C++ で簡単に拡張可能できるようにするためだ。なので,if や do,progn や block なども,一つの関数に対応している。

そういう方針だと,return-from や return の実装はちょっと注意が必要だ。なぜならば,通常の関数は,カッコとコッカで括られた (...) を評価して,その値を返せばそれで役目は終わりであるのに対し,return 系の関数は,そのあと,構文木の特定の箇所に移動しなければならないからだ。return は評価結果を持ちつつ,そういう役目も負っている。

それと,上記の etolisp の事情を考えると,なんとかして関数を跨いだ制御を実現する必要がある。ちょっと考えて思いついた選択肢は大域変数を使うか,例外を使うか,特殊な返り値を導入するかの三通り。リーズナブルなのは三番目だ。

というわけで,ValueSignal という新しいタイプの値を導入。この Value は,メンバとして Value を内包しており,普通に使うぶんにはその Value として振る舞う。それに加えて,

  • signal の種類
  • tag(戻る場所)

を持っている。使い道は考えてないが,return 以外の目的にも使用できそうなので,含みを持たせた名前にしてみた。で,これだけだと,(signal ではなく)単なる値としてしか扱ってもらえなかった場合,何も起こらない。(return 20) が,たんに 20 を返すだけの関数になってしまうのは,困る。Signal をちゃんと signal として扱うのは,上位関数の責任である。

その責任を明らかにするために,ValueSignal は,signal として扱われず,無視されて死んじゃった場合,デストラクタで C++ の例外を投げるという仕様にした。デストラクタで例外を投げるのは,あまり普通ではないが,設計上,メモリリークが起きないようになってるし,まあいいかなと思っている。この仕様のおかげで,return を処理し忘れた関数(if や do などの制御系の関数)が,例外を投げる(=悪い関数の証)ようにできた。

cons が構造を造る。value には宿命があり,関数には責任がある。今のところ,etolisp の世界は,秩序に守られている。