Подтвердить что ты не робот

Есть ли способ перегрузить оператор привязки regex `= ~` в Perl?

Я работаю над небольшим DSL, который использует резервную копию nomethod для перегрузки для захвата операторов, используемых для перегруженных значений. Это похоже на функцию символического калькулятора , описанного в документации overload.

Это отлично подходит для стандартных операторов сравнения, но учтите следующее:

my $ret = $overloaded =~ /regex/;

В этом случае nomethod вызывается для строки $overloaded, после чего перегрузка теряется. Я думал о возврате привязанной переменной, которая, по крайней мере, позволит мне переносить оригинальный перегруженный объект, но это все равно будет потеряно во время выполнения регулярного выражения.

Итак, конечный вопрос заключается в том, есть ли способ расширить идею overload символического калькулятора, чтобы включить операторы привязки regex =~ и !~, чтобы приведенный выше пример кода вызывал nomethod с ($overloaded, qr/regex/, 0, '=~') или что-то подобное?

Я также кратко рассмотрел перегрузку оператора smartmatch ~~, но это тоже не показалось трюком (всегда по умолчанию используется соответствие регулярному выражению, а не перегрузка).

Изменить: я просмотрел еще ~~ и обнаружил, что my $ret = $overloaded ~~ q/regex/ работает из-за правил smartmatching. Закрыть, но не идеальное решение, и я бы хотел, чтобы он работал до 5.10, поэтому я приветствую другие ответы.

4b9b3361

Ответ 1

Мне кажется, что DSL лучше всего писать с помощью исходных фильтров в perl. Вы можете буквально делать ВСЕ, что хотите.;-) В вашем примере вы можете regex заменить 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". Конечно, вам может понадобиться немного более интеллектуальный синтаксический анализ для замены регулярных выражений в фильтре, но это простое доказательство концепции.