Dlaczego ten program jest ważny? Próbowałem utworzyć błąd składniowy

489

Korzystam z 32-bitowej wersji ActivePerl 5.14.2 ActiveState w systemie Windows 7. Chciałem zadzierać z hakiem wstępnego zatwierdzania Git, aby wykryć programy sprawdzane z błędami składniowymi. (Jakimś cudem udało mi się zrobić tak złe zatwierdzenie.) Tak więc jako program testowy losowo zanotowałem:

use strict;
use warnings;

Syntax error!

exit 0;

Jednak kompiluje się i wykonuje bez ostrzeżeń, a poziom błędu wynosi zero przy wyjściu. Jaka jest ta poprawna składnia?

Bill Ruppert
źródło
121
Czy właśnie udowodniłeś, że wpisanie losowych słów w perlu tworzy działające programy ??!?!?!?!
Peter M,
10
@PeterM Trudne losowe słowa. Udowodniłem, że nie wiem wystarczająco dużo o składni Perla. Teraz wiem trochę więcej.
Bill Ruppert,
10
Prawdopodobnie chcesz no indirectpowstrzymać te wydarzenia
LeoNerd
@LeoNerd Dzięki za wskazówkę!
Bill Ruppert,
1
To najsłynniejsze pytanie perla w historii. Jeszcze lepiej niż fragment Schwartza :whatever / 25 ; # / ; die "this dies!";
jm666

Odpowiedzi:

540

Perl ma składnię zwaną „notacją metod pośrednich”. To pozwala

Foo->new($bar)

pisać jako

new Foo $bar

Wiec to znaczy

Syntax error ! exit 0;

jest taki sam jak

error->Syntax(! exit 0);

lub

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

Jest to nie tylko poprawna składnia, ale nie powoduje błędu w czasie wykonywania, ponieważ pierwszą rzeczą jest wykonanie exit(0).

ikegami
źródło
1
@Hassan, dlaczego? Po nim następuje wyrażenie.
ikegami
3
Dotarłem tak daleko jak „Błąd składniowy! Wyjście 0;”, ale nie myślałem o wywołaniu pośrednim. Spędziłem dużo czasu zapominając o tym!
Bill Ruppert
6
@Hassan, Pomyśl o tym w ten sposób, !exit(0)nie może być większym błędem niż, !$xponieważ żaden z nich nie jest wpisany.
ikegami
11
@Hassan, Język ma typy. W szczególności wartości mają typy. Operatory i podwodne po prostu nie ograniczają się do zwracania określonych typów wartości. To okazuje się bardzo przydatne przy niewielkich kosztach (dzięki ostrzeżeniom).
ikegami
6
@Nawaz, w rzeczywistości jest dość popularny. Jest używany przez wszystkich, którzy konstruują obiekty w Javie i C ++, oraz dużą grupę programistów Perla, którzy używają new Classi print $fh ...zamiast Class->new(...)i $fh->print(...). Przyznaję, że powoduje to dziwne komunikaty o błędach
ikegami,
112

Nie wiem dlaczego, ale właśnie to robi Perl:

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

Wygląda na to, że parser myśli, że wywołujesz metodę Syntaxna error-object ... Dziwne!

pavel
źródło
3
To jest pośrednia składnia wywołania metody. Działa tutaj (poniekąd), ponieważ exit(0)najpierw jest oceniany, co powoduje, że program kończy działanie, zanim spróbuje przekazać wynik 'error'->Syntax().
duskwuff -inactive-
6
Perl wydaje się zakładać „składnię pośrednią (obiektową)”, zwykle używaną jak new Classzamiast Class->new(). Aby wywołać metodę Syntax, exitfunkcja jest wykonywana, więc błąd czasu wykonania nigdy nie występuje.
amon
118
Gratulacje. Znalazłeś program, w którym musisz dodać średnik, aby kompilacja zakończyła się niepowodzeniem.
tłum
use strict; use warnings; error->Syntax(! print "hi"); Wydajność: Składnia Ok na perlu -MO = Deparse również, ale z use warningstym powinien prawdopodobnie coś powiedzieć, ponieważ może dowiedzieć się, że nie jest ładowany. Zamiast tego generuje błąd czasu wykonywania „Nie można zlokalizować metody obiektu ..”.
53

Powodem, dla którego nie pojawia się błąd, jest to, że pierwszy wykonany kod to

exit(0);

Ponieważ w pierwszym wierszu nie było średnika:

Syntax error!

Kompilator zgadnie (niepoprawnie), że jest to wywołanie podprogramu z wrzuconym notoperatorem !. Następnie wykona argumenty tego podprogramu, który akurat jestexit(0) , w którym to momencie program kończy działanie i ustawia poziom błędu na 0. Nic innego nie jest wykonywane , więc nie są zgłaszane więcej błędów środowiska wykonawczego.

Zauważysz, że jeśli zmienisz exit(0)na coś takiego print "Hello world!", pojawi się błąd:

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

a Twój poziom błędu zostanie ustawiony:

> echo %errorlevel%
255
TLP
źródło
7
>The compiler will guess (incorrectly) Kompilator nie może nic zrobić niepoprawnie.
Liam Laverty,
14
@LiamLaverty Tak, może. Może błędnie zgadywać, co człowiek miał na myśli.
TLP,
4
Człowiek jest niewłaściwy w równaniu. Kompilator może być tylko „poprawny” lub „uszkodzony”. Nie otrzymuje opinii na temat definicji języka ani intencji użytkownika.
Liam Laverty,
4
@LiamLaverty Byłoby to całkiem fajny kompilator, gdyby mógł odgadnąć zamiar użytkownika w tym przypadku, tak. Dlatego kompilator nie może poprawnie zgadnąć. Być może robisz techniczną analizę żargonu mojej wypowiedzi, co jest, dodam, niewłaściwym sposobem jej odczytania.
TLP
Czy to nie jest tłumacz ustny? ;-)
Rikki
33

Jak wspomniano powyżej, jest to spowodowane notacją wywołującą metodę pośrednią. Możesz ostrzec o tym:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Produkuje:

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

Wymaga to pośredniego modułu CPAN .

Możesz także użyć, no indirect "fatal";aby spowodować śmierć programu (to właśnie robię)

Mark Fowler
źródło
8

Wypróbuj Perl 6 , wydaje się, że łatwiej spełnia twoje oczekiwania:

===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
źródło
1

W tym artykule chcemy odpowiedzieć na od dawna otwarty problem społeczności języków programowania: czy można rozmazać farbę na ścianie bez tworzenia prawidłowego Perla?

TLDR; Ledwie

Holli
źródło
Uwielbiam to. Być może będę musiał zeskanować niektóre zdjęcia.
Bill Ruppert