Документация для встраивания встроенных модулей?
Я столкнулся с ситуацией, когда я не могу сдерживать предупреждения интуитивно, потому что perl вставляет вызов встроенной функции. например.
use strict;
use warnings;
{
no warnings 'substr'; # no effect
foo(substr('123', 4, 6)); # out of range but shouldn't emit a warning
}
sub foo {
my $s = shift; # warning reported here
# do something
}
Запуск этого кода приводит к
substr outside of string at c:\temp\foo.pl line 10.
Чтобы заблокировать предупреждение, мне нужно переместить no warnings 'substr'
внутри функции.
sub foo {
no warnings 'substr'; # works here, but there no call to substr
my $s = shift; # no warnings here
# do something
}
Я вижу, что вызов substr
встраивается путем передачи кода через perl -MO=Terse
LISTOP (0x27dcaa8) leave [1]
OP (0x27a402c) enter
COP (0x27dcac8) nextstate
BINOP (0x27dcb00) leaveloop
LOOP (0x27dcb20) enterloop
LISTOP (0x27dcb68) lineseq
COP (0x27dcb88) nextstate
UNOP (0x27dcbc0) entersub [5] # entry point for foo
UNOP (0x27dcbf4) null [148]
OP (0x27dcbdc) pushmark
LISTOP (0x27dcc48) substr [4] # substr gets called here
OP (0x27dcc30) null [3]
SVOP (0x27dcc84) const [6] PV (0x2319944) "123"
SVOP (0x27dcc68) const [7] IV (0x2319904) 4
SVOP (0x27dcc14) const [8] IV (0x231944c) 6
UNOP (0x27dcca0) null [17]
PADOP (0x27dccf4) gv GV (0x2318e5c) *foo
Является ли это поведение оптимизатора документированным где угодно? perlsub
только упоминает вложение постоянных функций. Учитывая, что предупреждение сообщается в неправильной строке и что no warnings
не работает в лексической области, где выполняется вызов, я склонен сообщать об этом как об ошибке, хотя я не могу придумать, как это сделать может быть разумно исправлена при сохранении оптимизации.
Примечание. Это поведение наблюдалось в Perl 5.16.1.
Ответы
Ответ 1
Как вы видели из B:: Terse, substr
не встроен.
$ perl -MO=Concise,-exec -e'f(substr($_, 3, 4))'
1 <0> enter
2 <;> nextstate(main 1 -e:1) v:{
3 <0> pushmark s
4 <#> gvsv[*_] s
5 <$> const[IV 3] s
6 <$> const[IV 4] s
7 <@> substr[t4] sKM/3 <-- The substr operator is evaluated first.
8 <#> gv[*f] s/EARLYCV
9 <1> entersub[t5] vKS/TARG <-- The sub call second.
a <@> leave[1 ref] vKP/REFC
-e syntax OK
Когда substr
вызывается как контекст lvalue, substr
возвращает волшебный скаляр, содержащий операнды, переданные в substr
.
$ perl -MDevel::Peek -e'$_ = "abcdef"; Dump(${\ substr($_, 3, 4) })'
SV = PVLV(0x2865d60) at 0x283fbd8
REFCNT = 2
FLAGS = (GMG,SMG) <--- Gets and sets are magical.
IV = 0 GMG: A function that mods the scalar
NV = 0 is called before fetches.
PV = 0 SMG: A function is called after the
MAGIC = 0x2856810 scalar is modified.
MG_VIRTUAL = &PL_vtbl_substr
MG_TYPE = PERL_MAGIC_substr(x)
TYPE = x
TARGOFF = 3 <--- substr second arg
TARGLEN = 4 <--- substr third arg
TARG = 0x287bfd0 <--- substr first arg
FLAGS = 0
SV = PV(0x28407f0) at 0x287bfd0 <--- A dump of substr first arg
REFCNT = 2
FLAGS = (POK,IsCOW,pPOK)
PV = 0x2865d20 "abcdef"\0
CUR = 6
LEN = 10
COW_REFCNT = 1
Аргументы подпрограммы вычисляются в контексте lvalue, потому что аргументы подпрограммы всегда передаются по ссылке в Perl [1].
$ perl -E'sub f { $_[0] = "def"; } $x = "abc"; f($x); say $x;'
def
Операция подстроки происходит при доступе к магическому скаляру.
$ perl -E'$x = "abc"; $r = \substr($x, 0, 1); $x = "def"; say $$r;'
d
Это сделано, чтобы разрешить substr(...) = "abc";
- Это, вероятно, документировано с использованием языка, подобного следующему: "Элементы
@_
сглажены аргументам подпрограммы".
Ответ 2
Это документированное поведение (в perldiag):
substr вне строки
(W substr), (F) Вы пытались ссылаться на substr(), который указывал вне строки. То есть абсолютное значение смещения было больше длины строки. См. "Substr" в perlfunc. Это предупреждение является фатальным, если substr используется в контексте lvalue (как в левой части задания или в качестве аргумента подпрограммы для пример).
Акцент на мой.
Изменение вызова на
foo(my $o = substr('123', 4, 6));
приводит к исчезновению предупреждений.
Перемещение no warnings
в sub не меняет поведения для меня. Какая версия Perl у вас есть? (5.14.4 здесь).
Код, который я использовал для тестирования:
#!/usr/bin/perl
use strict;
use warnings;
$| = 1;
print 1, foo(my $s1 = substr('abc', 4, 6));
print 2, bar(my $s2 = substr('def', 4, 6));
{
no warnings 'substr';
print 3, foo(my $s3 = substr('ghi', 4, 6));
print 4, bar(my $s4 = substr('jkl', 4, 6));
print 5, bar(substr('mno', 4, 6)); # Stops here, reports line 12.
print 6, foo(substr('pqr', 4, 6));
}
print "ok\n";
sub foo {
my $s = shift;
}
sub bar {
no warnings 'substr';
my $s = shift;
}
Обновление:
Я получаю то же поведение в 5.10.1, но в 5.20.1 поведение такое, как вы описали.