(WIP)「リテラルオブジェクトをRubyのオブジェクトから卒業させる」をやってみた Part 2

はじめに

この記事は、以下の記事の続きです

gamelinks007.hatenablog.com

parse.yリファクタリングチャレンジの中の一つ「リテラルオブジェクトをRubyのオブジェクトから卒業させる」をチャレンジしている途中記録をまとめたものになります。

前回から今回の記事までにやったこと

マイナスがついているIntegerのリテラルオブジェクトを生成できるように対応

前回の記事までの対応だと、以下のようなコードが正しく処理されませんでした。

p -117
# => 117と出力される

これは parse.y の以下の部分で行っている -117 へと変換する処理がすり抜けているため、117 という正の数になってしまっていた感じでした。

github.com

なので、以下のコミットでマイナスがついている場合も負のIntegerを生成できるように修正した。

github.com

やっていることとしては rb_integer_literal_info_t というInteger関連の情報を保持する構造体を追加し、そこへ負の値かどうかの情報を渡すようにしています。 それを compile.cリテラルオブジェクトを生成する部分でチェックし、チェックに引っかかれば負の値として値を返すようにしています。

0の場合だけIntegerのリテラルオブジェクトを正しく生成できない問題に対応

次になんとかしたのは 0 の場合だけ正しくリテラルオブジェクトを生成できていない部分です。

具体的には以下のコードが false を返していました。

p 117 - 117 == 0
# => falseが返される

挙動などを調べたところ、これは以下のようにリテラルオブジェクトを生成していることが分かりました。

117 - 117 == 117

何故か 0 の部分が 117となっているため 0 == 117という式になり、結果として false が返っていたというわけです。

で、こちらに関しては以下のコミットで修正しました。

github.com

どうも tok(p) で値を取得している際に以前の値が残ったままになっているケースがあり、そのエッジケースに遭遇したということのようです。 そのため tokfix(p) を追加して、その辺をいい感じに処理しています。

ここは現状のRubyでは問題になっていませんが、あとでPR投げてもいいかなと思っています。

今後

とりあえず、 make btest でパスしていないテストの数が17件くらいになってきたので残りの部分を直していきたいですね。 たぶん次に対応するのは 1.2rとかのリテラルオブジェクトを生成する部分などになりそう。

宣伝

parse.y リファクタリングチャレンジとかUniversal Parserの話、またはCRubyの内部実装の話などは以下のイベントでアレコレ話してたりするので興味のある方は是非是非ご参加くださいー。

hamadarb.connpass.com