前回、if文におけるthenキーワードを省略できないと書いたが、画期的なアイディアをひらめいて解決したので嬉しくなってバージョンアップした。 そして、この記事を書いている途中でunless文のthenを省略できるようにすることを失念したことに気がついた…。
commit一覧
- 839ad1c Enable command history.
- 4574276 Merge Pipeline into Connector.
- 2f6e755 Add the option to omit "then".
- aead929 No longer refers to $IFS.
- bb29724 Remove mirb
- 6f7a321 v0.7.0
コマンド履歴機能を有効にした
これは読んで時のごとく。
なんとなく有効にしてなかったけど、2,3行書くだけで有効になるし、デバッグ作業が楽になるので有効にした。
コマンド履歴をどこかに保存する必要があるのだが、XDGに倣って ~/.local/share/reddish/history.txt
に保存するようにした。
Element::PipelineをElement::Connectorに統合した
パイプライン(cmd1 | cmd2)とコネクタ(&&結合や||結合)をなぜか別のクラスとして定義していたのを統合した。 これにより、パーサーが最終的に生成する要素はElement::Command、Element::Connector、Element::Statementの3つになってシンプルになった。
thenを省略できるようにした
これが今回の目玉機能。
なぜthenが省略できなかったか改めて簡単に説明すると、Rubyにおいては ;
は式の終わりが明確なのだけど、コマンドラインにおいてはそうではないので、ifの条件文としてコマンドラインなのか、ifで実行するコマンドラインなのかの境目がわからずパーサーが正しく判定できないのであった。
で、どうやって解決したかというと if cmd1; cmd2; end
とあったとしたら cmd1
を条件文として見なすようにした。
パーサー的には cmd1; cmd2
は2つのコマンドを ;
でつないだコマンドラインとして見なすのだけど、それを処理する部分(パーサーアクションと読んでいる)では、cmd1を条件文として取り出して、cmd2を条件分がtrueのときに実行するコマンドに分割するという感じである。
これを思いついたときは「天才か?!」っと思ったけど、文章でこの凄さを表現するのはハチャメチャに難しいな。。 具体的な実装を交えて書けばいいのだろうか…。
レキサーにおいて$IFSを参照しないようになった
なんとなく$IFSを尊重するようにレキサーを書いていた*1のだけど、これをやめた。 そもそも、bashにおいて$IFSの扱い方を勘違いしていた。 bashにおいて$IFSを参照するのは以下のときだけであった。
- $* の展開時
- read内蔵コマンドの実行時
- 変数の展開など単語の分割(Word Splitting)が発生するとき
そのため、コマンドラインをパースするときは$IFSを参照しないのであった。学び。
mirbをビルドするのをやめた
いままで、利用しているmgemの動作確認をするためにmirbをビルドしていたのだけど、rakeするときにそこそこ時間がかかるのでやめてしまった。 mrubyの仕様かもしれないけど、ビルドターゲットごとにmgemをcloneしてそしてバイナリをつくるのがその要因だと思う*2。 mirb自体使わなくなったので削除した。
次回の実装予定
忘れていたunless文のthen省略を追加する。 それと今は複数行のコマンドラインのサポートをしようとしている。 ただ、これが結構めんどくさく今まで1行しかコマンドがないという前提でレキサー/パーサーを書いていたので、根本的に見直す必要があるという感じ。 これができたら、ENVの取扱の見直しと、コマンド置換あたりを実装して、while/until文を実装したい。