Perché questo programma è valido? Stavo cercando di creare un errore di sintassi


489

Sto eseguendo ActivePerl 5.14.2 a 32 bit di ActiveState su Windows 7. Volevo scherzare con un hook pre-commit Git per rilevare i programmi che venivano registrati con errori di sintassi. (In qualche modo sono appena riuscito a fare un così cattivo commit.) Quindi come programma di test ho annotato casualmente questo:

use strict;
use warnings;

Syntax error!

exit 0;

Tuttavia, viene compilato ed eseguito senza avvisi e il livello di errore è zero all'uscita. Come è valida questa sintassi?


121
Hai appena dimostrato che la digitazione di parole casuali in perl produce programmi di lavoro ??!?!?!?!
Peter M,

10
@PeterM Parole quasi casuali. Ho dimostrato di non conoscere abbastanza la sintassi del Perl. Ora ne so un po 'di più.
Bill Ruppert,

10
Probabilmente vuoi no indirectimpedire che
accadano

@LeoNerd Grazie per la punta!
Bill Ruppert,

1
Questa è la domanda perl più famosa di sempre. Ancora meglio come frammento di Schwartz :whatever / 25 ; # / ; die "this dies!";
jm666

Risposte:


540

Perl ha una sintassi chiamata "notazione del metodo indiretto". Permette

Foo->new($bar)

essere scritto come

new Foo $bar

Quindi questo significa

Syntax error ! exit 0;

equivale a

error->Syntax(! exit 0);

o

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

Non è solo una sintassi valida, non provoca un errore di runtime perché la prima cosa eseguita è exit(0).


1
@Hassan, Why? È seguito da un'espressione.
ikegami,

3
Sono arrivato a leggerlo come "Errore di sintassi! Exit 0;", ma non ho pensato all'invocazione indiretta. Ho passato molto tempo a dimenticarlo!
Bill Ruppert,

6
@Hassan, pensala in questo modo, !exit(0)non può più essere un errore di tipo rispetto a !$xquando nessuno dei due viene digitato.
ikegami,

11
@Hassan, la lingua ha tipi. In particolare, i valori hanno tipi. Operatori e sottotitoli non si limitano semplicemente a restituire tipi specifici di valori. Questo risulta essere molto utile a basso costo (grazie agli avvisi).
ikegami,

6
@Nawaz, In realtà è abbastanza popolare. È usato da tutti coloro che costruiscono oggetti in Java e C ++ e da un gran numero di programmatori Perl che usa new Classe print $fh ...invece di Class->new(...)e $fh->print(...). Ti garantirò che provoca strani messaggi di errore
ikegami,

112

Non so perché, ma questo è ciò che Perl ne fa:

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

Sembra che il parser pensa che stai chiamando il metodo Syntaxsul error-oggetto ... Strano davvero!


3
Questa è la sintassi della chiamata del metodo indiretto. Funziona (in un certo senso) qui perché exit(0)viene valutato per primo, facendo uscire il programma prima di provare a passare il risultato 'error'->Syntax().
duskwuff -inattivo-

6
Perl sembra assumere la "sintassi indiretta (oggetto)", di solito usata come new Classinvece di Class->new(). Per chiamare il metodo Syntax, la exitfunzione viene eseguita, quindi l'errore di runtime non si verifica mai.
Amon,

118
Congratulazioni. Hai trovato un programma in cui devi aggiungere un punto e virgola per far fallire la compilazione.
mob

use strict; use warnings; error->Syntax(! print "hi"); Rese: Sintassi Ok su perl -MO = Deparse pure, ma con use warningsesso probabilmente dovrebbe dire qualcosa dal momento che può capire che non viene caricato. Invece genera un errore di runtime "Impossibile individuare il metodo oggetto ..".

53

Il motivo per cui non si ottiene un errore è che il primo codice eseguito è

exit(0);

Perché non avevi un punto e virgola sulla prima riga:

Syntax error!

Il compilatore indovinerà (erroneamente) che si tratta di una chiamata di subroutine con un notoperatore !inserito. Quindi eseguirà gli argomenti di questa subroutine, che risulta essere exit(0), a quel punto il programma esce e imposta il livello di errore su 0. Nient'altro viene eseguito , quindi non vengono segnalati più errori di runtime.

Noterai che se cambi exit(0)in qualcosa del genere print "Hello world!"ricevi un errore:

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

e il tuo livello di errore verrà impostato:

> echo %errorlevel%
255

7
>The compiler will guess (incorrectly) Il compilatore non può fare nulla in modo errato.
Liam Laverty

14
@LiamLaverty Sì, può. Può indovinare in modo errato cosa intendesse l'essere umano.
TLP

4
L'umano è quello errato nell'equazione. Il compilatore può essere solo "corretto" o "rotto". Non ottiene un'opinione sulla definizione della lingua o sull'intenzione di un utente.
Liam Laverty

4
@LiamLaverty Sarebbe un compilatore piuttosto accurato se potesse indovinare l'intenzione dell'utente in questo caso, sì. Quindi, il compilatore non può indovinare correttamente. Potresti fare alcune analisi gergali tecniche della mia affermazione, che è, potrei aggiungere, il modo errato di leggerlo.
TLP

Non è un interprete? ;-)
Rikki

33

Come notato sopra, ciò è causato dal metodo indiretto che chiama notazione. Puoi avvertire su questo:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

produce:

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

Ciò richiede il modulo CPAN indiretto .

Puoi anche usarlo no indirect "fatal";per far morire il programma (questo è quello che faccio)


8

Prova Perl 6 , sembra soddisfare le tue aspettative più facilmente:

===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

1

In questo documento , miriamo a rispondere a un problema aperto di vecchia data nella comunità dei linguaggi di programmazione: è possibile spalmare la vernice sul muro senza creare un Perl valido?

TLDR; quasi


Lo amo. Potrei dover scansionare alcune immagini.
Bill Ruppert,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.