有没有一种方法可以在Perl中重载正则表达式绑定运算符`=~`?

19

我正在开发一个小型DSL,使用nomethod回退机制来实现重载,并捕获用于重载值的运算符。这类似于overload文档中描述的符号计算器的功能。

这对于标准比较运算符很有效,但考虑以下情况:

my $ret = $overloaded =~ /regex/;
在这种情况下,nomethod被调用以将$overloaded转换为字符串,在此之后,重载会丢失。我考虑返回一个绑定的变量,这样至少可以带着原始的重载对象,但在执行正则表达式期间仍将丢失。

所以,最终问题是是否有任何方法可以扩展overload对符号计算器的理解,以包括正则表达式绑定运算符=~!〜,这样上述代码示例将使用 nomethod 和类似于($overloaded,qr / regex /,0,'=〜')进行调用?
我还简要研究了智能匹配运算符~~,但那似乎也行不通(始终使用默认的正则表达式匹配而不是重载)。
编辑:我更深入地研究了~~,并发现my $ret = $overloaded ~~ q/regex/ 由于智能匹配规则而起作用。接近,但不是理想的解决方案,我希望它适用于5.10之前的版本,因此欢迎其他答案。

如果你想让它在5.10之前的版本中运行,那么为正则表达式引擎提供一个包装器也不起作用。 - brian d foy
结束疯狂!学习Python! - bukzor
1
@bukzor:我很确定你无法在Python中重载正则表达式绑定运算符,因为它没有这样的运算符。当然,你可以编写一个类来提供类似但有限的功能:http://code.activestate.com/recipes/302498-re-match-and-replace-through-operator-overloading/ - Adam Bellaire
@Adam => 当然,Perl 中也可以做到同样的事情。我一直在考虑让通常毫无意义的 $overloaded == qr/.../$overloaded =~ /.../ 表现出相同的行为。至少在 5.10 之前这将起作用... - Eric Strom
1个回答

3
我觉得DSL最好用Perl中的源过滤器编写。你可以做任何你想做的事情。;-) 在你的例子中,你可以使用正则表达式将FOO =~ BAR替换为myfunc(FOO,BAR),并运行任意代码。
这里有一个示例解决方案:
# THE "MyLang" SOURCE FILTER
package MyLang;
use strict;
use warnings;
use Filter::Util::Call;

sub import {
    my ($type, @args) = @_;
    my %p = @args;
    no strict 'refs';
    my $caller = caller;
    # Create the function to call
    *{"${caller}::_mylang_defaultmethod"} = sub {
        my ($a, $op, $b) = @_;
        $p{nomethod}->($a, $b, 0, $op);
    };
    my ($ref) = [];
    filter_add(bless $ref);
}

sub filter {
    my ($self) = @_;
    my ($status);
    if ($status = filter_read() > 0) {
        $_ =~ s/([^=]+)(=~)([^;]+)/ _mylang_defaultmethod($1,'$2',$3)/g;
    }
    $status;
}

1;

例子使用

use MyLang nomethod => \&mywrap;

my $a = "foo";
my $b = "bar";
$x = $a =~ $b;

sub mywrap {
   my ($a, $b, $inv, $op) = @_;
   print "$a\n";
}

现在以上代码将打印出"foo\n",因为这是"$a"变量中的内容。当然,您可能希望对过滤器中的正则表达式替换进行一些稍微更智能的解析,但这只是一个简单的概念证明。

因为你在乒乓球方面很糟糕。 - mkoryak
通常情况下,源代码过滤器是一种脆弱的解决方案,特别是当过滤器具有上下文敏感边界时。您的示例在$x = $a =~ $b的情况下有效,但在$x = myfunc $a =~ $b的情况下会失败。这样的源代码过滤器存在太多的边角情况,以至于永远无法真正健壮。此外,如果您尝试编写源代码过滤器,您应该至少使用带有code_no_comments修饰符的Filter::Simple,以便仅过滤类似代码的区域,而不是注释、pod或引用字符串。 - Eric Strom
另外,一般来说,您应该避免将变量 $a$b 词法化,因为一旦词法化,在该作用域中对 sort 的任何调用都将失败。 - Eric Strom
这一切可能是真的,但他是唯一一个实际回答了问题的人。如果唯一的方法是通过源过滤器来完成,那么这是有用的信息。尽管如此,我承认它主要有用的是,如果你只能用源过滤器来完成它,也许你应该试着不用它。 ;) - Adam Bellaire
顺便说一句,我不是那个点踩的人,只是猜测为什么有人这样做。 - Eric Strom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接