¿Por qué es válido este programa? Estaba intentando crear un error de sintaxis

489

Estoy ejecutando ActivePerl 5.14.2 de 32 bits de ActiveState en Windows 7. Quería perder el tiempo con un enlace de precompromiso de Git para detectar programas que se registran con errores de sintaxis. (De alguna manera me las arreglé para hacer una mala confirmación). Entonces, como programa de prueba, escribí esto al azar:

use strict;
use warnings;

Syntax error!

exit 0;

Sin embargo, se compila y ejecuta sin advertencias, y el nivel de error es cero al salir. ¿Cómo es esta sintaxis válida?

Bill Ruppert
fuente
121
¿Acabas de demostrar que escribir palabras al azar en Perl produce programas de trabajo ??!?!?!?!
Peter M
10
@PeterM Palabras apenas aleatorias. Probé que no sé lo suficiente sobre la sintaxis de Perl. Ahora sé un poco más.
Bill Ruppert
10
Probablemente quieras no indirectevitar que esos sucedan
LeoNerd
@LeoNerd Gracias por el consejo!
Bill Ruppert
1
Esta es la pregunta perl más famosa de la historia. Incluso mejor que el fragmento de Schwartz :whatever / 25 ; # / ; die "this dies!";
jm666

Respuestas:

540

Perl tiene una sintaxis llamada "notación de método indirecto". Permite

Foo->new($bar)

ser escrito como

new Foo $bar

Entonces eso significa

Syntax error ! exit 0;

es lo mismo que

error->Syntax(! exit 0);

o

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

No solo es una sintaxis válida, sino que no genera un error de tiempo de ejecución porque lo primero que se ejecuta es exit(0).

ikegami
fuente
1
@Hassan, ¿por qué? Es seguido por una expresión.
ikegami
3
Llegué a leerlo como "Error de sintaxis! Salir 0;", pero no pensé en la invocación indirecta. ¡Pasé mucho tiempo olvidando eso!
Bill Ruppert
66
@Hassan, piénsalo de esta manera, !exit(0)no puede ser más un error de tipo que !$xya que ninguno está escrito.
ikegami
11
@Hassan, el idioma tiene tipos. Específicamente, los valores tienen tipos. Los operadores y los subs simplemente no se limitan a devolver tipos específicos de valores. Esto resulta ser muy útil a bajo costo (gracias a las advertencias).
ikegami
66
@ Nawaz, en realidad es bastante popular. Es utilizado por todos los que construyen objetos en Java y C ++, y un gran cuerpo de programadores de Perl que usa new Classy en print $fh ...lugar de Class->new(...)y $fh->print(...). Sin embargo, le concederé que causa mensajes de error extraños
Ikegami
112

No sé por qué, pero esto es lo que hace Perl:

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

Parece que el analizador cree que estás llamando al método Syntaxen el objeto error... ¡Extraño en verdad!

pavel
fuente
3
Esa es la sintaxis de llamada al método indirecto. Está (más o menos) trabajando aquí porque exit(0)se evalúa primero, lo que hace que el programa salga antes de intentar pasar el resultado 'error'->Syntax().
duskwuff -inactive-
66
Perl parece asumir la "sintaxis indirecta (objeto)", que generalmente se usa como en new Classlugar de Class->new(). Para llamar al método Syntax, la exitfunción se ejecuta, por lo que el error en tiempo de ejecución nunca se produce.
amon
118
Felicidades. Encontraste un programa donde necesitas agregar un punto y coma para que la compilación falle.
mafia
use strict; use warnings; error->Syntax(! print "hi"); Rendimientos: Sintaxis Ok en perl -MO = Deparse también, pero use warningsprobablemente debería decir algo, ya que puede darse cuenta de que no se está cargando. En su lugar, arroja un error de tiempo de ejecución "No se puede encontrar el método del objeto ...".
53

La razón por la que no recibe un error es que el primer código ejecutado es

exit(0);

Debido a que no tenía un punto y coma en la primera línea:

Syntax error!

El compilador adivinará (incorrectamente) que se trata de una llamada de subrutina con un notoperador !incluido. Luego ejecutará los argumentos de esta subrutina, que es el momento exit(0), momento en el que el programa sale y establece el nivel de error en 0. No se ejecuta nada más. , por lo que no se informan más errores de tiempo de ejecución.

Notarás que si cambias exit(0)a algo así print "Hello world!", obtienes un error:

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

y tu nivel de error se establecerá:

> echo %errorlevel%
255
TLP
fuente
77
>The compiler will guess (incorrectly) El compilador no puede hacer nada incorrectamente.
Liam Laverty
14
@LiamLaverty Sí, puede. Puede adivinar incorrectamente lo que el humano quería decir.
TLP
44
El humano es el incorrecto en la ecuación. El compilador solo puede ser "correcto" o "roto". No obtiene una opinión sobre la definición del idioma o la intención del usuario.
Liam Laverty
44
@LiamLaverty Sería un compilador bastante bueno si pudiera adivinar la intención del usuario en este caso, sí. Por lo tanto, el compilador no puede adivinar correctamente. Es posible que esté haciendo un análisis técnico de jerga de mi declaración, que es, podría agregar, la forma incorrecta de leerla.
TLP
¿No es un intérprete? ;-)
Rikki
33

Como se señaló anteriormente, esto es causado por el método indirecto que llama notación. Puedes advertir sobre esto:

use strict;
use warnings;
no indirect;

Syntax error!

exit 0;

Produce:

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

Esto requiere el módulo indirecto CPAN .

También puedes usar no indirect "fatal";para hacer que el programa muera (esto es lo que hago)

Mark Fowler
fuente
8

Pruebe Perl 6 , parece cumplir sus expectativas más fácilmente:

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

En esto documento , nuestro objetivo es responder a un problema abierto de larga data en la comunidad de lenguajes de programación: ¿es posible manchar la pintura en la pared sin crear un Perl válido?

TLDR; Apenas

Holli
fuente
Eso me encanta Puede que tenga que escanear en algunas imágenes.
Bill Ruppert