Ruby 2.0, 65 76 164 personagens
eval r="gets p;$<.pos=0;`ruby -c 2>&0`;p$?==0&&$_!='eval r=%p'%r"
Isso usa o verificador de sintaxe interno do Ruby ( ruby -c
) para verificar a sintaxe da entrada, o que significa que o código não será avaliado.
Exemplo 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
Explicação
Esta solução é (foi) baseada no padrão Ruby quine:
q="q=%p;puts q%%q";puts q%q
%p
é o especificador de formato para o arg.inspect
qual pode ser comparado uneval
: ao eval
inserir a string retornada por arg.inspect
, você (normalmente) obtém o valor original novamente. Assim, ao formatar a q
string como argumento, o %p
interior da string será substituído pela própria string citada (ou seja, obtemos algo parecido "q=\"q=%p;puts q%%q\";puts q%q"
).
A generalização desse tipo de quine leva a algo como o seguinte:
prelude;q="prelude;q=%p;postlude";postlude
Essa abordagem tem uma enorme desvantagem (pelo menos no código-golfe ): Todo o código precisa ser duplicado. Felizmente, eval
pode ser usado para contornar isso:
eval r="some code;'eval r=%p'%r"
O que acontece aqui é que o código passado para eval é armazenado dentro r
antes de eval
ser chamado. Como resultado, o código fonte completo da eval
instrução pode ser obtido com 'eval r=%p'%r
. Se fizermos isso dentro do eval
código d e garantirmos que o nível superior de nosso consistir apenas em uma eval
instrução, essa expressão realmente nos fornecerá o código fonte completo do nosso programa, pois qualquer código adicional passado eval
já está armazenado r
.
Nota lateral: Essa abordagem nos permite escrever um Ruby Quine em 26 caracteres: eval r="puts'eval r=%p'%r"
Agora, nesta solução, o código adicional executado dentro eval
consiste em quatro instruções:
gets p
Primeiro, lemos toda a entrada do STDIN e a salvamos implicitamente $_
.
$<.pos=0
Em seguida, rebobinamos o STDIN para que a entrada fique novamente disponível para o subprocesso que iniciaremos na próxima etapa.
`ruby -c 2>&0`
Isso inicia o Ruby no modo de verificação de sintaxe embutido, lendo o código fonte do stdin. Se a sintaxe do script fornecido (nome do arquivo ou stdin) estiver correta, ela será impressa Syntax OK
no seu stdout (que é capturado pelo processo pai), mas no caso de um erro de sintaxe, uma descrição do erro será impressa no stderr - o que seria fique visível, então redirecionamos isso para o nirvana ( 2>&0
).
p$?==0&&$_!='eval r=%p'%r
Depois, verificamos o código de saída do subprocesso $?
, que é 0 se a sintaxe estiver correta. Por fim, a entrada que lemos anteriormente ( $_
) é comparada com nosso próprio código-fonte (que, como descrevi anteriormente, pode ser obtido com 'eval r=%p'%r
).
Editar: salvou 14 caracteres graças a @histocrat!