Por que este programa é válido? Eu estava tentando criar um erro de sintaxe

489

Estou executando o ActivePerl 5.14.2 de 32 bits do ActiveState no Windows 7. Eu queria mexer com um gancho de pré-confirmação do Git para detectar programas sendo verificados com erros de sintaxe. (De alguma forma, eu apenas consegui fazer um commit tão ruim.) Então, como programa de teste, anotei isso aleatoriamente:

use strict;
use warnings;

Syntax error!

exit 0;

No entanto, ele compila e executa sem avisos e o nível de erro é zero na saída. Como essa sintaxe é válida?

Bill Ruppert
fonte
121
Você acabou de provar que digitar palavras aleatórias no perl produz programas de trabalho ??!?!?!?!
11556 Peter M em
10
@PeterM Palavras pouco aleatórias. Eu provei que não sei o suficiente sobre a sintaxe Perl. Agora eu sei um pouco mais.
Bill Ruppert
10
Você provavelmente vai querer no indirectparar aqueles aconteça
LeoNerd
@LeoNerd Obrigado pela dica!
Bill Ruppert
1
Esta é a pergunta perl mais famosa de todos os tempos. Ainda melhor como o trecho de Schwartz :whatever / 25 ; # / ; die "this dies!";
jm666 6/17/17

Respostas:

540

Perl tem uma sintaxe chamada "notação indireta de método". Permite

Foo->new($bar)

para ser escrito como

new Foo $bar

Então, isso significa

Syntax error ! exit 0;

é o mesmo que

error->Syntax(! exit 0);

ou

error->Syntax(!exit(0));

Não é apenas uma sintaxe válida, mas não resulta em um erro de tempo de execução, porque a primeira coisa executada é exit(0).

ikegami
fonte
1
@Hassan, por quê? É seguido por uma expressão.
Ikegami
3
Cheguei a ler como "Erro de sintaxe! Saída 0;", mas não pensei em invocação indireta. Passou muito tempo esquecendo isso!
Bill Ruppert
6
@ Hassan, pense desta maneira, !exit(0)não pode mais ser um erro de tipo do que !$xuma vez que nenhum deles é digitado.
Ikegami
11
@ Hasan, o idioma tem tipos. Especificamente, os valores têm tipos. Operadores e subs simplesmente não se limitam a retornar tipos específicos de valores. Isso acaba sendo muito útil a baixo custo (graças a avisos).
Ikegami
6
@ Nawaz, é realmente bastante popular. É usado por todos que constroem objetos em Java e C ++, e um grande corpo de programadores Perl que usa new Classe print $fh ...não Class->new(...)e $fh->print(...). Eu vou garantir que isso causa uma estranha mensagem de erro, #
ikegami
112

Não sei por que, mas é isso que Perl faz disso:

perl -MO=Deparse -w yuck
BEGIN { $^W = 1; }
use warnings;
use strict 'refs';
'error'->Syntax(!exit(0));
yuck syntax OK

Parece que o analisador pensa que você está chamando o método Syntaxno errorobjeto-... Estranho mesmo!

pavel
fonte
3
Essa é a sintaxe indireta de chamada de método. Ele está trabalhando aqui porque exit(0)é avaliado primeiro, fazendo com que o programa saia antes de tentar passar o resultado 'error'->Syntax().
duskwuff -inactive-
6
Perl parece assumir a "sintaxe indireta (objeto)", geralmente usada como ao new Classinvés de Class->new(). Para chamar o método Syntax, a exitfunção é executada, para que o erro em tempo de execução nunca ocorra.
amon
118
Parabéns. Você encontrou um programa em que precisa adicionar um ponto-e-vírgula para que a compilação falhe.
mob
use strict; use warnings; error->Syntax(! print "hi"); Rende: Sintaxe Ok no perl -MO = Deparse também, mas use warningsprovavelmente deve dizer algo, pois pode descobrir que não está sendo carregado. Em vez disso, gera um erro de tempo de execução "Não é possível localizar o método do objeto ..".
53

O motivo de você não receber um erro é que o primeiro código executado é

exit(0);

Porque você não tinha ponto e vírgula na primeira linha:

Syntax error!

O compilador adivinhará (incorretamente) que se trata de uma chamada de sub-rotina com um notoperador !acionado. Em seguida, ele executará os argumentos dessa sub-rotina, o que acontece exit(0), quando o programa sai e define o nível de erro como 0. Nada mais é executado. , para que não sejam relatados mais erros de tempo de execução.

Você notará que se você mudar exit(0)para algo como esse print "Hello world!", receberá um erro:

Can't locate object method "Syntax" via package "error" ...

e seu nível de erro será definido:

> echo %errorlevel%
255
TLP
fonte
7
>The compiler will guess (incorrectly) O compilador não pode fazer nada incorretamente.
Liam Laverty
14
@LiamLaverty Sim, pode. Pode adivinhar incorretamente o que o humano queria dizer.
TLP
4
O humano é o incorreto na equação. O compilador só pode estar "correto" ou "quebrado". Não obtém uma opinião sobre a definição do idioma ou a intenção do usuário.
Liam Laverty
4
@LiamLaverty Seria um compilador bem organizado se pudesse adivinhar a intenção do usuário nesse caso, sim. Portanto, o compilador não pode adivinhar corretamente. Você pode estar fazendo uma análise de jargão técnico da minha afirmação, que é, devo acrescentar, a maneira incorreta de lê-la.
TLP
Não é um interpretador? ;-)
Rikki
33

Como observado acima, isso é causado pelo método indireto que chama a notação. Você pode alertar sobre isso:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Produz:

Indirect call of method "Syntax" on object "error" at - line 5.

Isso requer o módulo CPAN indireto .

Você também pode usar no indirect "fatal";para causar a morte do programa (é isso que eu faço)

Mark Fowler
fonte
8

Tente o Perl 6 , ele parece atender às suas expectativas mais rapidamente:

===SORRY!=== Error while compiling synerror.p6
Negation metaoperator not followed by valid infix
at synerror.p6:1
------> Syntax error!⏏<EOL>
    expecting any of:
        infix
        infix stopper
Moritz
fonte
1

Neste artigo , nosso objetivo é responder a um problema aberto de longa data na comunidade de linguagens de programação: é possível manchar a tinta na parede sem criar Perl válido?

TLDR; Dificilmente

Holli
fonte
Eu amo isso. Talvez eu precise digitalizar algumas fotos.
Bill Ruppert