Как я могу ввести несколько строк с помощью Devel:: Declare?

Я хочу использовать Devel::Declare для ввода нескольких строк кода Perl. Однако Devel::Declare::set_linestr() не может иметь дело с несколькими строками.

Обычно я хотел бы объединить несколько операторов вместе как одну строку. Эти утверждения должны быть в отдельных строках, чтобы сохранить номера строк для целей сообщения об ошибках. Это необходимо решить эту ошибку в методе:: Подписи и эта связанная ошибка. Я открыт для альтернативных решений.

Например, метод:: Signatures в настоящее время включает этот код...

use Method::Signatures;

func hello(
    $who = "World",
    $greeting = get_greeting($who)
) {
    die "$greeting, $who";
}

... в это...

func  \&hello; sub hello  { BEGIN { Method::Signatures->inject_scope('') }; my $who = (@_ > 0) ? ($_[0]) : ( get_greeting($who)); my $greeting = (@_ > 1) ? ($_[1]) : ( "Hello"); Method::Signatures->too_many_args_error(2) if @_ > 2;
    die "$greeting, $who";
}

die $who после этого сообщает строку 4 вместо строки 7.

Я бы хотел, чтобы это было вместо этого (или, возможно, с участием #line).

func  \&hello; sub hello  { BEGIN { Method::Signatures->inject_scope('') };
    my $who = (@_ > 0) ? ($_[0]) : ( "World");
    my $greeting = (@_ > 1) ? ($_[1]) : ( get_greeting($who));
    Method::Signatures->too_many_args_error(2) if @_ > 2;
    die "$greeting, $who";
}

Не только это верно воспроизводит номера строк, если get_greeting сжимает, он будет сообщать, что был вызван из правильной строки.

Ответы

Ответ 1

В соответствии с вашим собственным ответом, следующие работы:

sub __empty() { '' }

sub parse_proto {
    my $self = shift;
    return q[print __LINE__."\n"; Foo::__empty(
);print __LINE__."\n"; Foo::__empty(
);print __LINE__."\n";];
}

Но вводит неприемлемые служебные данные, потому что функция __empty() должна вызываться для каждого параметра. Накладные расходы можно устранить, вызвав __empty() условно, используя условие, которое никогда не будет оцениваться как true.

sub __empty() { '' }

sub parse_proto {
    my $self = shift;
    return q[print __LINE__."\n"; 0 and Foo::__empty(
);print __LINE__."\n"; 0 and Foo::__empty(
);print __LINE__."\n";];
}

Ответ 2

Я понял способ сделать это, но он взломан и медленный.

Я заметил, что вы можете вводить строки с буквальными символами новой строки в них, и они будут работать. Я считаю, что синтаксический анализатор знает достаточно, чтобы продолжать следовать за новой строкой в ​​строке. Я решил, что можно использовать это, чтобы обмануть парсер, чтобы он продолжал идти.

package Foo;

use strict;
use warnings;
use v5.12;

use parent "Devel::Declare::MethodInstaller::Simple";

sub import {
    my $class = shift;
    my $caller = caller;

    $class->install_methodhandler(
        into            => $caller,
        name            => 'method'
    );
}

sub parse_proto {
    my $self = shift;
    return q[print __LINE__."\n"; my $__empty = q{
};print __LINE__."\n"; $__empty = q{
};print __LINE__."\n";];
}

1;

И он работает... кроме __LINE__ не увеличивается. Сбой в Perl-парсере? Я попробовал регулярное выражение с новой строкой в ​​нем, которая также не увеличивала строку.

Но работает подпрограмма!

sub __empty() { '' }

sub parse_proto {
    my $self = shift;
    return q[print __LINE__."\n"; Foo::__empty(
);print __LINE__."\n"; Foo::__empty(
);print __LINE__."\n";];
}

И это постоянный вызов подпрограммы, Perl должен оптимизировать его, правильно? Увы, нет. Кажется, что новая линия в вызове обманывает оптимизатора. С другой стороны, это предотвращает предупреждение "Бесполезное использование константы в пустоте". С нижней стороны он вводит вызов подпрограммы для каждого параметра и недопустимое количество служебных данных для добавления к каждому вызову подпрограммы.

Может кто-то может придумать умный способ проклинать новую строку в синтаксисе Perl?