Perl: возможно ли динамически исправить ошибку времени компиляции? - PullRequest
1 голос
/ 25 марта 2020

Если у меня есть, например, следующий perl сценарий:

use strict;
use warnings;

print $x;

При запуске этого сценария компиляция завершится с ошибкой:

Global symbol "$x" requires explicit package name (did you forget to declare "my $x"?) at ...

Is можно написать какой-нибудь модуль perl, который будет вызываться при возникновении этой ошибки, автоматически исправлять эту ошибку и продолжать компиляцию? (даже ссылки на любую информацию в порядке)

# This code is incorrect. 
# Here I just ask about such ability
# This code is very weak approximation how it might look
package AutoFix;

sub fix {
    $main::x =  'You are defined now';
}

1;

Итак, следующий код не подведет и напечатает You are defined now:

use strict;
use warnings;
use AutoFix;

print $x;

Ответы [ 2 ]

9 голосов
/ 25 марта 2020

Сколько работы вы хотели бы сделать, чтобы создать код, который мог бы выяснить, каким должно быть исправление? И будет ли этот объем работы сопоставим или меньше с работой, необходимой для проверки кода вручную?

Теперь я пишу все это, потратив немало времени, пытаясь придумать систему проанализировать вывод программы установки CPAN, чтобы выяснить, что пошло не так (основной стимул для CPANPLUS, теперь перенесенный в историю). Легко сказать, что что-то не так, но помимо этого много страданий.

В вашем примере у вас есть ошибка по поводу необъявленной переменной. Как AutoFix узнает, должен ли это быть пакет или лексическая переменная? Вы можете угадать одно или другое, но на самом деле у вас есть две большие проблемы:

  • Каков смысл кода?
  • Отражает ли код действительное намерение?

Определение смысла кода зачастую очень сложно даже для опытного программиста-человека выяснить (просто прочитайте комментарии к вопросу StackOverflow). Компиляция кода часто является неправильным кодом в том смысле, что он не дает желаемого результата. Кроме того, понимает ли программист проблему? Отражает ли код, написанный программистом (здесь неправильно), фактическую работу, которую должен выполнять код? В обзоре кода людям сложно понять это. Такие инструменты, как Coverity могут догадываться о проблемах, о которых он знает, но они не смогут исправить код.

Но допустим, что программист понимает проблему. Правильно ли они это выразили? По моему опыту, чем дольше вы программируете, тем больше вы склоняетесь к «нет».

Это полностью отличается от упомянутого вами ограничения базы данных. Это узконаправленное исправление для ожидаемой и разрешенной ситуации. Рассмотрим другую параллель: если запись содержит код города Нью-Йорка, но адрес Chica go, должен ли я указать город? Когда я был младше, я делал то же самое с базой данных. Это было глупо, потому что я думал, что знаю что-то, чего не знал, и все, кто понимал ситуацию, сразу это понимали. Даже тогда, эти виды ограничений - это то, как мы моделируем то, что мы знаем о мире, а не то, чем он является на самом деле.

Теперь, чтобы сделать AutoFix, вам нужно сделать что-то, что может смотреть на код, понимать его и выяснить, что он должен делать. Вы можете делать предположения, но у вас нет оснований для воспроизведения вероятностей там.

Технические вопросы не могут решить эту проблему. AutoFix может отменить работу прагм, так что некоторые классы ошибок не отображаются, но что с того? Программа с ошибкой просто продолжается? Как это кому-нибудь поможет?

Мало того, компиляторы склонны жаловаться, когда понимают, что не могут что-то проанализировать. То, на что они жалуются, часто не является проблемой. Первое, чему я учу людей во время отладки, это то, что им нужно посмотреть на оператор, сразу после номера строки в сообщении об ошибке. Любое сообщение об ошибке, которое вы ловите, может иметь практически бесконечное число причин.

Рассмотрим этот код, который не работает так же, как ваш пример (то же сообщение об ошибке), но по совершенно другой, но распространенной причине:

use strict;
use warnings;

my $x = 5,
print $x++;

Как выяснить, каким должно быть исправление? Речь не идет о том, чтобы объявить $x.

Итак, теперь у вас есть два случая, и вы создаете этот фиксатор. Затем вы сталкиваетесь с другим случаем, поэтому вы встраиваете его в себя. И продолжаете делать это до тех пор, пока не получите большой словарь исправлений. Может быть, вы немного сошли с ума и занялись машинным обучением (и не было бы здорово плохого кода и разрешений).

Но программа все равно не может продолжаться. Он должен начинаться сначала, потому что он должен по крайней мере вернуться туда, где он должен был что-то сделать, но не сделал этого Вы не можете просто перезапустить программу, потому что не знаете, является ли она идемпотентом. Повторный запуск программы может привести к тому, что она не будет работать, например, вставка дубликата в базы данных.

Сказав все это, подобные вещи связаны с анализом stati c и браузером рефакторинга 1038 *. Проект Адама Кеннеди Parse Perl Isolated (PPI) был первым шагом к пониманию кода Perl без его компиляции, а затем - к идеалу Smalltalk - пониманию того, какие части кода представляют одно и то же. Если бы вы знали, что две вещи с именем foo - это одно и то же, вы могли бы изменить код, работающий с foo. Например, если вы переименовали метод с bar на set_bar, вы могли бы сразу узнать, какие bar s вы должны переименовать, а какие принадлежали к другому классу.

Адам написал Acme: : BadExample и заставил любого запустить его. Он писал, что «любой данный фрагмент источника Perl существует в причудливом псевдоквантовоподобном состоянии, в котором он демонстрирует как дуальность, так и индетерминизм».

Джос Буманс подошел и использовал некоторые изгибающие ум Perl который он затем показал в Barely Legal XXX Perl, который, я думаю, он впервые представил в 2006 году. Он был удивительно креативен в своих решениях, и я не хотел бы этого в производственном коде.

Perl даже не знает, по какому типу, что будет в переменной, или даже что метод, который вы могли бы вызвать, будет существовать. На самом деле, он настолько сильно зависит от времени выполнения, полагая, что к тому времени, когда он вам понадобится, все будет готово, и мы часто говорим: «только Perl может проанализировать perl». Вы буквально должны иметь возможность запускать код Perl для его правильной компиляции, поскольку блоки BEGIN могут влиять на синтаксический анализ. Например, BEGIN может определять подпрограмму с определенной арностью. Как вы анализируете foo 5, 6? Вы должны знать, что уже было определено.

Perl имеет другие функции «действия на расстоянии», которые делают это еще более жестким. autodie переопределяет функции CORE для добавления дополнительного поведения, но вы не сможете увидеть это в коде. Вы можете установить флаги регулярных выражений по умолчанию (и я видел множество больших ошибок, когда люди применяли /isxm ко всем файлам без проверки).

0 голосов
/ 26 марта 2020

Как отмечалось выше, автоматическое исправление ошибки времени компиляции невозможно (или, вероятно, трудно исправить). Вместо исправления ошибки времени компиляции попробуйте решить вашу проблему другим способом.

Например. В вашем скрипте вы используете $x переменную. Возможно, вы знаете, что будете использовать его, и вы хотите получить экземпляр некоторого значения, например, You are defined now, тогда вы можете использовать Exporter:

use strict;
use warnings;

use AutoFix qw/ $x /;

print $x;

И AutoFix будет выглядеть так:

package AutoFix;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw( $x $y $z );  # symbols to export on request

... # code which will create instance of $x $y $z on request

1;

Гул удачи; -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...