Pourquoi ce programme est-il valable? J'essayais de créer une erreur de syntaxe

489

J'exécute ActivePerl 5.14.2 32 bits d' ActiveState sur Windows 7. Je voulais jouer avec un crochet de pré-validation Git pour détecter les programmes en cours d'enregistrement avec des erreurs de syntaxe. (D'une manière ou d'une autre, j'ai juste réussi à faire un mauvais commit.) Donc, en tant que programme de test, j'ai noté au hasard ceci:

use strict;
use warnings;

Syntax error!

exit 0;

Cependant, il compile et s'exécute sans avertissement et le niveau d'erreur est nul à la sortie. Comment est cette syntaxe valide?

Bill Ruppert
la source
121
Vous venez de prouver que taper des mots aléatoires en perl produit des programmes de travail ??!?!?!?!
Peter M
10
@PeterM Mots peu aléatoires. J'ai prouvé que je ne connaissais pas assez la syntaxe Perl. Maintenant j'en sais un peu plus.
Bill Ruppert
10
Vous voulez probablement no indirectempêcher ces événements de se produire
LeoNerd
@LeoNerd Merci pour le conseil!
Bill Ruppert
1
C'est la question Perl la plus connue de tous les temps. Encore mieux que l'extrait de Schwartz :whatever / 25 ; # / ; die "this dies!";
jm666

Réponses:

540

Perl a une syntaxe appelée "notation de méthode indirecte". Il permet

Foo->new($bar)

être écrit comme

new Foo $bar

Donc ça signifie

Syntax error ! exit 0;

est le même que

error->Syntax(! exit 0);

ou

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

Non seulement sa syntaxe est valide, mais elle n'entraîne pas d'erreur d'exécution car la première chose exécutée est exit(0).

ikegami
la source
1
@Hassan, pourquoi? Elle est suivie d'une expression.
ikegami
3
Je suis allé jusqu'à le lire comme "Erreur de syntaxe! Exit 0;", mais je n'ai pas pensé à l'invocation indirecte. J'ai passé beaucoup de temps à oublier ça!
Bill Ruppert
6
@Hassan, Pensez-y de cette façon, !exit(0)ne peut pas plus être une erreur de type que !$xpuisque ni l'un ni l'autre ne sont tapés.
ikegami
11
@Hassan, La langue a des types. Plus précisément, les valeurs ont des types. Les opérateurs et les sous-marins ne sont tout simplement pas limités à renvoyer des types de valeurs spécifiques. Cela s'avère très utile à peu de frais (grâce aux avertissements).
ikegami
6
@Nawaz, c'est en fait assez populaire. Il est utilisé par tous ceux qui construisent des objets en Java et C ++, et par un grand nombre de programmeurs Perl qui utilisent new Classet print $fh ...au lieu de Class->new(...)et $fh->print(...). Je vous accorde que cela provoque des messages d'erreur étranges, cependant
ikegami
112

Je ne sais pas pourquoi, mais c'est ce que Perl en fait:

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

Il semble que l'analyseur pense que vous appelez la méthode Syntaxsur le error-object ... Étrange en effet!

pavel
la source
3
C'est la syntaxe d'appel de méthode indirecte. Cela fonctionne (en quelque sorte) ici car le exit(0)est évalué en premier, ce qui fait que le programme se termine avant d'essayer de transmettre le résultat à 'error'->Syntax().
duskwuff -inactive-
6
Perl semble assumer la "syntaxe indirecte (objet)", généralement utilisée comme new Classau lieu de Class->new(). Pour appeler la méthode Syntax, la exitfonction est exécutée, donc l'erreur d'exécution ne se produit jamais.
amon
118
Toutes nos félicitations. Vous avez trouvé un programme dans lequel vous devez ajouter un point-virgule pour que la compilation échoue.
mob
use strict; use warnings; error->Syntax(! print "hi"); Donne: Syntaxe Ok sur perl -MO = Deparse aussi, mais avec use warningselle devrait probablement dire quelque chose car il peut comprendre que ce n'est pas en cours de chargement. Au lieu de cela, il génère une erreur d'exécution "Impossible de localiser la méthode d'objet ..".
53

La raison pour laquelle vous n'obtenez pas d'erreur est que le premier code exécuté est

exit(0);

Parce que vous n'aviez pas de point-virgule sur la première ligne:

Syntax error!

Le compilateur devinera (à tort) qu'il s'agit d'un appel de sous-programme avec un notopérateur !ajouté. Il exécutera ensuite les arguments de ce sous-programme, qui se trouve être exit(0), à quel moment le programme se termine et définit le niveau d'erreur à 0. Rien d'autre n'est exécuté , donc plus aucune erreur d'exécution n'est signalée.

Vous remarquerez que si vous passez exit(0)à quelque chose comme print "Hello world!"vous obtenez une erreur:

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

et votre niveau d'erreur sera défini:

> echo %errorlevel%
255
TLP
la source
7
>The compiler will guess (incorrectly) Le compilateur ne peut rien faire de mal.
Liam Laverty
14
@LiamLaverty Oui, c'est possible. Il peut deviner incorrectement ce que l'humain voulait dire.
TLP
4
L'humain est incorrect dans l'équation. Le compilateur ne peut être que "correct" ou "cassé". Il n'obtient pas d'opinion sur la définition de la langue ou l'intention d'un utilisateur.
Liam Laverty
4
@LiamLaverty Ce serait un compilateur assez soigné s'il pouvait deviner l'intention de l'utilisateur dans ce cas, oui. Par conséquent, le compilateur ne peut pas deviner correctement. Vous faites peut-être une analyse du jargon technique de ma déclaration, qui est, je pourrais ajouter, la mauvaise façon de la lire.
TLP
N'est-ce pas un interprète? ;-)
Rikki
33

Comme indiqué ci-dessus, cela est dû à la méthode indirecte appelant la notation. Vous pouvez avertir à ce sujet:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Produit:

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

Cela nécessite le module CPAN indirect .

Vous pouvez également utiliser no indirect "fatal";pour provoquer la mort du programme (c'est ce que je fais)

Mark Fowler
la source
8

Essayez Perl 6 , il semble répondre plus facilement à vos attentes:

===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
la source
1

Dans ce article , nous visons à répondre à un problème ouvert de longue date dans la communauté des langages de programmation: est-il possible d'étaler de la peinture sur le mur sans créer de Perl valide?

TLDR; À peine

Holli
la source
J'aime ça. Je devrai peut-être numériser certaines images.
Bill Ruppert