Как реализуются прагмы Perl с лексической областью видимости?
-
13-12-2019 - |
Вопрос
Прагмы, как autodie
, согласно документации, имеют лексическую область видимости.
{
use autodie;
..
..
}
# Can die here
Это относится ко всем модулям, загруженным с use
?Насколько я знаю, use
почти то же самое, что:
BEGIN {
require autodie;
autodie->import(LIST);
}
BEGIN
происходит во время компиляции, и require не имеет лексической области видимости.Так как autodie
осознаете его масштаб?
Решение
Короткий ответ: лексическая область видимости прагматические модули явно написаны для такого поведения и используют магические внутренние переменные $^H
и %^H
во время компиляции для включения и отключения функций.
Компилятор играет свою роль, неявно локализуя эти переменные, чтобы их значение восстанавливалось в конце компиляции блока кода до того, которое было в начале.Таким образом, он обеспечивает основу лексической семантики.
Первоначально только $^H
переменная была доступна.Он содержит битовую маску, которая определяет, какие параметры компилятора доступны в любой момент компиляции.По этой причине единственными лексическими прагмами, которые можно было написать, были те, которые манипулировали определенным набором магических битов в $^H
.
Позже %^H
был введен хеш, и теперь любая прагма может хранить значения в этом хэше с ключами, начинающимися с имени прагмы.Поскольку компилятор локализует хэш так же, как и скаляр, любая прагма может хранить здесь информацию о статусе с автоматически ограниченной областью действия.
А autodie
модуль не манипулирует ни одной из этих переменных, а создает подклассы Fatal
модуль, который делает всю тяжелую работу.Оно использует %^H
чтобы отслеживать, какие операторы стали фатальными, и полагается на то, что компилятор отбрасывает эту информацию в конце блока.
Другие советы
Из метода импорта Fatal.pm
который является серверной частью autodie
, наслаждайся:
# Dark magic to have autodie work under 5.8
# Copied from namespace::clean, that copied it from
# autobox, that found it on an ancient scroll written
# in blood.
# This magic bit causes %^H to be lexically scoped.
$^H |= 0x020000;
Итак, ответ заключается в том, что действительно существует способ сделать ваш импорт осведомленным об их лексической области, но он глубоко связан с внутренностями Perl и не предназначен для использования обычными программистами.
Это не require
Это интересно;это то, что делает прагма import
.
Большинство (все?) прагм используют $^H
или %^H
.Анализатор локализует их в анализируемой области, то есть восстанавливает их значение, которое они имели раньше.
Брать строгий, например.Его import
изменяет $^H
. $^H
содержит ряд флагов, которые указывают компилятору, как себя вести.
$ perl -e'
BEGIN { printf "%04X\n", $^H }
{
use strict;
BEGIN { printf "%04X\n", $^H }
}
BEGIN { printf "%04X\n", $^H }
'
0100
0702
0100
$^H
зарезервировано для использования в Perl, но аналогично локализовано %^H
доступен для общего пользования.Например, функция::qw_comment подключается к парсеру один раз, когда он загружается require
, но ничего не делает, если только $^H{'feature::qw_comments::'}
правда.Его импорт эквивалентен
sub import { $^H{'feature::qw_comments::'} = 1; }