ぶていのログでぶログ

思い出したが吉日

reddish-shell v0.7.0 開発進捗 / hisotryの有効化とthenの省略と$IFSの見直し

前回、if文におけるthenキーワードを省略できないと書いたが、画期的なアイディアをひらめいて解決したので嬉しくなってバージョンアップした。 そして、この記事を書いている途中でunless文のthenを省略できるようにすることを失念したことに気がついた…。

commit一覧

コマンド履歴機能を有効にした

これは読んで時のごとく。 なんとなく有効にしてなかったけど、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文を実装したい。

*1:テストしていないので本当に動くかわからん

*2:複数環境向けにビルドできるからこの仕様はそうだろうなぁというお気持ち