Ruby 2.0, 65 76 164 caracteres
eval r="gets p;$<.pos=0;`ruby -c 2>&0`;p$?==0&&$_!='eval r=%p'%r"
Esto utiliza el verificador de sintaxis incorporado de Ruby ( ruby -c
) para verificar la sintaxis de la entrada, lo que significa que el código no será evaluado.
Ejemplo de uso básico:
ruby syntax.rb <<< foo
true
ruby syntax.rb <<< "'"
false
ruby syntax.rb < synxtax.rb # assumes the file was saved without trailing newline
false
Explicación
Esta solución está (estaba) basada en el estándar Ruby quine:
q="q=%p;puts q%%q";puts q%q
%p
es el especificador de formato para arg.inspect
, que se puede comparar con uneval
: cuando se eval
ingresa la cadena devuelta arg.inspect
, (generalmente) obtiene el valor original nuevamente. Por lo tanto, al formatear la q
cadena consigo misma como argumento, el %p
interior de la cadena se reemplazará con la cadena citada (es decir, obtenemos algo así "q=\"q=%p;puts q%%q\";puts q%q"
).
Generalizar este tipo de quine lleva a algo como lo siguiente:
prelude;q="prelude;q=%p;postlude";postlude
Sin embargo, este enfoque tiene un gran inconveniente (al menos en code-golf ): todo el código debe duplicarse. Afortunadamente, eval
se puede usar para evitar esto:
eval r="some code;'eval r=%p'%r"
Lo que sucede aquí es que el código pasado a eval se almacena dentro r
antes de que eval
se llame. Como resultado, eval
se puede obtener el código fuente completo de la declaración 'eval r=%p'%r
. Si hacemos esto dentro del eval
código d y nos aseguramos de que el nivel superior de nuestro consiste solo en una eval
declaración, esa expresión en realidad nos da el código fuente completo de nuestro programa, ya que cualquier código adicional pasado eval
ya está almacenado dentro r
.
Nota al margen: este enfoque en realidad nos permite escribir un quine Ruby en 26 caracteres: eval r="puts'eval r=%p'%r"
Ahora, en esta solución, el código adicional ejecutado en su interior eval
consta de cuatro declaraciones:
gets p
Primero, leemos todas las entradas de STDIN y las guardamos implícitamente en ellas $_
.
$<.pos=0
Luego, rebobinamos STDIN para que la entrada esté disponible nuevamente para el subproceso que comenzamos en el siguiente paso.
`ruby -c 2>&0`
Esto inicia Ruby en su modo de verificación de sintaxis incorporado, leyendo el código fuente de stdin. Si la sintaxis del script proporcionado (nombre de archivo o stdin) es correcta, se imprime Syntax OK
en su stdout (que es capturado por el proceso principal), pero en caso de un error de sintaxis, se imprime una descripción del error en stderr , lo que ser visible, por lo que redirigimos eso a nirvana ( 2>&0
) en su lugar.
p$?==0&&$_!='eval r=%p'%r
Luego, verificamos el código de salida del subproceso $?
, que es 0 si la sintaxis era correcta. Por último, la entrada que leemos antes ( $_
) se compara con nuestro propio código fuente (que, como describí anteriormente, se puede obtener con 'eval r=%p'%r
).
Editar: ¡Salvé 14 caracteres gracias a @histocrat!