Regexp::Assemble のバグなのか、どうかいろいろ試す修行

Regexp::Assembleのバグ? - Humanity によると、

ということで正規表現リテラル(?)じゃなく文字列で渡せばうまくいきました。

ということだったけれど、いろいろやってみたらそういうわけでもなさそう、つまり、文字列を渡しても落ちるときは落ちるみたい、ということ。

まず、教えてもらったコードを自分なりに書き換えて work around を探ってみた。

use strict;
use warnings;
use Regexp::Assemble;

my %action_table = (
    qr{\A (\S+) \s* (are) \s* (.+) \Z}xms => sub {
        my ($n, $v, $p) = @_;
        return "are/$n/$p";
    },
    qr{\A (\S+) \s* (is) \s* (.+) \Z}xms => sub {
        my ($n, $v, $p) = @_;
        return "is/$n/$p";
    },
    qr{\A (.*) \Z}xms => sub {
        my $x = shift;
        return "else($x)\n";
    },
);
 
my $ra = Regexp::Assemble->new->track;

my $case = 0;

print "--- case $case ---\n";
if ($case == 0) {
    $ra->add(keys %action_table);
}
elsif ($case == 1) {
    foreach my $re (keys %action_table) {
        $ra->add($re);
        my $dummy = "$ra";
    }
}
elsif ($case == 2) {
    $ra->add(map {q{} . $_} keys %action_table);
}
 
my $s = 'this is a test.';
if ($ra->match($s)) {
    my $re = $ra->matched;
    my @args = $ra->capture;
    print $action_table{$re}->(@args), "\n";
}

このプログラムをそのまま ($case = 0 のまま) 動かすと、Regexp::Assembleのバグ? - Humanity とほぼ同じコードなので次のエラーが出る。

$ perl f.pl
--- case 0 ---
Unmatched ) in regex; marked by <-- HERE in m/(?:(?msx-i:\A (\S+) \s* (?:(are) \s* (.+) \Z)(?{$self->{m}=1})|(is) \s* (.+) \Z)(?{$self->{m}=2}))|(?msx-i:\A (.*) \Z)(?{$self->{m}=0})) <-- HERE / at /usr/lib/perl5/site_perl/5.8.8/Regexp/Assemble.pm line 996.

最後に一個閉じ括弧が足りない、って感じか。

次に、$case = 1 に書き換えて動かすと次のようになる。

$ perl f.pl
--- case 1 ---
is/this/a test.

ちゃんと動いている。アイディアとしては、add メソッドにリストを渡すんじゃなくて、正規表現リテラルを一個ずつ渡していく、というもの。
不思議なのは、

        my $dummy = "$ra";

の行をコメントアウトしてしまうと case 0 と同じエラーが出るというところ。Regexp::Assemble オブジェクトを文字列コンテキストで評価すると何かが変わって動くようになるらしい。嫌な work around だ。

最後に、正規表現リテラルだとダメで文字列ならオッケーということなら、add に渡す直前に文字列にしちゃえばいいじゃない、ということで、$case = 2 で動かしてみる。

$ perl f.pl
--- case 2 ---
Unmatched ) in regex; marked by <-- HERE in m/(?:(?msx-i:\A (\S+) \s* (?:(are) \s* (.+) \Z)(?{$self->{m}=1})|(is) \s* (.+) \Z)(?{$self->{m}=2}))|(?msx-i:\A (.*) \Z)(?{$self->{m}=0})) <-- HERE / at /usr/lib/perl5/site_perl/5.8.8/Regexp/As\
semble.pm line 996.

ということで、駄目でした。おしまい。

じゃなくて、本当に文字列でもダメなのか、もっと要素を減らしたスクリプトで試してみた。

use strict;
use warnings;
use Regexp::Assemble;

my @res = (
     '(?:(\S+)\s*(are))',
     '(?:(\S+)\s*(is))',
);
 
my $ra = Regexp::Assemble->new->track->add(@res);
my $s = 'this is a test.';
if ($ra->match($s)) {
    my $re = $ra->matched;
    my @args = $ra->capture;
    print "$re => ", join("/", @args), "\n";
}
$ perl  g.pl
Unmatched ) in regex; marked by <-- HERE in m/(?:(\S+)\s*(?:(are))(?{$self->{m}=0})|(is))(?{$self->{m}=1})) <-- HERE / at /usr/lib/perl5/site_perl/5.8.8/Regexp/Assemble.pm line 996.

おっと、これでもエラー。正規表現リテラルかどうかには関係なくエラーが起こっていることがわかる。

さて、どうしたものか。

追記

バージョンを記しておこう。

$ m=Regexp::Assemble; perl -M$m -le "print \$$m::VERSION"
0.34
$ perl -v

This is perl, v5.8.8 built for i386-linux-thread-multi